mirror of https://github.com/zachjs/sv2v.git
substitute constants from type information across scopes
This commit is contained in:
parent
6d2cdf1d21
commit
87ea9de853
|
|
@ -22,6 +22,7 @@ import qualified Convert.ForDecl
|
|||
import qualified Convert.Foreach
|
||||
import qualified Convert.FuncRet
|
||||
import qualified Convert.FuncRoutine
|
||||
import qualified Convert.HierConst
|
||||
import qualified Convert.ImplicitNet
|
||||
import qualified Convert.Inside
|
||||
import qualified Convert.Interface
|
||||
|
|
@ -74,6 +75,7 @@ mainPhases selectExclude =
|
|||
, Convert.MultiplePacked.convert
|
||||
, Convert.UnbasedUnsized.convert
|
||||
, Convert.Cast.convert
|
||||
, Convert.HierConst.convert
|
||||
, Convert.TypeOf.convert
|
||||
, Convert.DimensionQuery.convert
|
||||
, Convert.ParamType.convert
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
{- sv2v
|
||||
- Author: Zachary Snow <zach@zachjs.com>
|
||||
-
|
||||
- Elaborate hierarchical references to constants
|
||||
-
|
||||
- [System]Verilog does not allow hierarchical identifiers as constant
|
||||
- primaries. However, the resolution of type information across scopes can
|
||||
- create such hierarchical references. This conversion performs substitution
|
||||
- for any hierarchical references to parameters or localparams, regardless of
|
||||
- whether or not they occur within what should be a constant expression.
|
||||
-
|
||||
- If an identifier refers to a parameter which has been shadowed locally, the
|
||||
- conversion creates a localparam alias of the parameter at the top level scope
|
||||
- and refers to the parameter using that alias instead.
|
||||
-
|
||||
- TODO: Support resolution of hierarchical references to constant functions
|
||||
- TODO: Some other conversions still blindly substitute type information
|
||||
-}
|
||||
|
||||
module Convert.HierConst (convert) where
|
||||
|
||||
import Data.Either (fromLeft)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
import Convert.Scoper
|
||||
import Convert.Traverse
|
||||
import Language.SystemVerilog.AST
|
||||
|
||||
convert :: [AST] -> [AST]
|
||||
convert = map $ traverseDescriptions convertDescription
|
||||
|
||||
convertDescription :: Description -> Description
|
||||
convertDescription (Part attrs extern kw lifetime name ports items) =
|
||||
Part attrs extern kw lifetime name ports $
|
||||
if null shadowedParams
|
||||
then items'
|
||||
else map expand items'
|
||||
where
|
||||
(items', mapping) = runScoper traverseDeclM
|
||||
(traverseExprsM traverseExprM)
|
||||
(traverseGenItemExprsM traverseExprM)
|
||||
(traverseStmtExprsM traverseExprM)
|
||||
name items
|
||||
shadowedParams = Map.keys $ Map.filter (fromLeft False) $
|
||||
extractMapping mapping
|
||||
expand = traverseNestedModuleItems $ expandParam shadowedParams
|
||||
convertDescription description = description
|
||||
|
||||
expandParam :: [Identifier] -> ModuleItem -> ModuleItem
|
||||
expandParam shadowed (MIPackageItem (Decl (param @ (Param Parameter _ x _)))) =
|
||||
if elem x shadowed
|
||||
then Generate $ map (GenModuleItem . wrap) [param, extra]
|
||||
else wrap param
|
||||
where
|
||||
wrap = MIPackageItem . Decl
|
||||
extra = Param Localparam UnknownType (prefix x) (Ident x)
|
||||
expandParam _ item = item
|
||||
|
||||
prefix :: Identifier -> Identifier
|
||||
prefix = (++) "_sv2v_disambiguate_"
|
||||
|
||||
type ST = Scoper (Either Bool Expr)
|
||||
|
||||
traverseDeclM :: Decl -> ST Decl
|
||||
traverseDeclM decl = do
|
||||
case decl of
|
||||
Param Parameter _ x _ ->
|
||||
insertElem x (Left False)
|
||||
Param Localparam UnknownType x e ->
|
||||
scopeExpr e >>= insertElem x . Right
|
||||
Param Localparam (Implicit sg rs) x e ->
|
||||
scopeExpr (Cast (Left t) e) >>= insertElem x . Right
|
||||
where t = IntegerVector TLogic sg rs
|
||||
Param Localparam t x e ->
|
||||
scopeExpr (Cast (Left t) e) >>= insertElem x . Right
|
||||
_ -> return ()
|
||||
traverseDeclExprsM traverseExprM decl
|
||||
|
||||
-- rewrite an expression so that any constant identifiers it contains
|
||||
-- unambiguously refer refer to currently visible constant declarations so it
|
||||
-- can be substituted elsewhere
|
||||
scopeExpr :: Expr -> ST Expr
|
||||
scopeExpr expr = do
|
||||
expr' <- traverseSinglyNestedExprsM scopeExpr expr
|
||||
details <- lookupElemM expr'
|
||||
case details of
|
||||
Just (accesses, _, _) -> return $ accessesToExpr accesses
|
||||
_ -> return expr'
|
||||
|
||||
-- substitute hierarchical references to constants
|
||||
traverseExprM :: Expr -> ST Expr
|
||||
traverseExprM (expr @ (Dot _ x)) = do
|
||||
expr' <- traverseSinglyNestedExprsM traverseExprM expr
|
||||
detailsE <- lookupElemM expr'
|
||||
detailsX <- lookupElemM x
|
||||
case (detailsE, detailsX) of
|
||||
(Just ([_, _], _, Left{}), Just ([_, _], _, Left{})) ->
|
||||
return $ Ident x
|
||||
(Just (accesses @ [Access _ Nil, _], _, Left False), _) -> do
|
||||
insertElem accesses (Left True)
|
||||
return $ Ident $ prefix x
|
||||
(Just ([Access _ Nil, _], _, Left True), _) ->
|
||||
return $ Ident $ prefix x
|
||||
(Just (aE, replacements, Right value), Just (aX, _, _)) ->
|
||||
if aE == aX && Map.null replacements
|
||||
then return $ Ident x
|
||||
else traverseSinglyNestedExprsM traverseExprM $
|
||||
replaceInExpr replacements value
|
||||
(Just (_, replacements, Right value), Nothing) ->
|
||||
traverseSinglyNestedExprsM traverseExprM $
|
||||
replaceInExpr replacements value
|
||||
_ -> traverseSinglyNestedExprsM traverseExprM expr
|
||||
traverseExprM expr = traverseSinglyNestedExprsM traverseExprM expr
|
||||
|
|
@ -214,13 +214,6 @@ convertDescription parts (Part attrs extern Module lifetime name ports items) =
|
|||
Nothing -> accessesToExpr $ init accesses
|
||||
where Just (accesses, _, _) =
|
||||
lookupElem modports (Dot e "")
|
||||
accessesToExpr :: [Access] -> Expr
|
||||
accessesToExpr accesses =
|
||||
foldl accessToExpr (Ident topName) rest
|
||||
where Access topName Nil : rest = accesses
|
||||
accessToExpr :: Expr -> Access -> Expr
|
||||
accessToExpr e (Access x Nil) = Dot e x
|
||||
accessToExpr e (Access x i) = Bit (Dot e x) i
|
||||
|
||||
-- expand a modport binding into a series of expression substitutions
|
||||
genSubstitutions :: Scopes [ModportDecl] -> Expr -> Expr -> Expr
|
||||
|
|
|
|||
|
|
@ -27,9 +27,13 @@ module Convert.Scoper
|
|||
, ScoperT
|
||||
, evalScoper
|
||||
, evalScoperT
|
||||
, runScoper
|
||||
, runScoperT
|
||||
, partScoper
|
||||
, partScoperT
|
||||
, accessesToExpr
|
||||
, replaceInType
|
||||
, replaceInExpr
|
||||
, insertElem
|
||||
, injectItem
|
||||
, injectDecl
|
||||
|
|
@ -154,6 +158,34 @@ exprToAccesses (Dot e x) = do
|
|||
Just $ accesses ++ [Access x Nil]
|
||||
exprToAccesses _ = Nothing
|
||||
|
||||
accessesToExpr :: [Access] -> Expr
|
||||
accessesToExpr accesses =
|
||||
foldl accessToExpr (Ident topName) rest
|
||||
where Access topName Nil : rest = accesses
|
||||
|
||||
accessToExpr :: Expr -> Access -> Expr
|
||||
accessToExpr e (Access x Nil) = Dot e x
|
||||
accessToExpr e (Access x i) = Bit (Dot e x) i
|
||||
|
||||
replaceInType :: Replacements -> Type -> Type
|
||||
replaceInType replacements =
|
||||
if Map.null replacements
|
||||
then id
|
||||
else traverseNestedTypes $ traverseTypeExprs $
|
||||
replaceInExpr' replacements
|
||||
|
||||
replaceInExpr :: Replacements -> Expr -> Expr
|
||||
replaceInExpr replacements =
|
||||
if Map.null replacements
|
||||
then id
|
||||
else replaceInExpr' replacements
|
||||
|
||||
replaceInExpr' :: Replacements -> Expr -> Expr
|
||||
replaceInExpr' replacements (Ident x) =
|
||||
Map.findWithDefault (Ident x) x replacements
|
||||
replaceInExpr' replacements other =
|
||||
traverseSinglyNestedExprs (replaceInExpr replacements) other
|
||||
|
||||
class ScopePath k where
|
||||
toTiers :: Scopes a -> k -> [Tier]
|
||||
|
||||
|
|
@ -301,6 +333,18 @@ evalScoperT declMapper moduleItemMapper genItemMapper stmtMapper topName items =
|
|||
topName items
|
||||
return items'
|
||||
|
||||
runScoper
|
||||
:: MapperM (Scoper a) Decl
|
||||
-> MapperM (Scoper a) ModuleItem
|
||||
-> MapperM (Scoper a) GenItem
|
||||
-> MapperM (Scoper a) Stmt
|
||||
-> Identifier
|
||||
-> [ModuleItem]
|
||||
-> ([ModuleItem], Scopes a)
|
||||
runScoper declMapper moduleItemMapper genItemMapper stmtMapper topName items =
|
||||
runIdentity $ runScoperT
|
||||
declMapper moduleItemMapper genItemMapper stmtMapper topName items
|
||||
|
||||
runScoperT
|
||||
:: forall a m. Monad m
|
||||
=> MapperM (ScoperT a m) Decl
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
module Convert.TypeOf (convert) where
|
||||
|
||||
import Data.Tuple (swap)
|
||||
import qualified Data.Map.Strict as Map
|
||||
|
||||
import Convert.ExprUtils (dimensionsSize, endianCondRange, simplify)
|
||||
import Convert.Scoper
|
||||
|
|
@ -38,8 +37,10 @@ convert = map $ traverseDescriptions $ partScoper
|
|||
pattern UnitType :: Type
|
||||
pattern UnitType = IntegerVector TLogic Unspecified []
|
||||
|
||||
type ST = Scoper (Type, Bool)
|
||||
|
||||
-- insert the given declaration into the scope, and convert an TypeOfs within
|
||||
traverseDeclM :: Decl -> Scoper Type Decl
|
||||
traverseDeclM :: Decl -> ST Decl
|
||||
traverseDeclM decl = do
|
||||
decl' <- traverseDeclExprsM traverseExprM decl
|
||||
>>= traverseDeclTypesM traverseTypeM
|
||||
|
|
@ -47,45 +48,61 @@ traverseDeclM decl = do
|
|||
Variable _ (Implicit sg rs) ident a _ ->
|
||||
-- implicit types, which are commonly found in function return
|
||||
-- types, are recast as logics to avoid outputting bare ranges
|
||||
insertElem ident t' >> return decl'
|
||||
insertType ident t' >> return decl'
|
||||
where t' = injectRanges (IntegerVector TLogic sg rs) a
|
||||
Variable d t ident a e -> do
|
||||
let t' = injectRanges t a
|
||||
insertElem ident t'
|
||||
insertType ident t'
|
||||
return $ case t' of
|
||||
UnpackedType t'' a' -> Variable d t'' ident a' e
|
||||
_ -> Variable d t' ident [] e
|
||||
Param _ UnknownType ident String{} ->
|
||||
insertElem ident UnknownType >> return decl'
|
||||
insertType ident UnknownType >> return decl'
|
||||
Param _ UnknownType ident e ->
|
||||
typeof e >>= insertElem ident >> return decl'
|
||||
typeof e >>= insertType ident >> return decl'
|
||||
Param _ (Implicit sg rs) ident _ ->
|
||||
insertElem ident t' >> return decl'
|
||||
insertType ident t' >> return decl'
|
||||
where t' = IntegerVector TLogic sg rs
|
||||
Param _ t ident _ ->
|
||||
insertElem ident t >> return decl'
|
||||
insertType ident t >> return decl'
|
||||
ParamType{} -> return decl'
|
||||
CommentDecl{} -> return decl'
|
||||
|
||||
-- rewrite and store a non-genvar data declaration's type information
|
||||
insertType :: Identifier -> Type -> ST ()
|
||||
insertType ident typ = do
|
||||
typ' <- traverseNestedTypesM (traverseTypeExprsM scopeExpr) typ
|
||||
insertElem ident (typ', False)
|
||||
|
||||
-- rewrite an expression so that any identifiers it contains unambiguously refer
|
||||
-- refer to currently visible declarations so it can be substituted elsewhere
|
||||
scopeExpr :: Expr -> ST Expr
|
||||
scopeExpr expr = do
|
||||
expr' <- traverseSinglyNestedExprsM scopeExpr expr
|
||||
details <- lookupElemM expr'
|
||||
case details of
|
||||
Just (accesses, _, (_, False)) -> return $ accessesToExpr accesses
|
||||
_ -> return expr'
|
||||
|
||||
-- convert TypeOf in a ModuleItem
|
||||
traverseModuleItemM :: ModuleItem -> Scoper Type ModuleItem
|
||||
traverseModuleItemM (Genvar x) = do
|
||||
insertElem x $ IntegerAtom TInteger Unspecified
|
||||
return $ Genvar x
|
||||
traverseModuleItemM :: ModuleItem -> ST ModuleItem
|
||||
traverseModuleItemM (Genvar x) =
|
||||
insertElem x (t, True) >> return (Genvar x)
|
||||
where t = IntegerAtom TInteger Unspecified
|
||||
traverseModuleItemM item =
|
||||
traverseNodesM traverseExprM return traverseTypeM traverseLHSM return item
|
||||
where traverseLHSM = traverseLHSExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in a GenItem
|
||||
traverseGenItemM :: GenItem -> Scoper Type GenItem
|
||||
traverseGenItemM :: GenItem -> ST GenItem
|
||||
traverseGenItemM = traverseGenItemExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in a Stmt
|
||||
traverseStmtM :: Stmt -> Scoper Type Stmt
|
||||
traverseStmtM :: Stmt -> ST Stmt
|
||||
traverseStmtM = traverseStmtExprsM traverseExprM
|
||||
|
||||
-- convert TypeOf in an Expr
|
||||
traverseExprM :: Expr -> Scoper Type Expr
|
||||
traverseExprM :: Expr -> ST Expr
|
||||
traverseExprM (Cast (Left (Implicit sg [])) expr) =
|
||||
-- `signed'(foo)` and `unsigned'(foo)` are syntactic sugar for the `$signed`
|
||||
-- and `$unsigned` system functions present in Verilog-2005
|
||||
|
|
@ -122,7 +139,7 @@ traverseExprM other =
|
|||
>>= traverseSinglyNestedExprsM traverseExprM
|
||||
|
||||
-- carry forward the signedness of the expression when cast to the given size
|
||||
elaborateSizeCast :: Expr -> Expr -> Scoper Type Expr
|
||||
elaborateSizeCast :: Expr -> Expr -> ST Expr
|
||||
elaborateSizeCast size value = do
|
||||
t <- typeof value
|
||||
case typeSignedness t of
|
||||
|
|
@ -130,7 +147,7 @@ elaborateSizeCast size value = do
|
|||
sg -> traverseExprM $ Cast (Left $ typeOfSize sg size) value
|
||||
|
||||
-- convert TypeOf in a Type
|
||||
traverseTypeM :: Type -> Scoper Type Type
|
||||
traverseTypeM :: Type -> ST Type
|
||||
traverseTypeM (TypeOf expr) =
|
||||
traverseExprM expr >>= typeof
|
||||
traverseTypeM other =
|
||||
|
|
@ -139,31 +156,22 @@ traverseTypeM other =
|
|||
|
||||
-- attempts to find the given (potentially hierarchical or generate-scoped)
|
||||
-- expression in the available scope information
|
||||
lookupTypeOf :: Expr -> Scoper Type Type
|
||||
lookupTypeOf :: Expr -> ST Type
|
||||
lookupTypeOf expr = do
|
||||
details <- lookupElemM expr
|
||||
case details of
|
||||
Nothing -> return $ TypeOf expr
|
||||
Just (_, replacements, typ) -> do
|
||||
Just (_, replacements, (typ, _)) -> do
|
||||
let typ' = toVarType typ
|
||||
return $ if Map.null replacements
|
||||
then typ'
|
||||
else rewriteType replacements typ'
|
||||
return $ replaceInType replacements typ'
|
||||
where
|
||||
toVarType :: Type -> Type
|
||||
toVarType (Net _ sg rs) = IntegerVector TLogic sg rs
|
||||
toVarType other = other
|
||||
rewriteType :: Replacements -> Type -> Type
|
||||
rewriteType replacements = traverseNestedTypes $ traverseTypeExprs $
|
||||
traverseNestedExprs (replace replacements)
|
||||
replace :: Replacements -> Expr -> Expr
|
||||
replace replacements (Ident x) =
|
||||
Map.findWithDefault (Ident x) x replacements
|
||||
replace _ other = other
|
||||
|
||||
-- determines the type of an expression based on the available scope information
|
||||
-- according the semantics defined in IEEE 1800-2017, especially Section 11.6
|
||||
typeof :: Expr -> Scoper Type Type
|
||||
typeof :: Expr -> ST Type
|
||||
typeof (Number n) =
|
||||
return $ IntegerVector TLogic sg [r]
|
||||
where
|
||||
|
|
@ -233,7 +241,7 @@ unescapedLength ('\\' : _ : rest) = 1 + unescapedLength rest
|
|||
unescapedLength (_ : rest) = 1 + unescapedLength rest
|
||||
|
||||
-- type of a standard (non-member) function call
|
||||
typeofCall :: String -> Args -> Scoper Type Type
|
||||
typeofCall :: String -> Args -> ST Type
|
||||
typeofCall "$unsigned" (Args [e] []) = return $ typeOfSize Unsigned $ sizeof e
|
||||
typeofCall "$signed" (Args [e] []) = return $ typeOfSize Signed $ sizeof e
|
||||
typeofCall "$clog2" (Args [_] []) =
|
||||
|
|
@ -250,7 +258,7 @@ typeSignednessOverride fallback sg t =
|
|||
_ -> fallback
|
||||
|
||||
-- type of a unary operator expression
|
||||
typeofUniOp :: UniOp -> Expr -> Scoper Type Type
|
||||
typeofUniOp :: UniOp -> Expr -> ST Type
|
||||
typeofUniOp UniAdd e = typeof e
|
||||
typeofUniOp UniSub e = typeof e
|
||||
typeofUniOp BitNot e = typeof e
|
||||
|
|
@ -259,7 +267,7 @@ typeofUniOp _ _ =
|
|||
return UnitType
|
||||
|
||||
-- type of a binary operator expression (Section 11.6.1)
|
||||
typeofBinOp :: BinOp -> Expr -> Expr -> Scoper Type Type
|
||||
typeofBinOp :: BinOp -> Expr -> Expr -> ST Type
|
||||
typeofBinOp op a b =
|
||||
case op of
|
||||
LogAnd -> unitType
|
||||
|
|
@ -293,7 +301,7 @@ typeofBinOp op a b =
|
|||
where unitType = return UnitType
|
||||
|
||||
-- produces a type large enough to hold either expression
|
||||
largerSizeType :: Expr -> Expr -> Scoper Type Type
|
||||
largerSizeType :: Expr -> Expr -> ST Type
|
||||
largerSizeType a (Number (Based 1 _ _ _ _)) = typeof a
|
||||
largerSizeType a b = do
|
||||
t <- typeof a
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ executable sv2v
|
|||
Convert.Foreach
|
||||
Convert.FuncRet
|
||||
Convert.FuncRoutine
|
||||
Convert.HierConst
|
||||
Convert.ImplicitNet
|
||||
Convert.Inside
|
||||
Convert.Interface
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
module top;
|
||||
parameter WIDTH = 1;
|
||||
if (1) begin : a
|
||||
localparam tmp = WIDTH * 2;
|
||||
if (1) begin : c
|
||||
localparam WIDTH = tmp * 3;
|
||||
reg [WIDTH-1:0] x;
|
||||
end
|
||||
end
|
||||
if (1) begin : b
|
||||
localparam tmp = WIDTH * 5;
|
||||
if (1) begin : d
|
||||
localparam WIDTH = tmp * 7;
|
||||
reg [WIDTH-1:0] x;
|
||||
end
|
||||
end
|
||||
reg [$bits(a.c.x):0] a_c_x;
|
||||
reg [$bits(b.d.x):0] b_d_x;
|
||||
if (1) begin : e
|
||||
localparam tmp = WIDTH * 11;
|
||||
if (1) begin : f
|
||||
localparam WIDTH = tmp * 13;
|
||||
reg [WIDTH-1:0] x;
|
||||
reg [$bits(a.c.x):0] a_c_x;
|
||||
reg [$bits(b.d.x):0] b_d_x;
|
||||
initial begin
|
||||
a_c_x = 1;
|
||||
b_d_x = 1;
|
||||
$display("B a.c.x %b", a.c.x);
|
||||
$display("B a_c_x %b", a_c_x);
|
||||
$display("B b.d.x %b", b.d.x);
|
||||
$display("B b_d_x %b", b_d_x);
|
||||
end
|
||||
end
|
||||
end
|
||||
reg [$bits(e.f.x):0] e_f_x;
|
||||
reg [$bits(e.f.a_c_x):0] e_f_a_c_x;
|
||||
reg [$bits(e.f.b_d_x):0] e_f_b_d_x;
|
||||
initial begin
|
||||
e_f_x = 1'sb1;
|
||||
e_f_a_c_x = 1'sbx;
|
||||
e_f_b_d_x = 1'sbz;
|
||||
$display("A a.c.x %b", a.c.x);
|
||||
$display("A a_c_x %b", a_c_x);
|
||||
$display("A b.d.x %b", b.d.x);
|
||||
$display("A b_d_x %b", b_d_x);
|
||||
$display("A e.f.x %b", e.f.x);
|
||||
$display("A e_f_x %b", e_f_x);
|
||||
$display("A e.f.a_c_x %b", e.f.a_c_x);
|
||||
$display("A e_f_a_c_x %b", e_f_a_c_x);
|
||||
$display("A e.f.b_d_x %b", e.f.b_d_x);
|
||||
$display("A e_f_b_d_x %b", e_f_b_d_x);
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
module top;
|
||||
parameter WIDTH = 1;
|
||||
if (1) begin : a
|
||||
if (1) begin : c
|
||||
reg [WIDTH*2*3-1:0] x;
|
||||
end
|
||||
end
|
||||
if (1) begin : b
|
||||
if (1) begin : d
|
||||
reg [WIDTH*5*7-1:0] x;
|
||||
end
|
||||
end
|
||||
reg [WIDTH*2*3:0] a_c_x;
|
||||
reg [WIDTH*5*7:0] b_d_x;
|
||||
if (1) begin : e
|
||||
if (1) begin : f
|
||||
reg [WIDTH*11*13-1:0] x;
|
||||
reg [WIDTH*2*3:0] a_c_x;
|
||||
reg [WIDTH*5*7:0] b_d_x;
|
||||
initial begin
|
||||
a_c_x = 1;
|
||||
b_d_x = 1;
|
||||
$display("B a.c.x %b", a.c.x);
|
||||
$display("B a_c_x %b", a_c_x);
|
||||
$display("B b.d.x %b", b.d.x);
|
||||
$display("B b_d_x %b", b_d_x);
|
||||
end
|
||||
end
|
||||
end
|
||||
reg [WIDTH*11*13:0] e_f_x;
|
||||
reg [WIDTH*2*3+1:0] e_f_a_c_x;
|
||||
reg [WIDTH*5*7+1:0] e_f_b_d_x;
|
||||
initial begin
|
||||
e_f_x = 1'sb1;
|
||||
e_f_a_c_x = 1'sbx;
|
||||
e_f_b_d_x = 1'sbz;
|
||||
$display("A a.c.x %b", a.c.x);
|
||||
$display("A a_c_x %b", a_c_x);
|
||||
$display("A b.d.x %b", b.d.x);
|
||||
$display("A b_d_x %b", b_d_x);
|
||||
$display("A e.f.x %b", e.f.x);
|
||||
$display("A e_f_x %b", e_f_x);
|
||||
$display("A e.f.a_c_x %b", e.f.a_c_x);
|
||||
$display("A e_f_a_c_x %b", e_f_a_c_x);
|
||||
$display("A e.f.b_d_x %b", e.f.b_d_x);
|
||||
$display("A e_f_b_d_x %b", e_f_b_d_x);
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
`define TYPEOF(x) wire [$bits(x) - 1:0]
|
||||
|
||||
// The `REF` sections of this test are workarounds for steveicarus/iverilog#483
|
||||
|
||||
module top;
|
||||
genvar i;
|
||||
if (1) begin : blk
|
||||
for (i = 0; i < 3; i = i + 1) begin : prev
|
||||
localparam V = i * 2;
|
||||
localparam W = V;
|
||||
wire [W:0] x;
|
||||
end
|
||||
for (i = 0; i < 2; i = i + 1) begin : loop
|
||||
`TYPEOF(prev[i+1].x) x;
|
||||
if (1) begin : a
|
||||
localparam j = i - 3;
|
||||
if (1) begin : b
|
||||
localparam i = j + 2;
|
||||
`TYPEOF(prev[i+2].x) x;
|
||||
if (1) begin : c
|
||||
localparam j = i - 4;
|
||||
if (1) begin : d
|
||||
localparam i = j + 7;
|
||||
localparam z = i - 1;
|
||||
`TYPEOF(prev[z].x) x;
|
||||
if (1) begin : e
|
||||
localparam i = 0;
|
||||
`ifdef REF
|
||||
localparam j = 3;
|
||||
`else
|
||||
localparam j = $bits(blk.loop[i].a.b.c.d.x);
|
||||
`endif
|
||||
wire [j-1:0] y;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
`ifdef REF
|
||||
wire [1*2:0] a;
|
||||
wire [2*2:0] b;
|
||||
wire [1*2:0] c;
|
||||
wire [2*2:0] d;
|
||||
wire [1*2:0] e;
|
||||
wire [2*2:0] f;
|
||||
wire [1*2:0] g;
|
||||
wire [1*2:0] h;
|
||||
`else
|
||||
`TYPEOF(blk.loop[0].x) a;
|
||||
`TYPEOF(blk.loop[1].x) b;
|
||||
`TYPEOF(blk.loop[0].a.b.x) c;
|
||||
`TYPEOF(blk.loop[1].a.b.x) d;
|
||||
`TYPEOF(blk.loop[0].a.b.c.d.x) e;
|
||||
`TYPEOF(blk.loop[1].a.b.c.d.x) f;
|
||||
`TYPEOF(blk.loop[0].a.b.c.d.e.y) g;
|
||||
`TYPEOF(blk.loop[1].a.b.c.d.e.y) h;
|
||||
`endif
|
||||
|
||||
`define DUMP(x) assign x = 1; initial $display(`"x: %b (%0d bits)`", x, $bits(x));
|
||||
`DUMP(a) `DUMP(b) `DUMP(c) `DUMP(d) `DUMP(e) `DUMP(f) `DUMP(g) `DUMP(h)
|
||||
`DUMP(blk.loop[0].x)
|
||||
`DUMP(blk.loop[1].x)
|
||||
`DUMP(blk.loop[0].a.b.x)
|
||||
`DUMP(blk.loop[1].a.b.x)
|
||||
`DUMP(blk.loop[0].a.b.c.d.x)
|
||||
`DUMP(blk.loop[1].a.b.c.d.x)
|
||||
`DUMP(blk.loop[0].a.b.c.d.e.y)
|
||||
`DUMP(blk.loop[1].a.b.c.d.e.y)
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
`define REF 1
|
||||
`include "typeof_scope.sv"
|
||||
Loading…
Reference in New Issue