Commit 6e8659a5 by Zachary Snow

support hierarchical calls to functions with no inputs

parent 5dcbce5f
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
* Added support for procedural continuous assignments (`assign`/`deassign` and * Added support for procedural continuous assignments (`assign`/`deassign` and
`force`/`release`) `force`/`release`)
* Added conversion for `do` `while` loops * 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 DPI imports and exports
* Added support for passing through functions with output ports * Added support for passing through functions with output ports
* Extended applicability of simplified Yosys-compatible `for` loop elaboration * Extended applicability of simplified Yosys-compatible `for` loop elaboration
......
...@@ -67,6 +67,7 @@ finalPhases _ = ...@@ -67,6 +67,7 @@ finalPhases _ =
[ Convert.NamedBlock.convert [ Convert.NamedBlock.convert
, Convert.DuplicateGenvar.convert , Convert.DuplicateGenvar.convert
, Convert.AsgnOp.convert , Convert.AsgnOp.convert
, Convert.EmptyArgs.convert
, Convert.FuncRet.convert , Convert.FuncRet.convert
, Convert.TFBlock.convert , Convert.TFBlock.convert
] ]
...@@ -107,7 +108,6 @@ initialPhases selectExclude = ...@@ -107,7 +108,6 @@ initialPhases selectExclude =
, Convert.Unique.convert , Convert.Unique.convert
, Convert.EventEdge.convert , Convert.EventEdge.convert
, Convert.LogOp.convert , Convert.LogOp.convert
, Convert.EmptyArgs.convert
, Convert.DoWhile.convert , Convert.DoWhile.convert
, Convert.Foreach.convert , Convert.Foreach.convert
, Convert.FuncRoutine.convert , Convert.FuncRoutine.convert
......
...@@ -8,50 +8,77 @@ ...@@ -8,50 +8,77 @@
module Convert.EmptyArgs (convert) where module Convert.EmptyArgs (convert) where
import Control.Monad.Writer.Strict import Convert.Scoper
import qualified Data.Set as Set
import Convert.Traverse import Convert.Traverse
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
type Idents = Set.Set Identifier type SC = Scoper ()
convert :: [AST] -> [AST] convert :: [AST] -> [AST]
convert = map $ traverseDescriptions convertDescription convert = map $ traverseDescriptions traverseDescription
convertDescription :: Description -> Description traverseDescription :: Description -> Description
convertDescription description@Part{} = traverseDescription =
traverseModuleItems evalScoper . scopePart scoper .
(traverseExprs $ traverseNestedExprs $ convertExpr functions) traverseModuleItems addDummyArg
description' where scoper = scopeModuleItem
where traverseDecl traverseModuleItem traverseGenItem traverseStmt
(description', functions) =
runWriter $ traverseModuleItemsM traverseFunctionsM description -- add a dummy argument to functions with no input ports
convertDescription other = other addDummyArg :: ModuleItem -> ModuleItem
addDummyArg (MIPackageItem (Function l t f decls stmts))
traverseFunctionsM :: ModuleItem -> Writer Idents ModuleItem | all (not . isInput) decls =
traverseFunctionsM item@(MIPackageItem (Function _ Void _ _ _)) = MIPackageItem $ Function l t f (dummyDecl : decls) stmts
return item addDummyArg other = other
traverseFunctionsM (MIPackageItem (Function l t f decls stmts)) = do
decls' <- isInput :: Decl -> Bool
if any isInput decls isInput (Variable Input _ _ _ _) = True
then return decls isInput _ = False
else do
tell $ Set.singleton f -- write down all declarations so we can look up the dummy arg
return $ dummyDecl : decls traverseDecl :: Decl -> SC Decl
return $ MIPackageItem $ Function l t f decls' stmts traverseDecl decl = do
where decl' <- case decl of
dummyType = IntegerVector TReg Unspecified [] Param _ _ x _ -> insertElem x () >> return decl
dummyDecl = Variable Input dummyType "_sv2v_unused" [] Nil ParamType _ x _ -> insertElem x () >> return decl
isInput :: Decl -> Bool Variable d t x a e -> do
isInput (Variable Input _ _ _ _) = True insertElem x ()
isInput _ = False -- new dummy args have a special name for idempotence
traverseFunctionsM other = return other return $ if x == dummyIdent
then Variable d t dummyIdentFinal a e
convertExpr :: Idents -> Expr -> Expr else decl
convertExpr functions (Call (Ident func) (Args [] [])) = Net _ _ _ _ x _ _ -> insertElem x () >> return decl
Call (Ident func) (Args args []) CommentDecl{} -> return decl
where args = if Set.member func functions traverseDeclExprsM traverseExpr decl'
then [RawNum 0]
else [] traverseModuleItem :: ModuleItem -> SC ModuleItem
convertExpr _ other = other 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
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
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
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