diff --git a/src/Convert.hs b/src/Convert.hs index 065674b..48a9b5a 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -32,6 +32,7 @@ import qualified Convert.ParamType import qualified Convert.RemoveComments import qualified Convert.Return import qualified Convert.Simplify +import qualified Convert.SizeCast import qualified Convert.StarPort import qualified Convert.StmtBlock import qualified Convert.Stream @@ -58,6 +59,7 @@ phases excludes = , Convert.PackedArray.convert , Convert.DimensionQuery.convert , Convert.ParamType.convert + , Convert.SizeCast.convert , Convert.Simplify.convert , Convert.StarPort.convert , Convert.StmtBlock.convert diff --git a/src/Convert/SizeCast.hs b/src/Convert/SizeCast.hs new file mode 100644 index 0000000..ae7cda3 --- /dev/null +++ b/src/Convert/SizeCast.hs @@ -0,0 +1,133 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion of size casts on non-constant expressions. + -} + +module Convert.SizeCast (convert) where + +import Control.Monad.State +import Control.Monad.Writer +import qualified Data.Map.Strict as Map +import qualified Data.Set as Set + +import Convert.Traverse +import Language.SystemVerilog.AST + +type TypeMap = Map.Map Identifier Type +type CastSet = Set.Set (Int, Signing) + +type ST = StateT TypeMap (Writer CastSet) + +convert :: [AST] -> [AST] +convert = map convertFile + +convertFile :: AST -> AST +convertFile descriptions = + descriptions' ++ map (uncurry castFn) funcs + where + results = map convertDescription descriptions + descriptions' = map fst results + funcs = Set.toList $ Set.unions $ map snd results + +convertDescription :: Description -> (Description, CastSet) +convertDescription description = + (description', info) + where + (description', info) = + runWriter $ + scopedConversionM traverseDeclM traverseModuleItemM traverseStmtM + Map.empty description + +traverseDeclM :: Decl -> ST Decl +traverseDeclM decl = do + case decl of + Variable _ t x _ _ -> modify $ Map.insert x t + Param _ t x _ -> modify $ Map.insert x t + ParamType _ _ _ -> return () + return decl + +traverseModuleItemM :: ModuleItem -> ST ModuleItem +traverseModuleItemM item = traverseExprsM traverseExprM item + +traverseStmtM :: Stmt -> ST Stmt +traverseStmtM stmt = traverseStmtExprsM traverseExprM stmt + +traverseExprM :: Expr -> ST Expr +traverseExprM = + traverseNestedExprsM convertExprM + where + convertExprM :: Expr -> ST Expr + convertExprM (Cast (Right (Number n)) e) = do + typeMap <- get + case (readNumber n, exprSigning typeMap e) of + (Just size, Just sg) -> do + lift $ tell $ Set.singleton (size, sg) + let f = castFnName size sg + let args = Args [Just e] [] + return $ Call Nothing f args + _ -> return $ Cast (Right $ Number n) e + convertExprM other = return other + + +castFn :: Int -> Signing -> Description +castFn n sg = + PackageItem $ + Function (Just Automatic) t fnName [decl] [Return $ Ident inp] + where + inp = "inp" + r = (Number $ show (n - 1), Number "0") + t = IntegerVector TLogic sg [r] + fnName = castFnName n sg + decl = Variable Input t inp [] Nothing + +castFnName :: Int -> Signing -> String +castFnName n sg = + if n <= 0 + then error $ "cannot have non-positive size cast: " ++ show n + else + if sg == Unspecified + then init name + else name + where name = "sv2v_cast_" ++ show n ++ "_" ++ show sg + +exprSigning :: TypeMap -> Expr -> Maybe Signing +exprSigning typeMap (Ident x) = + case Map.lookup x typeMap of + Just t -> typeSigning t + Nothing -> Just Unspecified +exprSigning typeMap (BinOp op e1 e2) = + combiner sg1 sg2 + where + sg1 = exprSigning typeMap e1 + sg2 = exprSigning typeMap e2 + combiner = case op of + BitAnd -> combineSigning + BitXor -> combineSigning + BitXnor -> combineSigning + BitOr -> combineSigning + Mul -> combineSigning + Div -> combineSigning + Add -> combineSigning + Sub -> combineSigning + Mod -> curry fst + Pow -> curry fst + ShiftAL -> curry fst + ShiftAR -> curry fst + _ -> \_ _ -> Just Unspecified +exprSigning _ _ = Just Unspecified + +combineSigning :: Maybe Signing -> Maybe Signing -> Maybe Signing +combineSigning Nothing _ = Nothing +combineSigning _ Nothing = Nothing +combineSigning (Just Unspecified) msg = msg +combineSigning msg (Just Unspecified) = msg +combineSigning (Just Signed) _ = Just Signed +combineSigning _ (Just Signed) = Just Signed +combineSigning (Just Unsigned) _ = Just Unsigned + +typeSigning :: Type -> Maybe Signing +typeSigning (Net _ sg _) = Just sg +typeSigning (Implicit sg _) = Just sg +typeSigning (IntegerVector _ sg _) = Just sg +typeSigning _ = Nothing diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index 6e6e653..cdf0e0d 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -78,11 +78,13 @@ module Convert.Traverse , collectNestedLHSsM , traverseScopesM , scopedConversion +, scopedConversionM , stately , traverseFilesM , traverseFiles ) where +import Data.Functor.Identity (runIdentity) import Control.Monad.State import Control.Monad.Writer import Language.SystemVerilog.AST @@ -1009,10 +1011,11 @@ collectNestedExprsM = collectify traverseNestedExprsM -- statements recursively, as we add a recursive wrapper here. traverseScopesM :: (Eq s, Show s) - => MapperM (State s) Decl - -> MapperM (State s) ModuleItem - -> MapperM (State s) Stmt - -> MapperM (State s) ModuleItem + => Monad m + => MapperM (StateT s m) Decl + -> MapperM (StateT s m) ModuleItem + -> MapperM (StateT s m) Stmt + -> MapperM (StateT s m) ModuleItem traverseScopesM declMapper moduleItemMapper stmtMapper = fullModuleItemMapper where @@ -1072,7 +1075,19 @@ scopedConversion -> Description -> Description scopedConversion traverseDeclM traverseModuleItemM traverseStmtM s description = - evalState (initialTraverse description >>= scopedTraverse) s + runIdentity $ scopedConversionM traverseDeclM traverseModuleItemM traverseStmtM s description + +scopedConversionM + :: (Eq s, Show s) + => Monad m + => MapperM (StateT s m) Decl + -> MapperM (StateT s m) ModuleItem + -> MapperM (StateT s m) Stmt + -> s + -> Description + -> m Description +scopedConversionM traverseDeclM traverseModuleItemM traverseStmtM s description = + evalStateT (initialTraverse description >>= scopedTraverse) s where initialTraverse = traverseModuleItemsM traverseMIPackageItemDecl scopedTraverse = traverseModuleItemsM $ diff --git a/sv2v.cabal b/sv2v.cabal index 0b562e0..494bad0 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -77,6 +77,7 @@ executable sv2v Convert.RemoveComments Convert.Return Convert.Simplify + Convert.SizeCast Convert.StarPort Convert.StmtBlock Convert.Stream diff --git a/test/basic/cast.sv b/test/basic/cast.sv new file mode 100644 index 0000000..97b5c3f --- /dev/null +++ b/test/basic/cast.sv @@ -0,0 +1,23 @@ +module top; + initial begin + logic [31:0] w = 1234; + int x = -235; + int y = 1234; + logic [4:0] z = y; + $display("%0d %0d", w, 5'(w)); + $display("%0d %0d", x, 5'(x)); + $display("%0d %0d", y, 5'(y)); + $display("%0d %0d", z, 5'(z)); + $display("%0d %0d", w+1, 5'(w+1)); + $display("%0d %0d", x+1, 5'(x+1)); + $display("%0d %0d", y+1, 5'(y+1)); + $display("%0d %0d", z+1, 5'(z+1)); + $display("%b %b", w, 40'(w)); + $display("%b %b", x, 40'(x)); + $display("%b %b", y, 40'(y)); + $display("%b %b", z, 40'(z)); + end + localparam bit foo = '0; + localparam logic [31:0] bar = 32'(foo); + initial $display("%b %b", foo, bar); +endmodule diff --git a/test/basic/cast.v b/test/basic/cast.v new file mode 100644 index 0000000..a658614 --- /dev/null +++ b/test/basic/cast.v @@ -0,0 +1,27 @@ +module top; + initial begin : foo_block + reg [31:0] w; + reg signed [31:0] x; + reg signed [31:0] y; + reg [4:0] z; + w = 1234; + x = -235; + y = 1234; + z = y; + $display("%0d %0d", w, w[4:0]); + $display("%0d %0d", x, $signed(x[4:0])); + $display("%0d %0d", y, $signed(y[4:0])); + $display("%0d %0d", z, z[4:0]); + $display("%0d %0d", w+1, w[4:0]+1); + $display("%0d %0d", x+1, $signed(x[4:0])+1); + $display("%0d %0d", y+1, $signed(y[4:0])+1); + $display("%0d %0d", z+1, z[4:0]+1); + $display("%b %b", w, {8'b0, w}); + $display("%b %b", x, {8'hFF, x}); + $display("%b %b", y, {8'b0, y}); + $display("%b %b", z, {35'b0, z}); + end + localparam foo = 0; + localparam [31:0] bar = 32'b0; + initial $display("%b %b", foo, bar); +endmodule