diff --git a/src/Convert/Inside.hs b/src/Convert/Inside.hs index 6809f40..06cc1e8 100644 --- a/src/Convert/Inside.hs +++ b/src/Convert/Inside.hs @@ -19,6 +19,7 @@ module Convert.Inside (convert) where import Convert.Traverse import Language.SystemVerilog.AST +import Control.Monad.Writer import Data.Maybe (fromMaybe) convert :: [AST] -> [AST] @@ -54,12 +55,19 @@ convertStmt (Case u kw expr items) = Case u kw expr items else if kw /= CaseN then error $ "cannot use inside with " ++ show kw + else if hasSideEffects expr then + Block Seq "" [decl] [stmt] else foldr ($) defaultStmt $ map (uncurry $ If NoCheck) $ zip comps stmts where exprs = map fst items + -- evaluate expressions with side effects once + tmp = "sv2v_temp_" ++ shortHash expr + decl = Variable Local (TypeOf expr) tmp [] expr + stmt = convertStmt (Case u kw (Ident tmp) items) + -- underlying inside case elaboration itemsNonDefault = filter (not . null . fst) items isSpecialInside :: [Expr] -> Bool isSpecialInside [Inside Nil _] = True @@ -71,3 +79,11 @@ convertStmt (Case u kw expr items) = stmts = map snd itemsNonDefault defaultStmt = fromMaybe Null (lookup [] items) convertStmt other = other + +hasSideEffects :: Expr -> Bool +hasSideEffects expr = + getAny $ execWriter $ collectNestedExprsM write expr + where + write :: Expr -> Writer Any () + write Call{} = tell $ Any True + write _ = return () diff --git a/test/basic/inside_expr.sv b/test/basic/inside_expr.sv index 74abdac..1d07241 100644 --- a/test/basic/inside_expr.sv +++ b/test/basic/inside_expr.sv @@ -1,5 +1,11 @@ module top; + function integer sideEffect; + input integer inp; + $display("sideEffect(%b)", inp); + sideEffect = inp; + endfunction + initial for (logic [1:0] a = 0; a < 3; a++) begin if (a inside {2'b01, 2'b00}) @@ -13,6 +19,9 @@ module top; initial $display("C", 3'bz11 inside {3'b011}); initial $display("D", 3'bz11 inside {3'b1?1, 3'b011}); initial $display("E", 3'bz11 inside {3'b?01, 3'b011}); + // TODO: Add support for inside expressions with side effects. + // initial $display("F", sideEffect(3'bz11) inside {3'b?11}); + // initial $display("G", 3'bz11 inside {sideEffect(3'b?11)}); generate begin : patterns @@ -53,7 +62,7 @@ module top; function integer test3; input integer inp; - case (inp) inside + case (1 + sideEffect(inp)) inside [16:23]: return 1; [32:47]: return 2; default: return 0; diff --git a/test/basic/inside_expr.v b/test/basic/inside_expr.v index 39fbc51..65ed4a7 100644 --- a/test/basic/inside_expr.v +++ b/test/basic/inside_expr.v @@ -1,5 +1,13 @@ module top; + function integer sideEffect; + input integer inp; + begin + $display("sideEffect(%b)", inp); + sideEffect = inp; + end + endfunction + initial begin : foo reg [1:0] a; for (a = 0; a < 3; a++) begin @@ -15,6 +23,14 @@ module top; initial $display("C", 1'bx); initial $display("D", 1'bx); initial $display("E", 1'bx); + // TODO: Add support for inside expressions with side effects. + // initial begin : bar + // integer tmp; + // tmp = sideEffect(3'bz11); + // $display("F", 1'b1); + // tmp = sideEffect(3'b?11); + // $display("G", 1'b1); + // end function test1; input [2:0] inp; @@ -54,6 +70,7 @@ module top; function [0:31] test3; input integer inp; begin + inp = 1 + sideEffect(inp); if (16 <= inp && inp <= 23) test3 = 1; else if (32 <= inp && inp <= 47) test3 = 2; else if (inp == 0 || (60 <= inp && inp <= 61) || inp == 4) test3 = 3;