mirror of https://github.com/zachjs/sv2v.git
support for inside case statements
This commit is contained in:
parent
ba79b17bd9
commit
7ea5b60d0b
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue