support for inside case statements

This commit is contained in:
Zachary Snow 2019-12-21 19:31:56 -05:00
parent ba79b17bd9
commit 7ea5b60d0b
6 changed files with 121 additions and 31 deletions

View File

@ -1,14 +1,18 @@
{- sv2v
- Author: Zachary Snow <zach@zachjs.com>
-
- Conversion for `inside` expressions
- Conversion for `inside` expressions and cases
-
- 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.
-
- `case ... inside` statements are converted to an equivalent if-else cascade.
-
- TODO: Add support for array value ranges.
- TODO: This conversion may cause an expression with side effects to be
- evaluated more than once.
-}
module Convert.Inside (convert) where
@ -16,13 +20,20 @@ module Convert.Inside (convert) where
import Convert.Traverse
import Language.SystemVerilog.AST
import Data.Maybe (fromMaybe)
convert :: [AST] -> [AST]
convert =
map $
traverseDescriptions $ traverseModuleItems $
traverseExprs $ traverseNestedExprs convertExpr
convert = map $ traverseDescriptions $ traverseModuleItems convertModuleItem
convertModuleItem :: ModuleItem -> ModuleItem
convertModuleItem item =
traverseExprs (traverseNestedExprs convertExpr) $
traverseStmts convertStmt $
item
convertExpr :: Expr -> Expr
convertExpr (Inside Nil valueRanges) =
Inside Nil valueRanges
convertExpr (Inside expr valueRanges) =
if length checks == 1
then head checks
@ -44,3 +55,27 @@ convertExpr (Inside expr valueRanges) =
(BinOp Le lo expr)
(BinOp Ge hi expr)
convertExpr other = other
convertStmt :: Stmt -> Stmt
convertStmt (Case u kw expr items) =
if not $ any isSpecialInside exprs then
Case u kw expr items
else if kw /= CaseN then
error $ "cannot use inside with " ++ show kw
else
foldr ($) defaultStmt $
map (uncurry $ If NoCheck) $
zip comps stmts
where
exprs = map fst items
itemsNonDefault = filter (not . null . fst) items
isSpecialInside :: [Expr] -> Bool
isSpecialInside [Inside Nil _] = True
isSpecialInside _ = False
makeComp :: [Expr] -> Expr
makeComp [Inside Nil ovr] = Inside expr ovr
makeComp _ = error "internal invariant violated"
comps = map (makeComp . fst) itemsNonDefault
stmts = map snd itemsNonDefault
defaultStmt = fromMaybe Null (lookup [] items)
convertStmt other = other

View File

@ -16,6 +16,7 @@ module Language.SystemVerilog.AST.Expr
, DimFn (..)
, showAssignment
, showRanges
, showExprOrRange
, simplify
, rangeSize
, endianCondExpr
@ -85,9 +86,6 @@ instance Show Expr where
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
@ -159,6 +157,10 @@ showRanges l = " " ++ (concatMap showRange l)
showRange :: Range -> String
showRange (h, l) = printf "[%s:%s]" (show h) (show l)
showExprOrRange :: ExprOrRange -> String
showExprOrRange (Left x) = show x
showExprOrRange (Right x) = show x
clog2Help :: Int -> Int -> Int
clog2Help p n = if p >= n then 0 else 1 + clog2Help (p*2) n
clog2 :: Int -> Int

View File

