mirror of https://github.com/zachjs/sv2v.git
stronger typename checks
This commit is contained in:
parent
deed2d9fc5
commit
aa451b66a2
|
|
@ -15,12 +15,15 @@
|
|||
* Fixed an issue that prevented parsing tasks and functions with `inout` ports
|
||||
* Fixed conflicting genvar names when inlining interfaces and modules that use
|
||||
them; all genvars are now given a design-wide unique name
|
||||
* Fixed failure to resolve typenames suffixed with dimensions in contexts
|
||||
permitting both types and expressions, e.g., `$bits(T[W-1:0])`
|
||||
* Fixed errant constant folding of shadowed non-trivial localparams
|
||||
* Fixed certain non-ANSI style port declarations being incorrectly reported as
|
||||
incompatible
|
||||
|
||||
### Other Enhancements
|
||||
|
||||
* Added error checking for unresolved typenames
|
||||
* Added constant folding for `||` and `&&`
|
||||
|
||||
## v0.0.11
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Conversion for `typedef`
|
||||
- Conversion for `typedef` and `localparam type`
|
||||
-
|
||||
- Aliased types can appear in all data declarations, including modules, blocks,
|
||||
- and function parameters. They are also found in type cast expressions.
|
||||
|
|
@ -20,22 +20,44 @@ convert = map $ traverseDescriptions $ evalScoper . scopeModule scoper
|
|||
where scoper = scopeModuleItem
|
||||
traverseDeclM traverseModuleItemM traverseGenItemM traverseStmtM
|
||||
|
||||
traverseTypeOrExprM :: TypeOrExpr -> Scoper Type TypeOrExpr
|
||||
traverseTypeOrExprM (Left (TypeOf (Ident x))) = do
|
||||
details <- lookupElemM x
|
||||
return $ case details of
|
||||
Nothing -> Left $ TypeOf $ Ident x
|
||||
Just (_, _, UnknownType) -> Left $ TypeOf $ Ident x
|
||||
Just (_, _, typ) -> Left typ
|
||||
traverseTypeOrExprM (Right (Ident x)) = do
|
||||
details <- lookupElemM x
|
||||
return $ case details of
|
||||
Nothing -> Right $ Ident x
|
||||
Just (_, _, UnknownType) -> Right $ Ident x
|
||||
Just (_, _, typ) -> Left typ
|
||||
traverseTypeOrExprM other = return other
|
||||
type SC = Scoper IdentKind
|
||||
|
||||
traverseExprM :: Expr -> Scoper Type Expr
|
||||
data IdentKind
|
||||
= Type Type -- resolved typename
|
||||
| Pending -- unresolved type parameter
|
||||
| NonType String -- anything else
|
||||
|
||||
traverseTypeOrExprM :: TypeOrExpr -> SC TypeOrExpr
|
||||
traverseTypeOrExprM tore
|
||||
| Left (TypeOf expr) <- tore = possibleTypeName tore expr
|
||||
| Right expr <- tore = possibleTypeName tore expr
|
||||
| otherwise = return tore
|
||||
|
||||
possibleTypeName :: TypeOrExpr -> Expr -> SC TypeOrExpr
|
||||
possibleTypeName orig expr
|
||||
| Just (x, rs1) <- maybeTypeName = do
|
||||
details <- lookupElemM x
|
||||
return $ case details of
|
||||
Just (_, _, Type typ) ->
|
||||
Left $ tf $ rs1 ++ rs2
|
||||
where (tf, rs2) = typeRanges typ
|
||||
Just (_, _, Pending) ->
|
||||
Left $ Alias x rs1
|
||||
_ -> orig
|
||||
| otherwise = return orig
|
||||
where maybeTypeName = exprToTypeName [] expr
|
||||
|
||||
-- aliases in type-or-expr contexts are parsed as expressions
|
||||
exprToTypeName :: [Range] -> Expr -> Maybe (Identifier, [Range])
|
||||
exprToTypeName rs (Ident x) = Just (x, rs)
|
||||
exprToTypeName rs (Bit expr idx) =
|
||||
exprToTypeName (r : rs) expr
|
||||
where r = (RawNum 0, BinOp Sub idx (RawNum 1))
|
||||
exprToTypeName rs (Range expr NonIndexed r) = do
|
||||
exprToTypeName (r : rs) expr
|
||||
exprToTypeName _ _ = Nothing
|
||||
|
||||
traverseExprM :: Expr -> SC Expr
|
||||
traverseExprM (Cast v e) = do
|
||||
v' <- traverseTypeOrExprM v
|
||||
traverseExprM' $ Cast v' e
|
||||
|
|
@ -51,68 +73,82 @@ traverseExprM (Pattern items) = do
|
|||
traverseExprM' $ Pattern $ zip names exprs
|
||||
traverseExprM other = traverseExprM' other
|
||||
|
||||
traverseExprM' :: Expr -> Scoper Type Expr
|
||||
traverseExprM' :: Expr -> SC Expr
|
||||
traverseExprM' =
|
||||
traverseSinglyNestedExprsM traverseExprM
|
||||
>=> traverseExprTypesM traverseTypeM
|
||||
|
||||
traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem
|
||||
traverseModuleItemM :: ModuleItem -> SC ModuleItem
|
||||
traverseModuleItemM (Instance m params x rs p) = do
|
||||
let mapParam (i, v) = traverseTypeOrExprM v >>= \v' -> return (i, v')
|
||||
params' <- mapM mapParam params
|
||||
traverseModuleItemM' $ Instance m params' x rs p
|
||||
traverseModuleItemM item = traverseModuleItemM' item
|
||||
|
||||
traverseModuleItemM' :: ModuleItem -> Scoper Type ModuleItem
|
||||
traverseModuleItemM' :: ModuleItem -> SC ModuleItem
|
||||
traverseModuleItemM' =
|
||||
traverseNodesM traverseExprM return traverseTypeM traverseLHSM return
|
||||
where traverseLHSM = traverseLHSExprsM traverseExprM
|
||||
|
||||
traverseGenItemM :: GenItem -> Scoper Type GenItem
|
||||
traverseGenItemM :: GenItem -> SC GenItem
|
||||
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
||||
|
||||
traverseDeclM :: Decl -> Scoper Type Decl
|
||||
traverseDeclM :: Decl -> SC Decl
|
||||
traverseDeclM decl = do
|
||||
decl' <- traverseDeclNodesM traverseTypeM traverseExprM decl
|
||||
case decl' of
|
||||
Variable{} -> return decl'
|
||||
Net{} -> return decl'
|
||||
Variable _ _ x _ _ -> insertElem x (NonType "var") >> return decl'
|
||||
Net _ _ _ _ x _ _ -> insertElem x (NonType "net") >> return decl'
|
||||
Param s (UnpackedType t rs1) x e -> do
|
||||
insertElem x UnknownType
|
||||
insertElem x (NonType $ show s)
|
||||
let (tf, rs2) = typeRanges t
|
||||
let t' = tf $ rs1 ++ rs2
|
||||
return $ Param s t' x e
|
||||
Param _ _ x _ ->
|
||||
insertElem x UnknownType >> return decl'
|
||||
Param s _ x _ ->
|
||||
insertElem x (NonType $ show s) >> return decl'
|
||||
ParamType Localparam x t -> do
|
||||
traverseTypeM t >>= scopeType >>= insertElem x
|
||||
traverseTypeM t >>= scopeType >>= insertElem x . Type
|
||||
return $ case t of
|
||||
Enum{} -> ParamType Localparam tmpX t
|
||||
_ -> CommentDecl $ "removed localparam type " ++ x
|
||||
where tmpX = "_sv2v_keep_enum_for_params"
|
||||
ParamType{} -> return decl'
|
||||
ParamType Parameter x _ ->
|
||||
insertElem x Pending >> return decl'
|
||||
CommentDecl{} -> return decl'
|
||||
|
||||
traverseStmtM :: Stmt -> Scoper Type Stmt
|
||||
traverseStmtM :: Stmt -> SC Stmt
|
||||
traverseStmtM = traverseStmtExprsM traverseExprM
|
||||
|
||||
traverseTypeM :: Type -> Scoper Type Type
|
||||
traverseTypeM :: Type -> SC Type
|
||||
traverseTypeM (Alias st rs1) = do
|
||||
details <- lookupElemM st
|
||||
rs1' <- mapM traverseRangeM rs1
|
||||
return $ case details of
|
||||
Nothing -> Alias st rs1'
|
||||
Just (_, _, UnknownType) -> Alias st rs1'
|
||||
Just (_, _, typ) -> tf $ rs1' ++ rs2
|
||||
case details of
|
||||
Just (_, _, Type typ) ->
|
||||
return $ tf $ rs1' ++ rs2
|
||||
where (tf, rs2) = typeRanges typ
|
||||
Just (_, _, Pending) ->
|
||||
return $ Alias st rs1'
|
||||
Just (_, _, NonType kind) ->
|
||||
scopedErrorM $ "expected typename, but found " ++ kind
|
||||
++ " identifier " ++ show st
|
||||
Nothing ->
|
||||
scopedErrorM $ "couldn't resolve typename " ++ show st
|
||||
traverseTypeM (TypedefRef expr) = do
|
||||
details <- lookupElemM expr
|
||||
return $ case details of
|
||||
Nothing -> TypedefRef expr
|
||||
Just (_, _, typ) -> typ
|
||||
case details of
|
||||
Just (_, _, Type typ) -> return typ
|
||||
Just (_, _, Pending) ->
|
||||
error "TypdefRef invariant violated! Please file an issue."
|
||||
Just (_, _, NonType kind) ->
|
||||
scopedErrorM $ "expected interface-based typename, but found "
|
||||
++ kind ++ " " ++ show expr
|
||||
-- This can occur when the interface conversion is delayed due to
|
||||
-- multi-dimension instances.
|
||||
Nothing -> return $ TypedefRef expr
|
||||
traverseTypeM other =
|
||||
traverseSinglyNestedTypesM traverseTypeM other
|
||||
>>= traverseTypeExprsM traverseExprM
|
||||
|
||||
traverseRangeM :: Range -> Scoper Type Range
|
||||
traverseRangeM :: Range -> SC Range
|
||||
traverseRangeM = mapBothM traverseExprM
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
`define TEST_INNER(expr, size) \
|
||||
initial $display(`"expr %0d %0d %0d`", \
|
||||
$bits(expr), $bits(type(expr)), size);
|
||||
localparam type T = logic;
|
||||
localparam type U = logic [2:1];
|
||||
`include "typename_deep.svh"
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
`define TEST(expr, size) \
|
||||
`TEST_INNER(expr, size) \
|
||||
`TEST_INNER(expr[2], size * 2) \
|
||||
`TEST_INNER(expr[2][3], size * 6) \
|
||||
`TEST_INNER(expr[3:7], size * 5) \
|
||||
`TEST_INNER(expr[$bits(T)], size) \
|
||||
`TEST_INNER(expr[$bits(U)], size * 2) \
|
||||
`TEST_INNER(expr[$bits(T[$bits(U)])], size * 2) \
|
||||
`TEST_INNER(expr[$bits(U[$bits(U)])], size * 4)
|
||||
|
||||
module top;
|
||||
`TEST(T, 1)
|
||||
`TEST(U, 2)
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
`define TEST_INNER(expr, size) \
|
||||
initial $display(`"expr %0d %0d %0d`", \
|
||||
size, size, size);
|
||||
`include "typename_deep.svh"
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
// pattern: couldn't resolve typename "T"
|
||||
// location: typedef_missing.sv:4:5
|
||||
module top;
|
||||
T x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// pattern: expected typename, but found localparam identifier "L"
|
||||
// location: typedef_not_type_localparam.sv:5:5
|
||||
module top;
|
||||
localparam L = 0;
|
||||
L x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// pattern: expected typename, but found net identifier "w"
|
||||
// location: typedef_not_type_net.sv:5:5
|
||||
module top;
|
||||
wire w;
|
||||
w x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// pattern: expected typename, but found var identifier "v"
|
||||
// location: typedef_not_type_var.sv:5:5
|
||||
module top;
|
||||
var v;
|
||||
v x;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// pattern: expected interface-based typename, but found net x.y
|
||||
// location: typedef_ref_not_type.sv:7:5
|
||||
module top;
|
||||
if (1) begin : x
|
||||
wire y;
|
||||
end
|
||||
typedef x.y T;
|
||||
T x;
|
||||
endmodule
|
||||
Loading…
Reference in New Issue