mirror of https://github.com/zachjs/sv2v.git
support assignments within expressions
This commit is contained in:
parent
4ced649a87
commit
ed09fe88cf
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
### New Features
|
||||
|
||||
* Added support for assignments within expressions (e.g., `x = ++y;`)
|
||||
* Added support for excluding the conversion of unbased unsized literals (e.g.,
|
||||
`'1`, `'x`) via `--exclude UnbasedUniszed`
|
||||
* Added support for enumerated type ranges (e.g., `enum { X[3:5] }`)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import qualified Convert.DoWhile
|
|||
import qualified Convert.DuplicateGenvar
|
||||
import qualified Convert.EmptyArgs
|
||||
import qualified Convert.Enum
|
||||
import qualified Convert.ExprAsgn
|
||||
import qualified Convert.ForAsgn
|
||||
import qualified Convert.Foreach
|
||||
import qualified Convert.FuncRet
|
||||
|
|
@ -101,6 +102,7 @@ initialPhases :: Selector -> [Phase]
|
|||
initialPhases selectExclude =
|
||||
[ Convert.ForAsgn.convert
|
||||
, Convert.Jump.convert
|
||||
, Convert.ExprAsgn.convert
|
||||
, Convert.KWArgs.convert
|
||||
, Convert.Unique.convert
|
||||
, Convert.SenseEdge.convert
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
{-# LANGUAGE PatternSynonyms #-}
|
||||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion for assignments within expressions
|
||||
-
|
||||
- IEEE 1800-2017 Section 11.3.6 states that assignments within expressions can
|
||||
- only appear in procedural statements, though some tools support them in other
|
||||
- contexts. We do not currently raise an error for assignments within
|
||||
- expressions in unsupported contexts.
|
||||
-
|
||||
- Assignment expressions are replaced with the LHS, with the LHS being updated
|
||||
- in a preceding statement. For post-increment operations, a pre-increment is
|
||||
- performed and then the increment is reversed in the expression.
|
||||
-
|
||||
- This conversion occurs after the elaboration of `do` `while` loops and
|
||||
- `foreach` loops, but before the elaboration of jumps and extra `for` loop
|
||||
- initializations.
|
||||
-}
|
||||
|
||||
module Convert.ExprAsgn (convert) where
|
||||
|
||||
import Control.Monad.Writer.Strict
|
||||
import Data.Bitraversable (bimapM)
|
||||
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert = map $ traverseDescriptions $ traverseModuleItems $
|
||||
traverseStmts convertStmt
|
||||
|
||||
convertStmt :: Stmt -> Stmt
|
||||
|
||||
-- assignment expressions in a loop guard
|
||||
convertStmt (While cond stmt) =
|
||||
if null add
|
||||
then While cond stmt'
|
||||
else block $ add ++ [While cond' $ injectLoopIter add stmt']
|
||||
where
|
||||
(cond', add) = runWriter $ convertExpr cond
|
||||
stmt' = convertStmt stmt
|
||||
|
||||
-- assignment expressions can appear in any part of the for loop
|
||||
convertStmt (For inits cond incrs stmt) =
|
||||
if null initsAdd && null condAdd && null incrsAdd
|
||||
then For inits cond incrs stmt'
|
||||
else For initsCombined cond' incrs' $
|
||||
injectLoopIter (incrsAdd ++ condAdd) stmt'
|
||||
where
|
||||
(inits', initsAdd) = runWriter $ mapM convertInit inits
|
||||
(cond', condAdd) = runWriter $ convertExpr cond
|
||||
(incrs', incrsAdd) = runWriter $ mapM convertIncr incrs
|
||||
stmt' = convertStmt stmt
|
||||
initsCombined = map toInit initsAdd ++ inits' ++ map toInit condAdd
|
||||
|
||||
-- assignment expressions in other statements are added in front
|
||||
convertStmt stmt =
|
||||
traverseSinglyNestedStmts convertStmt $
|
||||
if null add
|
||||
then stmt
|
||||
else block $ add ++ [stmt']
|
||||
where (stmt', add) = runWriter $ traverseStmtExprsM convertExpr stmt
|
||||
|
||||
-- helper for creating simple blocks
|
||||
block :: [Stmt] -> Stmt
|
||||
block = Block Seq "" []
|
||||
|
||||
-- add statements before the loop guard is checked
|
||||
injectLoopIter :: [Stmt] -> Stmt -> Stmt
|
||||
injectLoopIter add stmt = block $ beforeContinue add stmt : add
|
||||
|
||||
-- add statements before every `continue` in the loop
|
||||
beforeContinue :: [Stmt] -> Stmt -> Stmt
|
||||
beforeContinue _ stmt@While{} = stmt
|
||||
beforeContinue _ stmt@For{} = stmt
|
||||
beforeContinue add Continue =
|
||||
block $ add ++ [Continue]
|
||||
beforeContinue add stmt =
|
||||
traverseSinglyNestedStmts (beforeContinue add) stmt
|
||||
|
||||
-- reversible pattern to unwrap in for loops
|
||||
pattern AsgnStmt :: LHS -> Expr -> Stmt
|
||||
pattern AsgnStmt lhs expr = Asgn AsgnOpEq Nothing lhs expr
|
||||
|
||||
toInit :: Stmt -> (LHS, Expr)
|
||||
toInit stmt = (lhs, expr)
|
||||
where AsgnStmt lhs expr = stmt
|
||||
|
||||
-- functions which convert and collect assignment expressions
|
||||
type Converter t = t -> Writer [Stmt] t
|
||||
|
||||
convertExpr :: Converter Expr
|
||||
convertExpr (ExprAsgn l r) = do
|
||||
l' <- convertExpr l
|
||||
r' <- convertExpr r
|
||||
let Just lhs = exprToLHS l' -- checked by parser
|
||||
tell [AsgnStmt lhs r']
|
||||
return l'
|
||||
convertExpr expr =
|
||||
traverseSinglyNestedExprsM convertExpr expr
|
||||
|
||||
convertLHS :: Converter LHS
|
||||
convertLHS = traverseNestedLHSsM $ traverseLHSExprsM convertExpr
|
||||
|
||||
convertInit :: Converter (LHS, Expr)
|
||||
convertInit = bimapM convertLHS convertExpr
|
||||
|
||||
convertIncr :: Converter (LHS, AsgnOp, Expr)
|
||||
convertIncr (lhs, op, expr) = do
|
||||
lhs' <- convertLHS lhs
|
||||
expr' <- convertExpr expr
|
||||
return (lhs', op, expr')
|
||||
|
|
@ -497,6 +497,10 @@ traverseSinglyNestedExprsM exprMapper = em
|
|||
e2' <- exprMapper e2
|
||||
e3' <- exprMapper e3
|
||||
return $ MinTypMax e1' e2' e3'
|
||||
em (ExprAsgn e1 e2) = do
|
||||
e1' <- exprMapper e1
|
||||
e2' <- exprMapper e2
|
||||
return $ ExprAsgn e1' e2'
|
||||
em (Nil) = return Nil
|
||||
|
||||
traverseSinglyNestedExprs :: Mapper Expr -> Mapper Expr
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ data Expr
|
|||
| Pattern [(TypeOrExpr, Expr)]
|
||||
| Inside Expr [Expr]
|
||||
| MinTypMax Expr Expr Expr
|
||||
| ExprAsgn Expr Expr
|
||||
| Nil
|
||||
deriving Eq
|
||||
|
||||
|
|
@ -92,6 +93,7 @@ instance Show Expr where
|
|||
showPatternItem (Left t, v) = printf "%s: %s" tStr (show v)
|
||||
where tStr = if null (show t) then "default" else show t
|
||||
show (MinTypMax a b c) = printf "(%s : %s : %s)" (show a) (show b) (show c)
|
||||
show (ExprAsgn l r) = printf "(%s = %s)" (show l) (show r)
|
||||
show e@UniOp{} = showsPrec 0 e ""
|
||||
show e@BinOp{} = showsPrec 0 e ""
|
||||
show e@Dot {} = showsPrec 0 e ""
|
||||
|
|
|
|||
|
|
@ -1385,6 +1385,11 @@ Expr :: { Expr }
|
|||
| "^" Expr %prec REDUCE_OP { UniOp RedXor $2 }
|
||||
| "~^" Expr %prec REDUCE_OP { UniOp RedXnor $2 }
|
||||
| "^~" Expr %prec REDUCE_OP { UniOp RedXnor $2 }
|
||||
-- assignments within expressions
|
||||
| "(" Expr "=" Expr ")" {% makeExprAsgn (tokenPosition $3, AsgnOpEq) $2 $4 }
|
||||
| "(" Expr AsgnBinOpP Expr ")" {% makeExprAsgn $3 $2 $4 }
|
||||
| Expr IncOrDecOperatorP {% makeIncrExprAsgn True $2 $1 }
|
||||
| IncOrDecOperatorP Expr %prec "++" {% makeIncrExprAsgn False $1 $2 }
|
||||
|
||||
ExprOrNil :: { Expr }
|
||||
: Expr { $1 }
|
||||
|
|
@ -1786,4 +1791,24 @@ makeDPIImport :: String -> DPIImportProperty -> Identifier
|
|||
-> (Type, Identifier, [Decl]) -> PackageItem
|
||||
makeDPIImport a b c (d, e, f) = DPIImport a b c d e f
|
||||
|
||||
makeExprAsgn :: (Position, AsgnOp) -> Expr -> Expr -> ParseState Expr
|
||||
makeExprAsgn (pos, AsgnOpEq) l r = do
|
||||
case exprToLHS l of
|
||||
Just{} -> return ()
|
||||
Nothing -> parseError pos $ "cannot convert expression to LHS: " ++ show l
|
||||
return $ ExprAsgn l r
|
||||
makeExprAsgn (pos, op) l r =
|
||||
makeExprAsgn (pos, AsgnOpEq) l r'
|
||||
where
|
||||
AsgnOp binop = op
|
||||
r' = BinOp binop l r
|
||||
|
||||
makeIncrExprAsgn :: Bool -> (Position, BinOp) -> Expr -> ParseState Expr
|
||||
makeIncrExprAsgn False (pos, op) expr =
|
||||
makeExprAsgn (pos, AsgnOp op) expr (RawNum 1)
|
||||
makeIncrExprAsgn True (pos, op) expr = do
|
||||
expr' <- makeIncrExprAsgn False (pos, op) expr
|
||||
return $ BinOp op expr' minusOne
|
||||
where minusOne = Number $ Decimal 1 True 1
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ executable sv2v
|
|||
Convert.DuplicateGenvar
|
||||
Convert.EmptyArgs
|
||||
Convert.Enum
|
||||
Convert.ExprAsgn
|
||||
Convert.ExprUtils
|
||||
Convert.ForAsgn
|
||||
Convert.Foreach
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
module top;
|
||||
integer i;
|
||||
byte b;
|
||||
shortint s;
|
||||
initial begin
|
||||
$monitor("%2d %b %b %b", $time, i, b, s);
|
||||
|
||||
#1 i = (b = (s = 0));
|
||||
#1 i = 1;
|
||||
#1 i = {1'bx, b++, 1'bx};
|
||||
#1 i = {1'bx, b--, 1'bx};
|
||||
#1 i = {1'bx, ++b, 1'bx};
|
||||
#1 i = {1'bx, --b, 1'bx};
|
||||
|
||||
#1 i = 3;
|
||||
while (--i) begin
|
||||
if (i == 2) begin
|
||||
s++;
|
||||
#10;
|
||||
end
|
||||
else if (i == 1) begin
|
||||
b++;
|
||||
#3 continue;
|
||||
$display("UNREACHABLE");
|
||||
end
|
||||
b--;
|
||||
#1;
|
||||
end
|
||||
|
||||
#1;
|
||||
for (i[i++] = s--; b++ - 10 != s--; i[++i]++) begin
|
||||
#1;
|
||||
if (i & 1)
|
||||
continue;
|
||||
#10;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
module top;
|
||||
integer i;
|
||||
reg signed [7:0] b;
|
||||
reg signed [15:0] s;
|
||||
initial begin
|
||||
$monitor("%2d %b %b %b", $time, i, b, s);
|
||||
|
||||
#1;
|
||||
s = 0;
|
||||
b = 0;
|
||||
i = 0;
|
||||
|
||||
#1 i = 1;
|
||||
|
||||
#1;
|
||||
b = b + 1;
|
||||
i = {1'bx, b - 8'b1, 1'bx};
|
||||
|
||||
#1;
|
||||
b = b - 1;
|
||||
i = {1'bx, b + 8'b1, 1'bx};
|
||||
|
||||
#1;
|
||||
b = b + 1;
|
||||
i = {1'bx, b, 1'bx};
|
||||
|
||||
#1;
|
||||
b = b - 1;
|
||||
i = {1'bx, b, 1'bx};
|
||||
|
||||
#1;
|
||||
i = 3;
|
||||
i = i - 1;
|
||||
s = s + 1;
|
||||
#10;
|
||||
b = b - 1;
|
||||
#1;
|
||||
i = i - 1;
|
||||
b = b + 1;
|
||||
#3;
|
||||
i = i - 1;
|
||||
|
||||
#1;
|
||||
i = i + 1;
|
||||
s = s - 1;
|
||||
i[i] = s;
|
||||
b = b + 1;
|
||||
s = s - 1;
|
||||
while (b - 1 - 10 != s + 1) begin
|
||||
#1;
|
||||
if (!(i & 1))
|
||||
#10;
|
||||
i = i + 1;
|
||||
i[i] = i[i] + 1;
|
||||
b = b + 1;
|
||||
s = s - 1;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// pattern: cannot convert expression to LHS
|
||||
// location: asgn_expr_non_lhs.sv:5:20
|
||||
module top;
|
||||
integer x;
|
||||
initial x = (1 = x);
|
||||
endmodule
|
||||
Loading…
Reference in New Issue