@ -28,7 +28,7 @@ import Text.Printf (printf)
import Language.SystemVerilog.AST.ShowHelp (commas, indent, unlines', showPad)
import Language.SystemVerilog.AST.Attr (Attr)
import Language.SystemVerilog.AST.Decl (Decl)
import Language.SystemVerilog.AST.Expr (Expr, Args(..))
import Language.SystemVerilog.AST.Expr (Expr(Inside, Nil), Args(..), showExprOrRange)
import Language.SystemVerilog.AST.LHS (LHS)
import Language.SystemVerilog.AST.Op (AsgnOp(AsgnOpEq))
import Language.SystemVerilog.AST.Type (Identifier)
@ -132,7 +132,11 @@ showShortBranch stmt = showBranch stmt
showCase :: Case -> String
showCase (a, b) = printf "%s:%s" exprStr (showShortBranch b)
where exprStr = if null a then "default" else commas $ map show a
where
exprStr = case a of
[] -> "default"
[Inside Nil c] -> commas $ map showExprOrRange c
_ -> commas $ map show a
data CaseKW
= CaseN

View File

@ -1046,17 +1046,13 @@ CaseKW :: { CaseKW }
| "casez" { CaseZ }
Cases :: { [Case] }
: {- empty -} { [] }
| Case Cases { $1 : $2 }
| CaseDefault CasesNoDefault { ([], $1) : $2 }
CasesNoDefault :: { [Case] }
: {- empty -} { [] }
| CasesNoDefault Case { $1 ++ [$2] }
Case :: { Case }
: Exprs ":" Stmt { ($1, $3) }
CaseDefault :: { Stmt }
: "default" opt(":") Stmt { $3 }
: opt("inside") InsideCases { validateCases $1 $2 }
InsideCases :: { [([ExprOrRange], Stmt)] }
: InsideCase { [$1] }
| InsideCases InsideCase { $1 ++ [$2] }
InsideCase :: { ([ExprOrRange], Stmt) }
: OpenRangeList ":" Stmt { ($1, $3) }
| "default" opt(":") Stmt { ([], $3) }
Number :: { String }
: number { tokenString $1 }
@ -1223,17 +1219,11 @@ GenBlock :: { (Identifier, [GenItem]) }
: "begin" StrTag GenItems "end" StrTag { (combineTags $2 $5, $3) }
GenCases :: { [GenCase] }
: {- empty -} { [] }
| GenCase GenCases { $1 : $2 }
| GenCaseDefault GenCasesNoDefault { ([], $1) : $2 }
GenCasesNoDefault :: { [GenCase] }
: {- empty -} { [] }
| GenCasesNoDefault GenCase { $1 ++ [$2] }
: GenCase { [$1] }
| GenCases GenCase { validateGenCases $ $1 ++ [$2] }
GenCase :: { GenCase }
: Exprs ":" GenItemOrNull { ($1, $3) }
GenCaseDefault :: { GenItem }
: "default" opt(":") GenItemOrNull { $3 }
: Exprs ":" GenItemOrNull { ($1, $3) }
| "default" opt(":") GenItemOrNull { ([], $3) }
GenvarInitialization :: { (Bool, Identifier, Expr) }
: "genvar" Identifier "=" Expr { (True , $2, $4) }
@ -1335,4 +1325,34 @@ fieldDecl t (x, rs2) =
(tf $ rs2 ++ rs1, x)
where (tf, rs1) = typeRanges t
validateCases :: Maybe Token -> [([ExprOrRange], Stmt)] -> [Case]
validateCases Nothing items =
if length (filter null exprs) <= 1
then zip exprs' stmts
else error $ "multiple default cases: " ++ show items
where
(exprs, stmts) = unzip items
exprs' = map (map unwrap) exprs
unwrap (Left expr) = expr
unwrap (Right range) =
error $ "illegal use of a range (" ++ show range
++ ") in a non-inside case"
validateCases (Just _) items =
if length (filter null sets) <= 1
then zip sets' stmts
else error $ "multiple default cases: " ++ show items
where
(sets, stmts) = unzip items
sets' = map unwrap sets
unwrap [] = []
unwrap ls = [Inside Nil ls]
validateGenCases :: [GenCase] -> [GenCase]
validateGenCases items =
if length (filter null exprs) <= 1
then items
else error $ "multiple default generate cases: " ++ show items
where
(exprs, _) = unzip items
}

View File

@ -46,4 +46,18 @@ module top;
$display("test2(%02d) = %b", i, test2(i));
end
function integer test3;
input integer inp;
case (inp) inside
[16:23]: return 1;
[32:47]: return 2;
default: return 0;
0, [60:61], 4: return 3;
endcase
endfunction
initial begin
for (integer i = 0; i < 64; ++i)
$display("test3(%02d) = %b", i, test3(i));
end
endmodule

View File

@ -51,4 +51,19 @@ module top;
$display("test2(%02d) = %b", i, test2(i));
end
function [0:31] test3;
input integer inp;
begin
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;
else test3 = 0;
end
endfunction
initial begin : block3
integer i;
for (i = 0; i < 64; ++i)
$display("test3(%02d) = %b", i, test3(i));
end
endmodule