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
|
{- sv2v
|
||||||
- Author: Zachary Snow <zach@zachjs.com>
|
- 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
|
- 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
|
- 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
|
- the candidate, the results is `1'bx`. As required by the specification, the
|
||||||
- result of each comparison is combined using an OR reduction.
|
- 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: 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
|
module Convert.Inside (convert) where
|
||||||
|
|
@ -16,13 +20,20 @@ module Convert.Inside (convert) where
|
||||||
import Convert.Traverse
|
import Convert.Traverse
|
||||||
import Language.SystemVerilog.AST
|
import Language.SystemVerilog.AST
|
||||||
|
|
||||||
|
import Data.Maybe (fromMaybe)
|
||||||
|
|
||||||
convert :: [AST] -> [AST]
|
convert :: [AST] -> [AST]
|
||||||
convert =
|
convert = map $ traverseDescriptions $ traverseModuleItems convertModuleItem
|
||||||
map $
|
|
||||||
traverseDescriptions $ traverseModuleItems $
|
convertModuleItem :: ModuleItem -> ModuleItem
|
||||||
traverseExprs $ traverseNestedExprs convertExpr
|
convertModuleItem item =
|
||||||
|
traverseExprs (traverseNestedExprs convertExpr) $
|
||||||
|
traverseStmts convertStmt $
|
||||||
|
item
|
||||||
|
|
||||||
convertExpr :: Expr -> Expr
|
convertExpr :: Expr -> Expr
|
||||||
|
convertExpr (Inside Nil valueRanges) =
|
||||||
|
Inside Nil valueRanges
|
||||||
convertExpr (Inside expr valueRanges) =
|
convertExpr (Inside expr valueRanges) =
|
||||||
if length checks == 1
|
if length checks == 1
|
||||||
then head checks
|
then head checks
|
||||||
|
|
@ -44,3 +55,27 @@ convertExpr (Inside expr valueRanges) =
|
||||||
(BinOp Le lo expr)
|
(BinOp Le lo expr)
|
||||||
(BinOp Ge hi expr)
|
(BinOp Ge hi expr)
|
||||||
convertExpr other = other
|
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 (..)
|
, DimFn (..)
|
||||||
, showAssignment
|
, showAssignment
|
||||||
, showRanges
|
, showRanges
|
||||||
|
, showExprOrRange
|
||||||
, simplify
|
, simplify
|
||||||
, rangeSize
|
, rangeSize
|
||||||
, endianCondExpr
|
, endianCondExpr
|
||||||
|
|
@ -85,9 +86,6 @@ instance Show Expr where
|
||||||
show (Inside e l ) = printf "(%s inside { %s })" (show e) (intercalate ", " strs)
|
show (Inside e l ) = printf "(%s inside { %s })" (show e) (intercalate ", " strs)
|
||||||
where
|
where
|
||||||
strs = map showExprOrRange l
|
strs = map showExprOrRange l
|
||||||
showExprOrRange :: ExprOrRange -> String
|
|
||||||
showExprOrRange (Left x) = show x
|
|
||||||
showExprOrRange (Right x) = show x
|
|
||||||
show (Pattern l ) =
|
show (Pattern l ) =
|
||||||
printf "'{\n%s\n}" (indent $ intercalate ",\n" $ map showPatternItem l)
|
printf "'{\n%s\n}" (indent $ intercalate ",\n" $ map showPatternItem l)
|
||||||
where
|
where
|
||||||
|
|
@ -159,6 +157,10 @@ showRanges l = " " ++ (concatMap showRange l)
|
||||||
showRange :: Range -> String
|
showRange :: Range -> String
|
||||||
showRange (h, l) = printf "[%s:%s]" (show h) (show l)
|
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 :: Int -> Int -> Int
|
||||||
clog2Help p n = if p >= n then 0 else 1 + clog2Help (p*2) n
|
clog2Help p n = if p >= n then 0 else 1 + clog2Help (p*2) n
|
||||||
clog2 :: Int -> Int
|
clog2 :: Int -> Int
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import Text.Printf (printf)
|
||||||
import Language.SystemVerilog.AST.ShowHelp (commas, indent, unlines', showPad)
|
import Language.SystemVerilog.AST.ShowHelp (commas, indent, unlines', showPad)
|
||||||
import Language.SystemVerilog.AST.Attr (Attr)
|
import Language.SystemVerilog.AST.Attr (Attr)
|
||||||
import Language.SystemVerilog.AST.Decl (Decl)
|
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.LHS (LHS)
|
||||||
import Language.SystemVerilog.AST.Op (AsgnOp(AsgnOpEq))
|
import Language.SystemVerilog.AST.Op (AsgnOp(AsgnOpEq))
|
||||||
import Language.SystemVerilog.AST.Type (Identifier)
|
import Language.SystemVerilog.AST.Type (Identifier)
|
||||||
|
|
@ -132,7 +132,11 @@ showShortBranch stmt = showBranch stmt
|
||||||
|
|
||||||
showCase :: Case -> String
|
showCase :: Case -> String
|
||||||
showCase (a, b) = printf "%s:%s" exprStr (showShortBranch b)
|
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
|
data CaseKW
|
||||||
= CaseN
|
= CaseN
|
||||||
|
|
|
||||||
|
|
@ -1046,17 +1046,13 @@ CaseKW :: { CaseKW }
|
||||||
| "casez" { CaseZ }
|
| "casez" { CaseZ }
|
||||||
|
|
||||||
Cases :: { [Case] }
|
Cases :: { [Case] }
|
||||||
: {- empty -} { [] }
|
: opt("inside") InsideCases { validateCases $1 $2 }
|
||||||
| Case Cases { $1 : $2 }
|
InsideCases :: { [([ExprOrRange], Stmt)] }
|
||||||
| CaseDefault CasesNoDefault { ([], $1) : $2 }
|
: InsideCase { [$1] }
|
||||||
CasesNoDefault :: { [Case] }
|
| InsideCases InsideCase { $1 ++ [$2] }
|
||||||
: {- empty -} { [] }
|
InsideCase :: { ([ExprOrRange], Stmt) }
|
||||||
| CasesNoDefault Case { $1 ++ [$2] }
|
: OpenRangeList ":" Stmt { ($1, $3) }
|
||||||
|
| "default" opt(":") Stmt { ([], $3) }
|
||||||
Case :: { Case }
|
|
||||||
: Exprs ":" Stmt { ($1, $3) }
|
|
||||||
CaseDefault :: { Stmt }
|
|
||||||
: "default" opt(":") Stmt { $3 }
|
|
||||||
|
|
||||||
Number :: { String }
|
Number :: { String }
|
||||||
: number { tokenString $1 }
|
: number { tokenString $1 }
|
||||||
|
|
@ -1223,17 +1219,11 @@ GenBlock :: { (Identifier, [GenItem]) }
|
||||||
: "begin" StrTag GenItems "end" StrTag { (combineTags $2 $5, $3) }
|
: "begin" StrTag GenItems "end" StrTag { (combineTags $2 $5, $3) }
|
||||||
|
|
||||||
GenCases :: { [GenCase] }
|
GenCases :: { [GenCase] }
|
||||||
: {- empty -} { [] }
|
: GenCase { [$1] }
|
||||||
| GenCase GenCases { $1 : $2 }
|
| GenCases GenCase { validateGenCases $ $1 ++ [$2] }
|
||||||
| GenCaseDefault GenCasesNoDefault { ([], $1) : $2 }
|
|
||||||
GenCasesNoDefault :: { [GenCase] }
|
|
||||||
: {- empty -} { [] }
|
|
||||||
| GenCasesNoDefault GenCase { $1 ++ [$2] }
|
|
||||||
|
|
||||||
GenCase :: { GenCase }
|
GenCase :: { GenCase }
|
||||||
: Exprs ":" GenItemOrNull { ($1, $3) }
|
: Exprs ":" GenItemOrNull { ($1, $3) }
|
||||||
GenCaseDefault :: { GenItem }
|
| "default" opt(":") GenItemOrNull { ([], $3) }
|
||||||
: "default" opt(":") GenItemOrNull { $3 }
|
|
||||||
|
|
||||||
GenvarInitialization :: { (Bool, Identifier, Expr) }
|
GenvarInitialization :: { (Bool, Identifier, Expr) }
|
||||||
: "genvar" Identifier "=" Expr { (True , $2, $4) }
|
: "genvar" Identifier "=" Expr { (True , $2, $4) }
|
||||||
|
|
@ -1335,4 +1325,34 @@ fieldDecl t (x, rs2) =
|
||||||
(tf $ rs2 ++ rs1, x)
|
(tf $ rs2 ++ rs1, x)
|
||||||
where (tf, rs1) = typeRanges t
|
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));
|
$display("test2(%02d) = %b", i, test2(i));
|
||||||
end
|
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
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -51,4 +51,19 @@ module top;
|
||||||
$display("test2(%02d) = %b", i, test2(i));
|
$display("test2(%02d) = %b", i, test2(i));
|
||||||
end
|
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
|
endmodule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue