From fb5fd39388876ae17b24ac98b5531a5418300e39 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sun, 8 Dec 2019 17:36:25 -0500 Subject: [PATCH] support for inside expression ranges and wildcards --- src/Convert.hs | 4 ++ src/Convert/Inside.hs | 46 +++++++++++++++++++++++ src/Convert/Struct.hs | 12 ++++++ src/Convert/Traverse.hs | 10 +++++ src/Convert/Wildcard.hs | 35 +++++++++++++++++ src/Language/SystemVerilog/AST/Expr.hs | 9 +++++ src/Language/SystemVerilog/Parser/Parse.y | 9 ++++- sv2v.cabal | 2 + test/basic/inside_expr.sv | 34 +++++++++++++++++ test/basic/inside_expr.v | 35 +++++++++++++++++ 10 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/Convert/Inside.hs create mode 100644 src/Convert/Wildcard.hs diff --git a/src/Convert.hs b/src/Convert.hs index 2e6a9a7..339cf66 100644 --- a/src/Convert.hs +++ b/src/Convert.hs @@ -19,6 +19,7 @@ import qualified Convert.Enum import qualified Convert.ForDecl import qualified Convert.Foreach import qualified Convert.FuncRet +import qualified Convert.Inside import qualified Convert.Interface import qualified Convert.IntTypes import qualified Convert.Jump @@ -43,6 +44,7 @@ import qualified Convert.UnbasedUnsized import qualified Convert.Unique import qualified Convert.UnpackedArray import qualified Convert.Unsigned +import qualified Convert.Wildcard type Phase = [AST] -> [AST] @@ -56,6 +58,7 @@ phases excludes = , Convert.ForDecl.convert , Convert.FuncRet.convert , Convert.EmptyArgs.convert + , Convert.Inside.convert , Convert.IntTypes.convert , Convert.KWArgs.convert , Convert.LogOp.convert @@ -74,6 +77,7 @@ phases excludes = , Convert.UnpackedArray.convert , Convert.Unsigned.convert , Convert.SignCast.convert + , Convert.Wildcard.convert , Convert.Package.convert , Convert.Enum.convert , Convert.NestPI.convert diff --git a/src/Convert/Inside.hs b/src/Convert/Inside.hs new file mode 100644 index 0000000..ba40160 --- /dev/null +++ b/src/Convert/Inside.hs @@ -0,0 +1,46 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `inside` expressions + - + - The expressions are compared to each candidate using the wildcard comparison + - operator. Note that if expression has any Xs or Zs that are not wildcarded in + - the candidate, the results is `1'bx`. As required by the specification, the + - result of each comparison is combined using an OR reduction. + - + - TODO: Add support for array value ranges. + -} + +module Convert.Inside (convert) where + +import Convert.Traverse +import Language.SystemVerilog.AST + +convert :: [AST] -> [AST] +convert = + map $ + traverseDescriptions $ traverseModuleItems $ + traverseExprs $ traverseNestedExprs convertExpr + +convertExpr :: Expr -> Expr +convertExpr (Inside expr valueRanges) = + if length checks == 1 + then head checks + else UniOp RedOr $ Concat checks + where + checks = map toCheck valueRanges + toCheck :: ExprOrRange -> Expr + toCheck (Left e) = + Mux + (BinOp TNe rxr lxlxrxr) + (Number "1'bx") + (BinOp WEq expr e) + where + lxl = BinOp BitXor expr expr + rxr = BinOp BitXor e e + lxlxrxr = BinOp BitXor lxl rxr + toCheck (Right (lo, hi)) = + BinOp LogAnd + (BinOp Le lo expr) + (BinOp Ge hi expr) +convertExpr other = other diff --git a/src/Convert/Struct.hs b/src/Convert/Struct.hs index 30e1f4c..08bba5f 100644 --- a/src/Convert/Struct.hs +++ b/src/Convert/Struct.hs @@ -538,6 +538,18 @@ convertAsgn structs types (lhs, expr) = where items' = map mapItem items mapItem (mx, e) = (mx, snd $ convertSubExpr e) + convertSubExpr (Inside e l) = + (t, Inside e' l') + where + t = IntegerVector TLogic Unspecified [] + (_, e') = convertSubExpr e + l' = map mapItem l + mapItem :: ExprOrRange -> ExprOrRange + mapItem (Left a) = Left $ snd $ convertSubExpr a + mapItem (Right (a, b)) = Right (a', b') + where + (_, a') = convertSubExpr a + (_, b') = convertSubExpr b convertSubExpr (MinTypMax a b c) = (t, MinTypMax a' b' c') where diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index 5d8a072..f348570 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -428,6 +428,12 @@ traverseNestedExprsM mapper = exprMapper typeOrExprMapper (Left t) = return $ Left t typeOrExprMapper (Right e) = exprMapper e >>= return . Right + exprOrRangeMapper (Left e) = + exprMapper e >>= return . Left + exprOrRangeMapper (Right (e1, e2)) = do + e1' <- exprMapper e1 + e2' <- exprMapper e2 + return $ Right (e1', e2') em (String s) = return $ String s em (Number s) = return $ Number s em (Time s) = return $ Time s @@ -487,6 +493,10 @@ traverseNestedExprsM mapper = exprMapper let names = map fst l exprs <- mapM exprMapper $ map snd l return $ Pattern $ zip names exprs + em (Inside e l) = do + e' <- exprMapper e + l' <- mapM exprOrRangeMapper l + return $ Inside e' l' em (MinTypMax e1 e2 e3) = do e1' <- exprMapper e1 e2' <- exprMapper e2 diff --git a/src/Convert/Wildcard.hs b/src/Convert/Wildcard.hs new file mode 100644 index 0000000..aa93a81 --- /dev/null +++ b/src/Convert/Wildcard.hs @@ -0,0 +1,35 @@ +{- sv2v + - Author: Zachary Snow + - + - Conversion for `==?` and `!=?` + - + - `a ==? b` is defined as the bitwise comparison of `a` and `b`, where X and Z + - values in `b` (but not those in `a`) are used as wildcards. We convert `a ==? + - b` to `a ^ b === b ^ b`. This works because any value xor'ed with X or Z + - becomes X. + - + - `!=?` is simply converted as the logical negation of `==?`, which is + - converted as described above. + -} + +module Convert.Wildcard (convert) where + +import Convert.Traverse +import Language.SystemVerilog.AST + +convert :: [AST] -> [AST] +convert = + map $ + traverseDescriptions $ traverseModuleItems $ + traverseExprs $ traverseNestedExprs convertExpr + +convertExpr :: Expr -> Expr +convertExpr (BinOp WEq l r) = + BinOp TEq + (BinOp BitXor r r) + (BinOp BitXor r l) +convertExpr (BinOp WNe l r) = + UniOp LogNot $ + convertExpr $ + BinOp WEq l r +convertExpr other = other diff --git a/src/Language/SystemVerilog/AST/Expr.hs b/src/Language/SystemVerilog/AST/Expr.hs index d9e5de0..e0f7436 100644 --- a/src/Language/SystemVerilog/AST/Expr.hs +++ b/src/Language/SystemVerilog/AST/Expr.hs @@ -9,6 +9,7 @@ module Language.SystemVerilog.AST.Expr ( Expr (..) , Range , TypeOrExpr + , ExprOrRange , Args (..) , PartSelectMode (..) , DimsFn (..) @@ -34,6 +35,7 @@ import {-# SOURCE #-} Language.SystemVerilog.AST.Type type Range = (Expr, Expr) type TypeOrExpr = Either Type Expr +type ExprOrRange = Either Expr Range data Expr = String String @@ -55,6 +57,7 @@ data Expr | DimFn DimFn TypeOrExpr Expr | Dot Expr Identifier | Pattern [(Identifier, Expr)] + | Inside Expr [ExprOrRange] | MinTypMax Expr Expr Expr | Nil deriving (Eq, Ord) @@ -79,6 +82,12 @@ instance Show Expr where show (Cast tore e ) = printf "%s'(%s)" (showEither tore) (show e) show (DimsFn f v ) = printf "%s(%s)" (show f) (showEither v) show (DimFn f v e) = printf "%s(%s, %s)" (show f) (showEither v) (show e) + show (Inside e l ) = printf "(%s inside { %s })" (show e) (intercalate ", " strs) + where + strs = map showExprOrRange l + showExprOrRange :: ExprOrRange -> String + showExprOrRange (Left x) = show x + showExprOrRange (Right x) = show x show (Pattern l ) = printf "'{\n%s\n}" (indent $ intercalate ",\n" $ map showPatternItem l) where diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index 536b564..e783906 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -1095,6 +1095,13 @@ TypeOrExpr :: { TypeOrExpr } : TypeNonIdent { Left $1 } | Expr { Right $1 } +OpenRangeList :: { [ExprOrRange] } + : ValueRange { [$1] } + | OpenRangeList "," ValueRange { $1 ++ [$3] } +ValueRange :: { ExprOrRange } + : Expr { Left $1 } + | Range { Right $1 } + Expr :: { Expr } : "(" Expr ")" { $2 } | String { String $1 } @@ -1120,7 +1127,7 @@ Expr :: { Expr } | "'" "{" PatternItems "}" { Pattern $3 } | "{" StreamOp StreamSize Concat "}" { Stream $2 $3 $4 } | "{" StreamOp Concat "}" { Stream $2 (Number "1") $3 } - | Expr "inside" Concat { foldl1 (BinOp LogOr) $ map (BinOp Eq $1) $3 } + | Expr "inside" "{" OpenRangeList "}" { Inside $1 $4 } | "(" Expr ":" Expr ":" Expr ")" { MinTypMax $2 $4 $6 } -- binary expressions | Expr "||" Expr { BinOp LogOr $1 $3 } diff --git a/sv2v.cabal b/sv2v.cabal index 13bb502..e36c776 100644 --- a/sv2v.cabal +++ b/sv2v.cabal @@ -65,6 +65,7 @@ executable sv2v Convert.ForDecl Convert.Foreach Convert.FuncRet + Convert.Inside Convert.Interface Convert.IntTypes Convert.Jump @@ -90,6 +91,7 @@ executable sv2v Convert.Unique Convert.UnpackedArray Convert.Unsigned + Convert.Wildcard -- sv2v CLI modules Job ghc-options: diff --git a/test/basic/inside_expr.sv b/test/basic/inside_expr.sv index 7fd00f5..132796c 100644 --- a/test/basic/inside_expr.sv +++ b/test/basic/inside_expr.sv @@ -1,4 +1,5 @@ module top; + initial for (logic [1:0] a = 0; a < 3; a++) begin if (a inside {2'b01, 2'b00}) @@ -6,4 +7,37 @@ module top; if (a inside {2'b10}) $display("buzz"); end + + initial $display("A", 3'bz11 inside {3'b?01}); + initial $display("B", 3'bz11 inside {3'b1?1}); + 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}); + + function test1; + input logic [2:0] inp; + return inp inside {3'b1?1}; + endfunction + initial begin + // should match + $display("test1: %b %b", 3'b101, test1(3'b101)); + $display("test1: %b %b", 3'b111, test1(3'b111)); + $display("test1: %b %b", 3'b1x1, test1(3'b1x1)); + $display("test1: %b %b", 3'b1z1, test1(3'b1z1)); + // shouldn't match + $display("test1: %b %b", 3'b001, test1(3'b001)); + $display("test1: %b %b", 3'b011, test1(3'b011)); + $display("test1: %b %b", 3'b0x1, test1(3'b0x1)); + $display("test1: %b %b", 3'b0z1, test1(3'b0z1)); + end + + function test2; + input integer inp; + return inp inside { [16:23], [32:47] }; + endfunction + initial begin + for (integer i = 0; i < 64; ++i) + $display("test2(%02d) = %b", i, test2(i)); + end + endmodule diff --git a/test/basic/inside_expr.v b/test/basic/inside_expr.v index 61bd9c9..ccceb93 100644 --- a/test/basic/inside_expr.v +++ b/test/basic/inside_expr.v @@ -1,4 +1,5 @@ module top; + initial begin : foo reg [1:0] a; for (a = 0; a < 3; a++) begin @@ -8,4 +9,38 @@ module top; $display("buzz"); end end + + initial $display("A", 1'b0); + initial $display("B", 1'bx); + initial $display("C", 1'bx); + initial $display("D", 1'bx); + initial $display("E", 1'bx); + + function test1; + input [2:0] inp; + test1 = inp[0] == 1 && inp[2] == 1; + endfunction + initial begin + // should match + $display("test1: %b %b", 3'b101, test1(3'b101)); + $display("test1: %b %b", 3'b111, test1(3'b111)); + $display("test1: %b %b", 3'b1x1, test1(3'b1x1)); + $display("test1: %b %b", 3'b1z1, test1(3'b1z1)); + // shouldn't match + $display("test1: %b %b", 3'b001, test1(3'b001)); + $display("test1: %b %b", 3'b011, test1(3'b011)); + $display("test1: %b %b", 3'b0x1, test1(3'b0x1)); + $display("test1: %b %b", 3'b0z1, test1(3'b0z1)); + end + + function test2; + input integer inp; + test2 = (16 <= inp && inp <= 23) || (32 <= inp && inp <= 47); + endfunction + initial begin : foobar + integer i; + for (i = 0; i < 64; ++i) + $display("test2(%02d) = %b", i, test2(i)); + end + endmodule