Commit e27d6920 by Zachary Snow

conversion for array query system functions (resolves #37)

parent f5d66834
......@@ -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
......
{- 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
{- 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
{- 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
......
`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
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment