From 6e8659a5376db0887b7408353b5499bd96ecbf2a Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sun, 10 Jul 2022 22:43:33 -0400 Subject: [PATCH] support hierarchical calls to functions with no inputs --- CHANGELOG.md | 1 + src/Convert.hs | 2 +- src/Convert/EmptyArgs.hs | 105 ++++++++++++++++++++++------------- test/core/empty_args_hier.sv | 32 +++++++++++ test/core/empty_args_hier.v | 36 ++++++++++++ 5 files changed, 136 insertions(+), 40 deletions(-) create mode 100644 test/core/empty_args_hier.sv create mode 100644 test/core/empty_args_hier.v diff --git a/CHANGELOG.md b/CHANGELOG.md index d98396b..5eb83d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ * Added support for procedural continuous assignments (`assign`/`deassign` and `force`/`release`) * Added conversion for `do` `while` loops +* Added support for hierarchical calls to functions with no inputs * Added support for passing through DPI imports and exports * Added support for passing through functions with output ports * Extended applicability of simplified Yosys-compatible `for` loop elaboration diff --git a/src/Convert.hs b/src/Convert.hs index 8424f0f..2b1aac2 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -67,6 +67,7 @@ finalPhases _ = [ Convert.NamedBlock.convert , Convert.DuplicateGenvar.convert , Convert.AsgnOp.convert + , Convert.EmptyArgs.convert , Convert.FuncRet.convert , Convert.TFBlock.convert ] @@ -107,7 +108,6 @@ initialPhases selectExclude = , Convert.Unique.convert , Convert.EventEdge.convert , Convert.LogOp.convert - , Convert.EmptyArgs.convert , Convert.DoWhile.convert , Convert.Foreach.convert , Convert.FuncRoutine.convert diff --git a/src/Convert/EmptyArgs.hs b/src/Convert/EmptyArgs.hs index 8e9c42a..4290e61 100644 --- a/src/Convert/EmptyArgs.hs +++ b/src/Convert/EmptyArgs.hs @@ -8,50 +8,77 @@ module Convert.EmptyArgs (convert) where -import Control.Monad.Writer.Strict -import qualified Data.Set as Set - +import Convert.Scoper import Convert.Traverse import Language.SystemVerilog.AST -type Idents = Set.Set Identifier +type SC = Scoper () convert :: [AST] -> [AST] -convert = map $ traverseDescriptions convertDescription +convert = map $ traverseDescriptions traverseDescription -convertDescription :: Description -> Description -convertDescription description@Part{} = - traverseModuleItems - (traverseExprs $ traverseNestedExprs $ convertExpr functions) - description' - where - (description', functions) = - runWriter $ traverseModuleItemsM traverseFunctionsM description -convertDescription other = other +traverseDescription :: Description -> Description +traverseDescription = + evalScoper . scopePart scoper . + traverseModuleItems addDummyArg + where scoper = scopeModuleItem + traverseDecl traverseModuleItem traverseGenItem traverseStmt -traverseFunctionsM :: ModuleItem -> Writer Idents ModuleItem -traverseFunctionsM item@(MIPackageItem (Function _ Void _ _ _)) = - return item -traverseFunctionsM (MIPackageItem (Function l t f decls stmts)) = do - decls' <- - if any isInput decls - then return decls - else do - tell $ Set.singleton f - return $ dummyDecl : decls - return $ MIPackageItem $ Function l t f decls' stmts - where - dummyType = IntegerVector TReg Unspecified [] - dummyDecl = Variable Input dummyType "_sv2v_unused" [] Nil - isInput :: Decl -> Bool - isInput (Variable Input _ _ _ _) = True - isInput _ = False -traverseFunctionsM other = return other +-- add a dummy argument to functions with no input ports +addDummyArg :: ModuleItem -> ModuleItem +addDummyArg (MIPackageItem (Function l t f decls stmts)) + | all (not . isInput) decls = + MIPackageItem $ Function l t f (dummyDecl : decls) stmts +addDummyArg other = other -convertExpr :: Idents -> Expr -> Expr -convertExpr functions (Call (Ident func) (Args [] [])) = - Call (Ident func) (Args args []) - where args = if Set.member func functions - then [RawNum 0] - else [] -convertExpr _ other = other +isInput :: Decl -> Bool +isInput (Variable Input _ _ _ _) = True +isInput _ = False + +-- write down all declarations so we can look up the dummy arg +traverseDecl :: Decl -> SC Decl +traverseDecl decl = do + decl' <- case decl of + Param _ _ x _ -> insertElem x () >> return decl + ParamType _ x _ -> insertElem x () >> return decl + Variable d t x a e -> do + insertElem x () + -- new dummy args have a special name for idempotence + return $ if x == dummyIdent + then Variable d t dummyIdentFinal a e + else decl + Net _ _ _ _ x _ _ -> insertElem x () >> return decl + CommentDecl{} -> return decl + traverseDeclExprsM traverseExpr decl' + +traverseModuleItem :: ModuleItem -> SC ModuleItem +traverseModuleItem = traverseExprsM traverseExpr + +traverseGenItem :: GenItem -> SC GenItem +traverseGenItem = traverseGenItemExprsM traverseExpr + +traverseStmt :: Stmt -> SC Stmt +traverseStmt = traverseStmtExprsM traverseExpr + +-- pass a dummy value to functions which had no inputs +traverseExpr :: Expr -> SC Expr +traverseExpr (Call func (Args args [])) = do + details <- lookupElemM $ Dot func dummyIdent + let args' = if details /= Nothing + then RawNum 0 : args + else args + return $ Call func (Args args' []) +traverseExpr expr = + traverseSinglyNestedExprsM traverseExpr expr + +dummyIdent :: Identifier +dummyIdent = '?' : dummyIdentFinal + +dummyIdentFinal :: Identifier +dummyIdentFinal = "_sv2v_unused" + +dummyType :: Type +dummyType = IntegerVector TReg Unspecified [] + +dummyDecl :: Decl +dummyDecl = Variable Input dummyType dummyIdent [] Nil diff --git a/test/core/empty_args_hier.sv b/test/core/empty_args_hier.sv new file mode 100644 index 0000000..b6bc21e --- /dev/null +++ b/test/core/empty_args_hier.sv @@ -0,0 +1,32 @@ +interface intf; + function automatic integer f; + return 1; + endfunction + if (1) begin : blk + function automatic integer f; + return 2; + endfunction + end +endinterface + +module top; + intf i(); + function automatic integer f; + return 3; + endfunction + if (1) begin : blk + function automatic integer f; + return 4; + endfunction + end + initial begin + $display(f()); + $display(blk.f()); + $display(i.f()); + $display(i.blk.f()); + $display(top.f()); + $display(top.blk.f()); + $display(top.i.f()); + $display(top.i.blk.f()); + end +endmodule diff --git a/test/core/empty_args_hier.v b/test/core/empty_args_hier.v new file mode 100644 index 0000000..23d804d --- /dev/null +++ b/test/core/empty_args_hier.v @@ -0,0 +1,36 @@ +module top; + generate + if (1) begin : i + function automatic integer f; + input unused; + f = 1; + endfunction + if (1) begin : blk + function automatic integer f; + input unused; + f = 2; + endfunction + end + end + function automatic integer f; + input unused; + f = 3; + endfunction + if (1) begin : blk + function automatic integer f; + input unused; + f = 4; + endfunction + end + endgenerate + initial begin + $display(f(0)); + $display(blk.f(0)); + $display(i.f(0)); + $display(i.blk.f(0)); + $display(top.f(0)); + $display(top.blk.f(0)); + $display(top.i.f(0)); + $display(top.i.blk.f(0)); + end +endmodule