From 77b9d2f08509c416aef3d8db4d54b19917368823 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sun, 15 Sep 2019 15:49:21 -0400 Subject: [PATCH] support and conversion for foreach --- src/Convert.hs | 2 ++ src/Convert/Foreach.hs | 38 +++++++++++++++++++++ src/Convert/Traverse.hs | 2 ++ src/Language/SystemVerilog/AST/Expr.hs | 40 ++++++++++++++--------- src/Language/SystemVerilog/AST/Stmt.hs | 2 ++ src/Language/SystemVerilog/AST/Type.hs | 5 ++- src/Language/SystemVerilog/Parser/Parse.y | 7 ++++ sv2v.cabal | 1 + test/basic/foreach.sv | 18 ++++++++++ test/basic/foreach.v | 29 ++++++++++++++++ test/lib/functions.sh | 4 +-- 11 files changed, 129 insertions(+), 19 deletions(-) create mode 100644 src/Convert/Foreach.hs create mode 100644 test/basic/foreach.sv create mode 100644 test/basic/foreach.v diff --git a/src/Convert.hs b/src/Convert.hs index 6960514..065674b 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -17,6 +17,7 @@ import qualified Convert.DimensionQuery import qualified Convert.EmptyArgs import qualified Convert.Enum import qualified Convert.ForDecl +import qualified Convert.Foreach import qualified Convert.FuncRet import qualified Convert.Interface import qualified Convert.IntTypes @@ -69,6 +70,7 @@ phases excludes = , Convert.Enum.convert , Convert.NestPI.convert , Convert.Return.convert + , Convert.Foreach.convert , selectExclude (Job.Interface, Convert.Interface.convert) , selectExclude (Job.Always , Convert.AlwaysKW.convert) , selectExclude (Job.Succinct , Convert.RemoveComments.convert) diff --git a/src/Convert/Foreach.hs b/src/Convert/Foreach.hs new file mode 100644 index 0000000..d0b99e8 --- /dev/null +++ b/src/Convert/Foreach.hs @@ -0,0 +1,38 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `foreach` loops. + - + - We simply convert these loops to a series of loops, with the bounds and + - direction provided by the array dimension query system functions. Omitted + - indices are skipped. + -} + +module Convert.Foreach (convert) where + +import Convert.Traverse +import Language.SystemVerilog.AST + +convert :: [AST] -> [AST] +convert = + map $ traverseDescriptions $ traverseModuleItems $ + traverseStmts convertStmt + +convertStmt :: Stmt -> Stmt +convertStmt (Foreach x idxs stmt) = + (foldl (.) id $ map toLoop $ zip [1..] idxs) stmt + where + toLoop :: (Int, Maybe Identifier) -> (Stmt -> Stmt) + toLoop (_, Nothing) = id + toLoop (d, Just i) = + For [Left idxDecl] (Just cmp) [incr] + where + queryFn f = DimFn f (Right $ Ident x) (Number $ show d) + idxDecl = Variable Local (IntegerAtom TInteger Unspecified) i [] + $ Just $ queryFn FnLeft + cmp = + Mux (BinOp Eq (queryFn FnIncrement) (Number "1")) + (BinOp Ge (Ident i) (queryFn FnRight)) + (BinOp Le (Ident i) (queryFn FnRight)) + incr = (LHSIdent i, AsgnOp Sub, queryFn FnIncrement) +convertStmt other = other diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index 8907549..c13152f 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -235,6 +235,7 @@ traverseSinglyNestedStmtsM fullMapper = cs cs (RepeatL e stmt) = fullMapper stmt >>= return . RepeatL e cs (DoWhile e stmt) = fullMapper stmt >>= return . DoWhile e cs (Forever stmt) = fullMapper stmt >>= return . Forever + cs (Foreach x vars stmt) = fullMapper stmt >>= return . Foreach x vars cs (If u e s1 s2) = do s1' <- fullMapper s1 s2' <- fullMapper s2 @@ -682,6 +683,7 @@ traverseStmtExprsM exprMapper = flatStmtMapper flatStmtMapper (DoWhile e stmt) = exprMapper e >>= \e' -> return $ DoWhile e' stmt flatStmtMapper (Forever stmt) = return $ Forever stmt + flatStmtMapper (Foreach x vars stmt) = return $ Foreach x vars stmt flatStmtMapper (If u cc s1 s2) = exprMapper cc >>= \cc' -> return $ If u cc' s1 s2 flatStmtMapper (Timing event stmt) = return $ Timing event stmt diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index cc86b5c..0a7c815 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -162,6 +162,8 @@ readNumber n = -- basic expression simplfication utility to help us generate nicer code in the -- common case of ranges like `[FOO-1:0]` simplify :: Expr -> Expr +simplify (UniOp LogNot (Number "1")) = Number "0" +simplify (UniOp LogNot (Number "0")) = Number "1" simplify (Repeat (Number "0") _) = Concat [] simplify (Concat [expr]) = expr simplify (Concat exprs) = @@ -170,23 +172,17 @@ simplify (orig @ (Call Nothing "$clog2" (Args [Just (Number n)] []))) = case readNumber n of Nothing -> orig Just x -> Number $ show $ clog2 x -simplify (Mux (Number "0") e _) = e -simplify (Mux (BinOp Ge c1 c2) e1 e2) = - case (c1', c2') of - (Number a, Number b) -> - case (readNumber a, readNumber b) of - (Just x, Just y) -> - if x >= y - then e1 - else e2 - _ -> nochange - _ -> nochange +simplify (Mux cc e1 e2) = + case cc' of + Number "1" -> e1' + Number "0" -> e2' + _ -> Mux cc' e1' e2' where - c1' = simplify c1 - c2' = simplify c2 + cc' = simplify cc e1' = simplify e1 e2' = simplify e2 - nochange = Mux (BinOp Ge c1' c2') e1' e2' +simplify (Range e NonIndexed r) = Range e NonIndexed r +simplify (Range e _ (i, Number "0")) = Bit e i simplify (BinOp Sub (Number n1) (BinOp Sub (Number n2) e)) = simplify $ BinOp Add (BinOp Sub (Number n1) (Number n2)) e simplify (BinOp Sub (Number n1) (BinOp Sub e (Number n2))) = @@ -211,21 +207,30 @@ simplify (BinOp op e1 e2) = (Add, BinOp Sub e (Number "1"), Number "1") -> e (Add, e, BinOp Sub (Number "0") (Number "1")) -> BinOp Sub e (Number "1") (_ , Number a, Number b) -> - case (op, readNumber a, readNumber b) of + case (op, readNumber a :: Maybe Int, readNumber b :: Maybe Int) of (Add, Just x, Just y) -> Number $ show (x + y) (Sub, Just x, Just y) -> Number $ show (x - y) (Mul, Just x, Just y) -> Number $ show (x * y) (Div, Just _, Just 0) -> Number "x" (Div, Just x, Just y) -> Number $ show (x `quot` y) + (Eq , Just x, Just y) -> bool $ x == y + (Ne , Just x, Just y) -> bool $ x /= y + (Gt , Just x, Just y) -> bool $ x > y + (Ge , Just x, Just y) -> bool $ x >= y + (Lt , Just x, Just y) -> bool $ x < y + (Le , Just x, Just y) -> bool $ x <= y _ -> BinOp op e1' e2' (Add, BinOp Add e (Number a), Number b) -> case (readNumber a, readNumber b) of (Just x, Just y) -> BinOp Add e $ Number $ show (x + y) _ -> BinOp op e1' e2' + (Sub, e, Number "-1") -> BinOp Add e (Number "1") _ -> BinOp op e1' e2' where e1' = simplify e1 e2' = simplify e2 + bool True = Number "1" + bool False = Number "0" simplify other = other rangeSize :: Range -> Expr @@ -258,7 +263,10 @@ sizedExpr x s (Number n) = ++ " doesn't have size " ++ show size else Number res where - Number size = simplify s + size = + case simplify s of + Number v -> v + other -> error $ "could not simplify sizedExpr: " ++ show other unticked = case n of '\'' : rest -> rest rest -> rest diff --git a/src/Language/SystemVerilog/AST/Stmt.hs b/src/Language/SystemVerilog/AST/Stmt.hs index ebec897..b80aced 100644 --- a/src/Language/SystemVerilog/AST/Stmt.hs +++ b/src/Language/SystemVerilog/AST/Stmt.hs @@ -43,6 +43,7 @@ data Stmt | RepeatL Expr Stmt | DoWhile Expr Stmt | Forever Stmt + | Foreach Identifier [Maybe Identifier] Stmt | If (Maybe UniquePriority) Expr Stmt Stmt | Timing Timing Stmt | Return Expr @@ -86,6 +87,7 @@ instance Show Stmt where show (RepeatL e s) = printf "repeat (%s) %s" (show e) (show s) show (DoWhile e s) = printf "do %s while (%s);" (show s) (show e) show (Forever s ) = printf "forever %s" (show s) + show (Foreach x i s) = printf "foreach (%s [ %s ]) %s" x (commas $ map (maybe "" id) i) (show s) show (If u a b Null) = printf "%sif (%s) %s" (maybe "" showPad u) (show a) (show b) show (If u a b c ) = printf "%sif (%s) %s\nelse %s" (maybe "" showPad u) (show a) (show b) (show c) show (Return e ) = printf "return %s;" (show e) diff --git a/src/Language/SystemVerilog/AST/Type.hs b/src/Language/SystemVerilog/AST/Type.hs index a162c86..4c06328 100644 --- a/src/Language/SystemVerilog/AST/Type.hs +++ b/src/Language/SystemVerilog/AST/Type.hs @@ -95,7 +95,10 @@ nullRange :: Type -> ([Range] -> Type) nullRange t [] = t nullRange t [(Number "0", Number "0")] = t nullRange (IntegerAtom TInteger sg) rs = - -- integer arrays are allowed in SystemVerilog but not in Verilor + -- integer arrays are allowed in SystemVerilog but not in Verilog + IntegerVector TBit sg (rs ++ [(Number "31", Number "0")]) +nullRange (IntegerAtom TInt sg) rs = + -- int arrays are allowed in SystemVerilog but not in Verilog IntegerVector TBit sg (rs ++ [(Number "31", Number "0")]) nullRange t rs = error $ "non-vector type " ++ show t ++ diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index c4df5ab..1a520bb 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -884,6 +884,7 @@ StmtNonAsgn :: { Stmt } | "repeat" "(" Expr ")" Stmt { RepeatL $3 $5 } | "do" Stmt "while" "(" Expr ")" ";" { DoWhile $5 $2 } | "forever" Stmt { Forever $2 } + | "foreach" "(" Identifier IdxVars ")" Stmt { Foreach $3 $4 $6 } | "->" Identifier ";" { Trigger $2 } | AttributeInstance Stmt { StmtAttr $1 $2 } | ProceduralAssertionStatement { Assertion $1 } @@ -905,6 +906,12 @@ ForStepAssignment :: { (LHS, AsgnOp, Expr) } | IncOrDecOperator LHS { ($2, AsgnOp $1, Number "1") } | LHS IncOrDecOperator { ($1, AsgnOp $2, Number "1") } +IdxVars :: { [Maybe Identifier] } + : "[" IdxVarsInside "]" { $2 } +IdxVarsInside :: { [Maybe Identifier] } + : opt(Identifier) { [$1] } + | opt(Identifier) "," IdxVarsInside { $1 : $3 } + DeclsAndStmts :: { ([Decl], [Stmt]) } : DeclOrStmt DeclsAndStmts { combineDeclsAndStmts $1 $2 } | StmtNonAsgn Stmts { ([], $1 : $2) } diff --git a/sv2v.cabal b/sv2v.cabal index 30cb39b..0b562e0 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -62,6 +62,7 @@ executable sv2v Convert.EmptyArgs Convert.Enum Convert.ForDecl + Convert.Foreach Convert.FuncRet Convert.Interface Convert.IntTypes diff --git a/test/basic/foreach.sv b/test/basic/foreach.sv new file mode 100644 index 0000000..47b8b74 --- /dev/null +++ b/test/basic/foreach.sv @@ -0,0 +1,18 @@ +module top; + logic [1:0] foo [4] = {2'b10,2'b01,2'b11,2'b00}; + initial + foreach (foo [ x ]) + $display(x, foo[x]); + + // from the SystemVerilog-2017 specification + int A [2][3][4]; + bit [3:0][2:1] B [5:1][4]; + initial begin + A = 0; + B = 0; + foreach( A [ i, j, k ] ) + $display(i, j, k); + foreach( B [ q, r, , s ] ) + $display(q, r, s); + end +endmodule diff --git a/test/basic/foreach.v b/test/basic/foreach.v new file mode 100644 index 0000000..468e835 --- /dev/null +++ b/test/basic/foreach.v @@ -0,0 +1,29 @@ +module top; + wire [7:0] foo = {2'b10,2'b01,2'b11,2'b00}; + initial begin : f + integer x; + for (x = 0; x <= 3; x = x + 1) + $display(x, foo[6 - 2*x+:2]); + end + + reg [32*2*3*4 - 1:0] A; + reg [5*4*4*2 + 32: 1 + 32] B; + initial begin + A = 0; + B = 0; + begin : g + integer i, j, k; + for (i = 0; i <= 1; i = i + 1) + for (j = 0; j <= 2; j = j + 1) + for (k = 0; k <= 3; k = k + 1) + $display(i, j, k); + end + begin : h + integer q, r, s; + for (q = 5; q >= 1; q = q - 1) + for (r = 0; r <= 3; r = r + 1) + for (s = 2; s >= 1; s = s - 1) + $display(q, r, s); + end + end +endmodule diff --git a/test/lib/functions.sh b/test/lib/functions.sh index a5fc1b0..966fc97 100644 --- a/test/lib/functions.sh +++ b/test/lib/functions.sh @@ -113,8 +113,8 @@ simulateAndCompare() { # simulate and compare the two files simulate "$ref_vcd" "$ref_log" top "$ve" "$tb" simulate "$gen_vcd" "$gen_log" top "$cv" "$tb" - diff "$ref_vcd" "$gen_vcd" > /dev/null - assertTrue "VCDs are different" $? + output=`diff "$ref_vcd" "$gen_vcd"` + assertTrue "VCDs are different:\n$output" $? output=`diff "$ref_log" "$gen_log"` assertTrue "Simulation outputs differ:\n$output" $? }