mirror of https://github.com/zachjs/sv2v.git
conversion for array query system functions (resolves #37)
This commit is contained in:
parent
f5d6683422
commit
e27d6920a7
|
|
@ -12,8 +12,8 @@ import qualified Job (Exclude(..))
|
|||
import qualified Convert.AlwaysKW
|
||||
import qualified Convert.AsgnOp
|
||||
import qualified Convert.Assertion
|
||||
import qualified Convert.Bits
|
||||
import qualified Convert.BlockDecl
|
||||
import qualified Convert.DimensionQuery
|
||||
import qualified Convert.EmptyArgs
|
||||
import qualified Convert.Enum
|
||||
import qualified Convert.ForDecl
|
||||
|
|
@ -45,7 +45,6 @@ phases excludes =
|
|||
[ Convert.AsgnOp.convert
|
||||
, Convert.NamedBlock.convert
|
||||
, Convert.Assertion.convert
|
||||
, Convert.Bits.convert
|
||||
, Convert.BlockDecl.convert
|
||||
, selectExclude (Job.Logic , Convert.Logic.convert)
|
||||
, Convert.ForDecl.convert
|
||||
|
|
@ -54,6 +53,7 @@ phases excludes =
|
|||
, Convert.IntTypes.convert
|
||||
, Convert.KWArgs.convert
|
||||
, Convert.PackedArray.convert
|
||||
, Convert.DimensionQuery.convert
|
||||
, Convert.ParamType.convert
|
||||
, Convert.Simplify.convert
|
||||
, Convert.StarPort.convert
|
||||
|
|
|
|||
|
|
@ -1,109 +0,0 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Elaboration of `$bits` expressions.
|
||||
-
|
||||
- Some tools support $bits in Verilog, but it is not part of the specification,
|
||||
- so we have to convert it ourselves.
|
||||
-
|
||||
- `$bits(t)`, where `t` is a type, is trivially elaborated to the product of
|
||||
- the sizes of its dimensions once `t` is resolved to a primitive base type.
|
||||
-
|
||||
- `$bits(e)`, where `e` is an expression, requires a scoped traversal to
|
||||
- determine the underlying type of expression. The conversion recursively
|
||||
- breaks the expression into its subtypes, finding their sizes instead.
|
||||
-}
|
||||
|
||||
module Convert.Bits (convert) where
|
||||
|
||||
import Control.Monad.State
|
||||
import Data.List (elemIndex)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
type Info = Map.Map Identifier (Type, [Range])
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert files =
|
||||
if files == files'
|
||||
then files
|
||||
else convert files'
|
||||
where files' = map (traverseDescriptions convertDescription) files
|
||||
|
||||
convertDescription :: Description -> Description
|
||||
convertDescription =
|
||||
scopedConversion traverseDeclM traverseModuleItemM traverseStmtM Map.empty
|
||||
|
||||
traverseDeclM :: Decl -> State Info Decl
|
||||
traverseDeclM decl = do
|
||||
case decl of
|
||||
Variable _ t ident a _ -> modify $ Map.insert ident (t, a)
|
||||
Param _ t ident _ -> modify $ Map.insert ident (t, [])
|
||||
ParamType _ _ _ -> return ()
|
||||
item <- traverseModuleItemM (MIPackageItem $ Decl decl)
|
||||
let MIPackageItem (Decl decl') = item
|
||||
return decl'
|
||||
|
||||
traverseModuleItemM :: ModuleItem -> State Info ModuleItem
|
||||
traverseModuleItemM item = traverseExprsM traverseExprM item
|
||||
|
||||
traverseStmtM :: Stmt -> State Info Stmt
|
||||
traverseStmtM stmt = traverseStmtExprsM traverseExprM stmt
|
||||
|
||||
traverseExprM :: Expr -> State Info Expr
|
||||
traverseExprM = traverseNestedExprsM $ stately converter
|
||||
where converter a b = simplify $ (traverseNestedExprs (convertExpr a) b)
|
||||
|
||||
-- simplify a bits expression given scoped type information
|
||||
convertExpr :: Info -> Expr -> Expr
|
||||
convertExpr _ (DimsFn FnBits (Left t)) =
|
||||
case t of
|
||||
IntegerVector _ _ rs -> dimensionsSize rs
|
||||
Implicit _ rs -> dimensionsSize rs
|
||||
Net _ rs -> dimensionsSize rs
|
||||
_ -> DimsFn FnBits $ Left t
|
||||
convertExpr info (DimsFn FnBits (Right e)) =
|
||||
case e of
|
||||
Ident x ->
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimsFn FnBits $ Right e
|
||||
Just (t, rs) -> simplify $ BinOp Mul
|
||||
(dimensionsSize rs)
|
||||
(convertExpr info $ DimsFn FnBits $ Left t)
|
||||
Concat exprs ->
|
||||
foldl (BinOp Add) (Number "0") $
|
||||
map (convertExpr info) $
|
||||
map (DimsFn FnBits . Right) $
|
||||
exprs
|
||||
Range expr mode range ->
|
||||
simplify $ BinOp Mul size
|
||||
(convertExpr info $ DimsFn FnBits $ Right $ Bit expr (Number "0"))
|
||||
where
|
||||
size = case mode of
|
||||
NonIndexed -> rangeSize range
|
||||
IndexedPlus -> snd range
|
||||
IndexedMinus -> snd range
|
||||
Bit (Ident x) idx ->
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimsFn FnBits $ Right $ Bit (Ident x) idx
|
||||
Just (t, rs) ->
|
||||
convertExpr info $ DimsFn FnBits $ Left t'
|
||||
where t' = popRange t rs
|
||||
Stream _ _ exprs -> convertExpr info $ DimsFn FnBits $ Right $ Concat exprs
|
||||
Number n ->
|
||||
case elemIndex '\'' n of
|
||||
Nothing -> Number "32"
|
||||
Just idx -> Number $ take idx n
|
||||
_ -> DimsFn FnBits $ Right e
|
||||
convertExpr _ other = other
|
||||
|
||||
-- combines the given type and dimensions and returns a new type with the
|
||||
-- innermost range removed
|
||||
popRange :: Type -> [Range] -> Type
|
||||
popRange t rs =
|
||||
tf $ tail rsCombined
|
||||
where
|
||||
(tf, trs) = typeRanges t
|
||||
rsCombined = rs ++ trs
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Elaboration of the "expression size system function" ($bits) and the "array
|
||||
- query functions" ($dimensions, $unpacked_dimensions, $left, $right, $low,
|
||||
- $high, $increment, and $size).
|
||||
-
|
||||
- Some tools support $bits and some of the other functions in Verilog, but it
|
||||
- is not part of the specification, so we have to convert them ourselves.
|
||||
-
|
||||
- Functions on types are trivially elaborated based on the dimensions of that
|
||||
- type, so long as it has been resolved to a primitive type.
|
||||
-
|
||||
- Functions on expressions requires a scoped traversal to determine the
|
||||
- underlying type of expression. The conversion of `$bits` on expressions
|
||||
- recursively breaks the expression into its subtypes and finds their sizes.
|
||||
-}
|
||||
|
||||
module Convert.DimensionQuery (convert) where
|
||||
|
||||
import Control.Monad.State
|
||||
import Data.List (elemIndex)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
type Info = Map.Map Identifier (Type, [Range])
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert files =
|
||||
if files == files'
|
||||
then files
|
||||
else convert files'
|
||||
where files' = map (traverseDescriptions convertDescription) files
|
||||
|
||||
convertDescription :: Description -> Description
|
||||
convertDescription =
|
||||
scopedConversion traverseDeclM traverseModuleItemM traverseStmtM Map.empty
|
||||
|
||||
traverseDeclM :: Decl -> State Info Decl
|
||||
traverseDeclM decl = do
|
||||
case decl of
|
||||
Variable _ t ident a _ -> modify $ Map.insert ident (elaborateType t, a)
|
||||
Param _ t ident _ -> modify $ Map.insert ident (elaborateType t, [])
|
||||
ParamType _ _ _ -> return ()
|
||||
item <- traverseModuleItemM (MIPackageItem $ Decl decl)
|
||||
let MIPackageItem (Decl decl') = item
|
||||
return decl'
|
||||
|
||||
traverseModuleItemM :: ModuleItem -> State Info ModuleItem
|
||||
traverseModuleItemM item = traverseExprsM traverseExprM item
|
||||
|
||||
traverseStmtM :: Stmt -> State Info Stmt
|
||||
traverseStmtM stmt = traverseStmtExprsM traverseExprM stmt
|
||||
|
||||
traverseExprM :: Expr -> State Info Expr
|
||||
traverseExprM = traverseNestedExprsM $ stately converter
|
||||
where converter a b = simplify $ (traverseNestedExprs (convertExpr a) b)
|
||||
|
||||
-- elaborate integer atom types to have explicit dimensions
|
||||
elaborateType :: Type -> Type
|
||||
elaborateType (IntegerAtom t sg) =
|
||||
IntegerVector TLogic sg [(hi, lo)]
|
||||
where
|
||||
size = atomSize t
|
||||
hi = Number $ show (size - 1)
|
||||
lo = Number "0"
|
||||
atomSize :: IntegerAtomType -> Int
|
||||
atomSize TByte = 8
|
||||
atomSize TShortint = 16
|
||||
atomSize TInt = 32
|
||||
atomSize TLongint = 64
|
||||
atomSize TInteger = 32
|
||||
atomSize TTime = 64
|
||||
elaborateType other = other
|
||||
|
||||
convertExpr :: Info -> Expr -> Expr
|
||||
|
||||
-- conversion for array dimensions functions
|
||||
convertExpr info (DimsFn FnBits v) =
|
||||
convertBits info v
|
||||
convertExpr _ (DimsFn FnUnpackedDimensions (Left _)) =
|
||||
Number "0"
|
||||
convertExpr _ (DimsFn FnDimensions (Left t)) =
|
||||
Number $ show $
|
||||
case t of
|
||||
IntegerAtom _ _ -> 1
|
||||
_ -> length $ snd $ typeRanges t
|
||||
convertExpr info (DimsFn FnUnpackedDimensions (Right (Ident x))) =
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimsFn FnUnpackedDimensions $ Right $ Ident x
|
||||
Just (_, rs) -> Number $ show $ length rs
|
||||
convertExpr info (DimsFn FnDimensions (Right (Ident x))) =
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimsFn FnDimensions $ Right $ Ident x
|
||||
Just (t, rs) -> DimsFn FnDimensions $ Left $ tf rsCombined
|
||||
where
|
||||
(tf, trs) = typeRanges t
|
||||
rsCombined = rs ++ trs
|
||||
|
||||
-- conversion for array dimension functions on types
|
||||
convertExpr _ (DimFn f (Left t) (Number str)) =
|
||||
if dm == Nothing || isAlias t then
|
||||
DimFn f (Left t) (Number str)
|
||||
else if d <= 0 || d > length rs then
|
||||
Number "'x"
|
||||
else case f of
|
||||
FnLeft -> fst r
|
||||
FnRight -> snd r
|
||||
FnIncrement -> endianCondExpr r (Number "1") (Number "-1")
|
||||
FnLow -> endianCondExpr r (snd r) (fst r)
|
||||
FnHigh -> endianCondExpr r (fst r) (snd r)
|
||||
FnSize -> rangeSize r
|
||||
where
|
||||
(_, rs) = typeRanges $ elaborateType t
|
||||
dm = readNumber str
|
||||
Just d = dm
|
||||
r = rs !! (d - 1)
|
||||
isAlias :: Type -> Bool
|
||||
isAlias (Alias _ _ _) = True
|
||||
isAlias _ = False
|
||||
convertExpr _ (DimFn f (Left t) d) =
|
||||
DimFn f (Left t) d
|
||||
|
||||
-- conversion for array dimension functions on expression
|
||||
convertExpr info (DimFn f (Right (Ident x)) d) =
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimFn f (Right (Ident x)) d
|
||||
Just (t, rs) -> DimFn f (Left $ tf rsCombined) d
|
||||
where
|
||||
(tf, trs) = typeRanges t
|
||||
rsCombined = rs ++ trs
|
||||
convertExpr info (DimFn f (Right (Bit (Ident x) idx)) d) =
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimFn f (Right $ Bit (Ident x) idx) d
|
||||
Just (t, rs) -> DimFn f (Left t') d
|
||||
where t' = popRange t rs
|
||||
convertExpr _ (DimFn f (Right e) d) =
|
||||
DimFn f (Right e) d
|
||||
|
||||
convertExpr _ other = other
|
||||
|
||||
-- simplify a bits expression given scoped type information
|
||||
convertBits :: Info -> TypeOrExpr -> Expr
|
||||
convertBits _ (Left t) =
|
||||
case elaborateType t of
|
||||
IntegerVector _ _ rs -> dimensionsSize rs
|
||||
Implicit _ rs -> dimensionsSize rs
|
||||
Net _ rs -> dimensionsSize rs
|
||||
_ -> DimsFn FnBits $ Left t
|
||||
convertBits info (Right e) =
|
||||
case e of
|
||||
Ident x ->
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimsFn FnBits $ Right e
|
||||
Just (t, rs) -> simplify $ BinOp Mul
|
||||
(dimensionsSize rs)
|
||||
(convertBits info $ Left t)
|
||||
Concat exprs ->
|
||||
foldl (BinOp Add) (Number "0") $
|
||||
map (convertBits info . Right) $
|
||||
exprs
|
||||
Range expr mode range ->
|
||||
simplify $ BinOp Mul size
|
||||
(convertBits info $ Right $ Bit expr (Number "0"))
|
||||
where
|
||||
size = case mode of
|
||||
NonIndexed -> rangeSize range
|
||||
IndexedPlus -> snd range
|
||||
IndexedMinus -> snd range
|
||||
Bit (Ident x) idx ->
|
||||
case Map.lookup x info of
|
||||
Nothing -> DimsFn FnBits $ Right $ Bit (Ident x) idx
|
||||
Just (t, rs) ->
|
||||
convertBits info $ Left t'
|
||||
where t' = popRange t rs
|
||||
Stream _ _ exprs -> convertBits info $ Right $ Concat exprs
|
||||
Number n ->
|
||||
case elemIndex '\'' n of
|
||||
Nothing -> Number "32"
|
||||
Just idx -> Number $ take idx n
|
||||
_ -> DimsFn FnBits $ Right e
|
||||
|
||||
-- combines the given type and dimensions and returns a new type with the
|
||||
-- innermost range removed
|
||||
popRange :: Type -> [Range] -> Type
|
||||
popRange t rs =
|
||||
tf $ tail rsCombined
|
||||
where
|
||||
(tf, trs) = typeRanges t
|
||||
rsCombined = rs ++ trs
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Elaboration of size casts and ternary expressions where the condition
|
||||
- references a localparam.
|
||||
- Elaboration of size casts, dimension query system functions, and ternary
|
||||
- expressions where the condition references a localparam.
|
||||
-
|
||||
- Our conversions generate a lot of ternary expressions. This conversion
|
||||
- attempts to make the code output a bit cleaner. Note that we can only do this
|
||||
|
|
@ -55,6 +55,10 @@ convertExpr info (Cast (Right c) e) =
|
|||
where
|
||||
c' = simplify $ traverseNestedExprs (substitute info) (simplify c)
|
||||
sized = sizedExpr "" c' e
|
||||
convertExpr info (DimFn f v e) =
|
||||
DimFn f v e'
|
||||
where
|
||||
e' = simplify $ traverseNestedExprs (substitute info) e
|
||||
convertExpr info (Mux cc aa bb) =
|
||||
if before == after
|
||||
then Mux cc aa bb
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ module Language.SystemVerilog.AST.Expr
|
|||
, endianCondRange
|
||||
, sizedExpr
|
||||
, dimensionsSize
|
||||
, readNumber
|
||||
) where
|
||||
|
||||
import Data.List (intercalate)
|
||||
|
|
|
|||
|
|
@ -94,9 +94,12 @@ typeRanges (InterfaceT x my r) = (InterfaceT x my, r)
|
|||
nullRange :: Type -> ([Range] -> Type)
|
||||
nullRange t [] = t
|
||||
nullRange t [(Number "0", Number "0")] = t
|
||||
nullRange t other =
|
||||
error $ "non vector type " ++ show t ++
|
||||
" cannot have a range: " ++ show other
|
||||
nullRange (IntegerAtom TInteger sg) rs =
|
||||
-- integer arrays are allowed in SystemVerilog but not in Verilor
|
||||
IntegerVector TBit sg (rs ++ [(Number "31", Number "0")])
|
||||
nullRange t rs =
|
||||
error $ "non-vector type " ++ show t ++
|
||||
" cannot have a packed dimesions:" ++ show rs
|
||||
|
||||
data Signing
|
||||
= Unspecified
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ executable sv2v
|
|||
Convert.AlwaysKW
|
||||
Convert.AsgnOp
|
||||
Convert.Assertion
|
||||
Convert.Bits
|
||||
Convert.BlockDecl
|
||||
Convert.DimensionQuery
|
||||
Convert.EmptyArgs
|
||||
Convert.Enum
|
||||
Convert.ForDecl
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
`define EXHAUST(t) \
|
||||
$display($size(t), $size(t,1), $size(t,2)); \
|
||||
$display($left(t), $left(t,1), $left(t,2)); \
|
||||
$display($right(t), $right(t,1), $right(t,2)); \
|
||||
$display($high(t), $high(t,1), $high(t,2)); \
|
||||
$display($low(t), $low(t,1), $low(t,2)); \
|
||||
$display($increment(t), $increment(t,1), $increment(t,2)); \
|
||||
$display($dimensions(t)); \
|
||||
$display($unpacked_dimensions(t)); \
|
||||
$display($bits(t));
|
||||
|
||||
module top;
|
||||
typedef logic [16:1] Word;
|
||||
Word Ram[0:9];
|
||||
integer ints [3:0];
|
||||
typedef struct packed { logic x, y, z; } T;
|
||||
logic [$size(T)-1:0] foo;
|
||||
initial begin
|
||||
$display($size(Word));
|
||||
$display($size(Ram,2));
|
||||
$display($size(Ram[0]));
|
||||
$display($bits(foo));
|
||||
|
||||
`EXHAUST(Ram);
|
||||
`EXHAUST(Word);
|
||||
`EXHAUST(integer);
|
||||
`EXHAUST(bit);
|
||||
`EXHAUST(byte);
|
||||
`EXHAUST(ints);
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
module top;
|
||||
initial begin
|
||||
$display(16);
|
||||
$display(16);
|
||||
$display(16);
|
||||
$display(3);
|
||||
|
||||
$display(10, 10, 16);
|
||||
$display(0, 0, 16);
|
||||
$display(9, 9, 1);
|
||||
$display(9, 9, 16);
|
||||
$display(0, 0, 1);
|
||||
$display(-1, -1, 1);
|
||||
$display(2);
|
||||
$display(1);
|
||||
$display(160);
|
||||
|
||||
$display(16, 16, 'bx);
|
||||
$display(16, 16, 'bx);
|
||||
$display(1, 1, 'bx);
|
||||
$display(16, 16, 'bx);
|
||||
$display(1, 1, 'bx);
|
||||
$display(1, 1, 'bx);
|
||||
$display(1);
|
||||
$display(0);
|
||||
$display(16);
|
||||
|
||||
$display(32, 32, 'bx);
|
||||
$display(31, 31, 'bx);
|
||||
$display(0, 0, 'bx);
|
||||
$display(31, 31, 'bx);
|
||||
$display(0, 0, 'bx);
|
||||
$display(1, 1, 'bx);
|
||||
$display(1);
|
||||
$display(0);
|
||||
$display(32);
|
||||
|
||||
$display('bx, 'bx, 'bx);
|
||||
$display('bx, 'bx, 'bx);
|
||||
$display('bx, 'bx, 'bx);
|
||||
$display('bx, 'bx, 'bx);
|
||||
$display('bx, 'bx, 'bx);
|
||||
$display('bx, 'bx, 'bx);
|
||||
$display(0);
|
||||
$display(0);
|
||||
$display(1);
|
||||
|
||||
$display(8, 8, 'bx);
|
||||
$display(7, 7, 'bx);
|
||||
$display(0, 0, 'bx);
|
||||
$display(7, 7, 'bx);
|
||||
$display(0, 0, 'bx);
|
||||
$display(1, 1, 'bx);
|
||||
$display(1);
|
||||
$display(0);
|
||||
$display(8);
|
||||
|
||||
$display(4, 4, 32);
|
||||
$display(3, 3, 31);
|
||||
$display(0, 0, 0);
|
||||
$display(3, 3, 31);
|
||||
$display(0, 0, 0);
|
||||
$display(1, 1, 1);
|
||||
$display(2);
|
||||
$display(1);
|
||||
$display(128);
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue