From e27d6920a79a20e85fdd182602e7afde67981099 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sat, 14 Sep 2019 16:42:54 -0400 Subject: [PATCH] conversion for array query system functions (resolves #37) --- src/Convert.hs | 4 +- src/Convert/Bits.hs | 109 -------------- src/Convert/DimensionQuery.hs | 192 +++++++++++++++++++++++++ src/Convert/Simplify.hs | 8 +- src/Language/SystemVerilog/AST/Expr.hs | 1 + src/Language/SystemVerilog/AST/Type.hs | 9 +- sv2v.cabal | 2 +- test/basic/dimensions.sv | 31 ++++ test/basic/dimensions.v | 68 +++++++++ 9 files changed, 307 insertions(+), 117 deletions(-) delete mode 100644 src/Convert/Bits.hs create mode 100644 src/Convert/DimensionQuery.hs create mode 100644 test/basic/dimensions.sv create mode 100644 test/basic/dimensions.v diff --git a/src/Convert.hs b/src/Convert.hs index 84b2382..ea3ee2a 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -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 diff --git a/src/Convert/Bits.hs b/src/Convert/Bits.hs deleted file mode 100644 index 3d63ae4..0000000 --- a/src/Convert/Bits.hs +++ /dev/null @@ -1,109 +0,0 @@ -{- sv2v - - Author: Zachary Snow - - - - 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 diff --git a/src/Convert/DimensionQuery.hs b/src/Convert/DimensionQuery.hs new file mode 100644 index 0000000..7beabf6 --- /dev/null +++ b/src/Convert/DimensionQuery.hs @@ -0,0 +1,192 @@ +{- sv2v + - Author: Zachary Snow + - + - 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 diff --git a/src/Convert/Simplify.hs b/src/Convert/Simplify.hs index 95149c3..569761f 100644 --- a/src/Convert/Simplify.hs +++ b/src/Convert/Simplify.hs @@ -1,8 +1,8 @@ {- sv2v - Author: Zachary Snow - - - 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 diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index 3e59e58..cc86b5c 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -21,6 +21,7 @@ module Language.SystemVerilog.AST.Expr , endianCondRange , sizedExpr , dimensionsSize + , readNumber ) where import Data.List (intercalate) diff --git a/src/Language/SystemVerilog/AST/Type.hs b/src/Language/SystemVerilog/AST/Type.hs index a02a975..a162c86 100644 --- a/src/Language/SystemVerilog/AST/Type.hs +++ b/src/Language/SystemVerilog/AST/Type.hs @@ -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 diff --git a/sv2v.cabal b/sv2v.cabal index ef64429..58e5f2d 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -57,8 +57,8 @@ executable sv2v Convert.AlwaysKW Convert.AsgnOp Convert.Assertion - Convert.Bits Convert.BlockDecl + Convert.DimensionQuery Convert.EmptyArgs Convert.Enum Convert.ForDecl diff --git a/test/basic/dimensions.sv b/test/basic/dimensions.sv new file mode 100644 index 0000000..4247bae --- /dev/null +++ b/test/basic/dimensions.sv @@ -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 diff --git a/test/basic/dimensions.v b/test/basic/dimensions.v new file mode 100644 index 0000000..fea0c15 --- /dev/null +++ b/test/basic/dimensions.v @@ -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