diff --git a/src/Convert/Cast.hs b/src/Convert/Cast.hs index 7bf9eee..2b7a328 100644 --- a/src/Convert/Cast.hs +++ b/src/Convert/Cast.hs @@ -117,12 +117,18 @@ convertCastM (Number size) (Number value) signed = ++ " is not an integer" convertCastM size value signed = do value' <- traverseExprM value - useFn <- embedScopes canUseCastFn size - if useFn then do + sizeUsesLocalVars <- embedScopes usesLocalVars size + inProcedure <- withinProcedureM + if not sizeUsesLocalVars || not inProcedure then do let name = castFnName size signed - details <- lookupLocalIdentM name - when (details == Nothing) $ - injectItem $ castFn name size signed + let item = castFn name size signed + if sizeUsesLocalVars + then do + details <- lookupLocalIdentM name + when (details == Nothing) (injectItem item) + else do + details <- lookupElemM name + when (details == Nothing) (injectTopItem item) return $ Call (Ident name) (Args [value'] []) else do name <- castDeclName 0 @@ -131,16 +137,19 @@ convertCastM size value signed = do injectDecl $ castDecl useVar name value' size signed return $ Ident name --- checks if a cast size can be hoisted to a cast function -canUseCastFn :: Scopes a -> Expr -> Bool -canUseCastFn scopes size = - not (inProcedure && anyNonLocal) +-- checks if a cast size references any vars not defined at the top level scope +usesLocalVars :: Scopes a -> Expr -> Bool +usesLocalVars scopes = + getAny . execWriter . collectNestedExprsM collectLocalVarsM where - inProcedure = withinProcedure scopes - anyNonLocal = getAny $ execWriter $ - collectNestedExprsM collectNonLocalExprM size - collectNonLocalExprM :: Expr -> Writer Any () - collectNonLocalExprM expr = + collectLocalVarsM :: Expr -> Writer Any () + collectLocalVarsM expr@(Ident x) = + if isLoopVar scopes x + then tell $ Any True + else resolve expr + collectLocalVarsM expr = resolve expr + resolve :: Expr -> Writer Any () + resolve expr = case lookupElem scopes expr of Nothing -> return () Just ([_, _], _, _) -> return () diff --git a/src/Convert/Scoper.hs b/src/Convert/Scoper.hs index f4569c9..08b1e76 100644 --- a/src/Convert/Scoper.hs +++ b/src/Convert/Scoper.hs @@ -38,6 +38,7 @@ module Convert.Scoper , scopeType , insertElem , injectItem + , injectTopItem , injectDecl , lookupElem , lookupElemM @@ -63,6 +64,7 @@ module Convert.Scoper import Control.Monad.State.Strict import Data.Functor.Identity (runIdentity) +import Data.List (partition) import Data.Maybe (isNothing) import qualified Data.Map.Strict as Map @@ -97,7 +99,7 @@ data Scopes a = Scopes { sCurrent :: [Tier] , sMapping :: Mapping a , sProcedureLoc :: [Access] - , sInjectedItems :: [ModuleItem] + , sInjectedItems :: [(Bool, ModuleItem)] , sInjectedDecls :: [Decl] } deriving Show @@ -225,7 +227,11 @@ insertElem key element = do injectItem :: Monad m => ModuleItem -> ScoperT a m () injectItem item = - modify' $ \s -> s { sInjectedItems = item : sInjectedItems s } + modify' $ \s -> s { sInjectedItems = (True, item) : sInjectedItems s } + +injectTopItem :: Monad m => ModuleItem -> ScoperT a m () +injectTopItem item = + modify' $ \s -> s { sInjectedItems = (False, item) : sInjectedItems s } injectDecl :: Monad m => Decl -> ScoperT a m () injectDecl decl = @@ -233,10 +239,13 @@ injectDecl decl = consumeInjectedItems :: Monad m => ScoperT a m [ModuleItem] consumeInjectedItems = do - injected <- gets sInjectedItems + -- only pull out top items if in the top scope + inTopLevelScope <- gets $ (== 1) . length . sCurrent + let op = if inTopLevelScope then const True else fst + (injected, remaining) <- gets $ partition op . sInjectedItems when (not $ null injected) $ - modify' $ \s -> s { sInjectedItems = [] } - return $ reverse injected + modify' $ \s -> s { sInjectedItems = remaining } + return $ reverse $ map snd $ injected consumeInjectedDecls :: Monad m => ScoperT a m [Decl] consumeInjectedDecls = do @@ -517,7 +526,7 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper = exitProcedure return $ Final stmt' fullModuleItemMapper (Generate genItems) = - mapM fullGenItemMapper genItems >>= return . Generate + fullGenItemBlockMapper genItems >>= return . Generate fullModuleItemMapper (MIAttr attr item) = fullModuleItemMapper item >>= return . MIAttr attr fullModuleItemMapper item = moduleItemMapper item @@ -526,43 +535,48 @@ scopeModuleItemT declMapper moduleItemMapper genItemMapper stmtMapper = fullGenItemMapper genItem = do genItem' <- genItemMapper genItem injected <- consumeInjectedItems + genItem'' <- scopeGenItemMapper genItem' + mapM_ injectItem injected -- defer until enclosing block + return genItem'' + + -- akin to fullGenItemMapper, but for lists of generate items, and + -- allowing module items to be injected in the middle of the list + fullGenItemBlockMapper :: [GenItem] -> ScoperT a m [GenItem] + fullGenItemBlockMapper = fmap concat . mapM genblkStep + genblkStep :: GenItem -> ScoperT a m [GenItem] + genblkStep genItem = do + genItem' <- fullGenItemMapper genItem + injected <- consumeInjectedItems if null injected - then scopeGenItemMapper genItem' + then return [genItem'] else do injected' <- mapM fullModuleItemMapper injected - genItem'' <- scopeGenItemMapper genItem' - let genItems = map GenModuleItem injected' ++ [genItem''] - -- flattened during traversal - return $ GenModuleItem $ Generate genItems + return $ map GenModuleItem injected' ++ [genItem'] + + -- enters and exits generate block scopes as appropriate scopeGenItemMapper :: GenItem -> ScoperT a m GenItem + scopeGenItemMapper (GenFor _ _ _ GenNull) = return GenNull scopeGenItemMapper (GenFor (index, a) b c genItem) = do - genItem' <- scopeGenItemBranchMapper index genItem + let GenBlock name genItems = genItem + enterScope name index + genItems' <- fullGenItemBlockMapper genItems + exitScope + let genItem' = GenBlock name genItems' return $ GenFor (index, a) b c genItem' scopeGenItemMapper (GenIf cond thenItem elseItem) = do - thenItem' <- scopeGenItemBranchMapper "" thenItem - elseItem' <- scopeGenItemBranchMapper "" elseItem + thenItem' <- fullGenItemMapper thenItem + elseItem' <- fullGenItemMapper elseItem return $ GenIf cond thenItem' elseItem' scopeGenItemMapper (GenBlock name genItems) = do enterScope name "" - genItems' <- mapM fullGenItemMapper genItems + genItems' <- fullGenItemBlockMapper genItems exitScope return $ GenBlock name genItems' scopeGenItemMapper (GenModuleItem moduleItem) = wrappedModuleItemMapper moduleItem >>= return . GenModuleItem - scopeGenItemMapper genItem = + scopeGenItemMapper genItem@GenCase{} = traverseSinglyNestedGenItemsM fullGenItemMapper genItem - - scopeGenItemBranchMapper :: Identifier -> GenItem -> ScoperT a m GenItem - scopeGenItemBranchMapper index (GenBlock name genItems) = do - enterScope name index - genItems' <- mapM fullGenItemMapper genItems - exitScope - return $ GenBlock name genItems' - scopeGenItemBranchMapper index genItem = do - enterScope "" index - genItem' <- fullGenItemMapper genItem - exitScope - return genItem' + scopeGenItemMapper GenNull = return GenNull partScoper :: MapperM (Scoper a) Decl diff --git a/test/core/cast_top_item.sv b/test/core/cast_top_item.sv new file mode 100644 index 0000000..31bfad1 --- /dev/null +++ b/test/core/cast_top_item.sv @@ -0,0 +1,39 @@ +`ifdef REF + `define CHECK(N) (P & (1 << (Z+N+1) - 1)) +`else + `define CHECK(N) ((Z+N+1)'(P) & (1 << (Z+N+1) - 1)) +`endif + +`define PRINT(N) initial #P $display(`"%b bit N is set`", P); + +module mod; + parameter unsigned P = 1; + parameter Z = 0; + + if (!Z) begin : blk1 + if (`CHECK(0)) `PRINT(0) + else if (`CHECK(1)) `PRINT(1) + else if (`CHECK(2)) `PRINT(2) + end + + if (!Z) begin : blk2 + genvar i; + if (`CHECK(3)) + `PRINT(3) + else + for (i = 1; i == 1 && `CHECK(4); i = i + 1) + `PRINT(4) + end + + if (!Z) begin : blk3 + wire signed x = 1; + `ifdef REF + wire [P - 1:0] tmp = x; + wire [7:0] y = tmp; + `else + wire [7:0] y = $unsigned(P'(x)); + `endif + end + wire [7:0] x = blk3.y; + initial #P $display("%b x = %b", P, x); +endmodule diff --git a/test/core/cast_top_item.v b/test/core/cast_top_item.v new file mode 100644 index 0000000..8bb983d --- /dev/null +++ b/test/core/cast_top_item.v @@ -0,0 +1,2 @@ +`define REF +`include "cast_top_item.sv" diff --git a/test/core/cast_top_item_tb.v b/test/core/cast_top_item_tb.v new file mode 100644 index 0000000..a3647a6 --- /dev/null +++ b/test/core/cast_top_item_tb.v @@ -0,0 +1,7 @@ +module top; + genvar i; + generate + for (i = 0; i < 32; i = i + 1) + mod #(i) m(); + endgenerate +endmodule diff --git a/test/core/local_cast.sv b/test/core/local_cast.sv index b5204a7..ca99121 100644 --- a/test/core/local_cast.sv +++ b/test/core/local_cast.sv @@ -1,17 +1,20 @@ module top; generate for (genvar i = 1; i < 5; ++i) begin + localparam A = $unsigned(i'(1'sb1)); + localparam B = $unsigned((i + 5)'(1'sb1)); initial begin integer x, y; x = $unsigned(i'(1'sb1)); y = $unsigned((i + 5)'(1'sb1)); - $display("%0d %b %b", i, x, y); + $display("%0d %b %b %b %b", i, x, y, A, B); end for (genvar j = 3; j < 6; ++j) begin + localparam C = $unsigned((i * j)'(1'sb1)); initial begin integer x; x = $unsigned((i * j)'(1'sb1)); - $display("%0d %0d %b", i, j, x); + $display("%0d %0d %b %b", i, j, x, C); end end end diff --git a/test/core/local_cast.v b/test/core/local_cast.v index 930c287..d81f107 100644 --- a/test/core/local_cast.v +++ b/test/core/local_cast.v @@ -2,17 +2,20 @@ module top; generate genvar i, j; for (i = 1; i < 5; i = i + 1) begin + localparam [i - 1:0] A = 1'sb1; + localparam [i + 4:0] B = 1'sb1; initial begin : foo integer x, y; x = $unsigned(cast_i(1'sb1)); y = (1 << (i + 5)) - 1; - $display("%0d %b %b", i, x, y); + $display("%0d %b %b %b %b", i, x, y, A, B); end for (j = 3; j < 6; j = j + 1) begin + localparam [i * j - 1:0] C = 1'sb1; initial begin : bar integer x; x = (1 << (i * j)) - 1; - $display("%0d %0d %b", i, j, x); + $display("%0d %0d %b %b", i, j, x, C); end end function signed [i-1:0] cast_i; diff --git a/test/core/named_genblk_cascade.sv b/test/core/named_genblk_cascade.sv new file mode 100644 index 0000000..2e5f4e5 --- /dev/null +++ b/test/core/named_genblk_cascade.sv @@ -0,0 +1,25 @@ +module mod( + output wire [31:0] out +); + parameter P = 0; + if (P == 1) begin : blk1 + wire w [2]; + end + else if (P == 2) begin : blk2 + wire x [3]; + end + else if (P == 3) begin : blk3 + wire y [5]; + end + else begin : blk4 + wire z [7]; + end + if (P == 1) + assign out = $bits(blk1.w); + else if (P == 2) + assign out = $bits(blk2.x); + else if (P == 3) + assign out = $bits(blk3.y); + else + assign out = $bits(blk4.z); +endmodule diff --git a/test/core/named_genblk_cascade.v b/test/core/named_genblk_cascade.v new file mode 100644 index 0000000..1232d87 --- /dev/null +++ b/test/core/named_genblk_cascade.v @@ -0,0 +1,13 @@ +module mod( + output wire [31:0] out +); + parameter P = 0; + if (P == 1) + assign out = 2; + else if (P == 2) + assign out = 3; + else if (P == 3) + assign out = 5; + else + assign out = 7; +endmodule diff --git a/test/core/named_genblk_cascade_tb.v b/test/core/named_genblk_cascade_tb.v new file mode 100644 index 0000000..532fa56 --- /dev/null +++ b/test/core/named_genblk_cascade_tb.v @@ -0,0 +1,7 @@ +module top; + wire [31:0] out1, out2, out3, out4; + mod #(1) m1(out1); + mod #(2) m2(out2); + mod #(3) m3(out3); + mod #(4) m4(out4); +endmodule