diff --git a/src/Convert/Interface.hs b/src/Convert/Interface.hs index 2cd9bfa..add2f0e 100644 --- a/src/Convert/Interface.hs +++ b/src/Convert/Interface.hs @@ -7,7 +7,7 @@ module Convert.Interface (convert) where -import Data.Maybe (isNothing, mapMaybe) +import Data.Maybe (isJust, isNothing, mapMaybe) import Control.Monad.Writer.Strict import qualified Data.Map.Strict as Map @@ -391,17 +391,26 @@ inlineInstance global ranges modportBindings items partName Param _ _ x _ -> insertElem x () ParamType _ x _ -> insertElem x () CommentDecl{} -> return () - return decl + traverseDeclExprsM traverseExprM decl traverseModuleItemM :: ModuleItem -> Scoper () ModuleItem - traverseModuleItemM (item @ Modport{}) = + traverseModuleItemM item@Modport{} = traverseExprsM (scopeExpr >=> traverseExprM) item + traverseModuleItemM item@(Instance _ _ x _ _) = + insertElem x () >> traverseExprsM traverseExprM item traverseModuleItemM item = traverseExprsM traverseExprM item >>= traverseLHSsM traverseLHSM traverseGenItemM :: GenItem -> Scoper () GenItem - traverseGenItemM = traverseGenItemExprsM traverseExprM + traverseGenItemM item@(GenFor (x, _) _ _ _) = do + -- don't want to be scoped in modports + insertElem x () + item' <- traverseGenItemExprsM traverseExprM item + removeElem x + return item' + traverseGenItemM item = + traverseGenItemExprsM traverseExprM item traverseStmtM :: Stmt -> Scoper () Stmt traverseStmtM = @@ -497,14 +506,20 @@ inlineInstance global ranges modportBindings items partName checkExprResolution :: Scopes () -> Expr -> a -> a checkExprResolution local expr = - case (lookupElem local expr, lookupElem global expr) of - (Nothing, Just (_, _, DeclVal)) -> + if not (exprResolves local expr) && exprResolves global expr + then error $ "inlining instance \"" ++ instanceName ++ "\" of " ++ inlineKind ++ " \"" ++ partName ++ "\" would make expression \"" ++ show expr ++ "\" used in \"" ++ instanceName ++ "\" resolvable when it wasn't previously" - _ -> id + else id + + exprResolves :: Scopes a -> Expr -> Bool + exprResolves local (Ident x) = + isJust (lookupElem local x) || isLoopVar local x + exprResolves local expr = + isJust (lookupElem local expr) -- unambiguous reference to the current instance scopedInstanceRaw = accessesToExpr $ localAccesses global instanceName diff --git a/src/Convert/Scoper.hs b/src/Convert/Scoper.hs index 3a5ac8b..fbdf9f2 100644 --- a/src/Convert/Scoper.hs +++ b/src/Convert/Scoper.hs @@ -37,6 +37,7 @@ module Convert.Scoper , scopeExpr , scopeType , insertElem + , removeElem , injectItem , injectTopItem , injectDecl @@ -218,10 +219,16 @@ instance ScopePath [Access] where where Ident y = iy insertElem :: Monad m => ScopePath k => k -> a -> ScoperT a m () -insertElem key element = do +insertElem key = setElem key . Just + +removeElem :: Monad m => ScopePath k => k -> ScoperT a m () +removeElem key = setElem key Nothing + +setElem :: Monad m => ScopePath k => k -> Maybe a -> ScoperT a m () +setElem key maybeElement = do s <- get let mapping = sMapping s - let entry = Entry (Just element) "" Map.empty + let entry = Entry maybeElement "" Map.empty let mapping' = setScope (toTiers s key) entry mapping put $ s { sMapping = mapping' } diff --git a/test/core/interface_check_extra.sv b/test/core/interface_check_extra.sv new file mode 100644 index 0000000..123310d --- /dev/null +++ b/test/core/interface_check_extra.sv @@ -0,0 +1,27 @@ +interface intf; + byte x; +endinterface + +module mod(intf j); + intf i(); + assign j.x = 1; + assign i.x = 2; + genvar z; + for (z = 0; z < 2; z++) begin : blk + wire [7:0] x = $bits(j.x) - 5 + z; + end +endmodule + +module top; + byte z = 0; + intf i(); + mod m(i); +`define DUMP(expr) $display(`"expr = %b`", expr); + initial begin + `DUMP(z) + `DUMP(i.x) + `DUMP(m.i.x) + `DUMP(m.blk[0].x) + `DUMP(m.blk[1].x) + end +endmodule diff --git a/test/core/interface_check_extra.v b/test/core/interface_check_extra.v new file mode 100644 index 0000000..bc2be13 --- /dev/null +++ b/test/core/interface_check_extra.v @@ -0,0 +1,11 @@ +module top; + reg [7:0] z = 0; +`define DUMP(expr, val) $display(`"expr = %b`", val); + initial begin + `DUMP(z, z) + `DUMP(i.x, 8'd1) + `DUMP(m.i.x, 8'd2) + `DUMP(m.blk[0].x, 8'd3) + `DUMP(m.blk[1].x, 8'd4) + end +endmodule diff --git a/test/error/interface_bad_expr_genvar.sv b/test/error/interface_bad_expr_genvar.sv new file mode 100644 index 0000000..8b8f54f --- /dev/null +++ b/test/error/interface_bad_expr_genvar.sv @@ -0,0 +1,8 @@ +// pattern: inlining instance "intf" of interface "Interface" would make expression "x" used in "intf" resolvable when it wasn't previously +interface Interface; + assign x = 1; +endinterface +module top; + for (genvar x = 0; x < 2; x++) + Interface intf(); +endmodule