mirror of https://github.com/zachjs/sv2v.git
specialized parsing for parameter port lists
This adds support for typed valued parameters declared in parameter port lists without explicitly providing a leading `parameter` or `localparam` marker.
This commit is contained in:
parent
109964bfc3
commit
da2d4117f2
|
|
@ -20,6 +20,8 @@
|
|||
* Fix parsing of sized ports with implicit directions
|
||||
* Ensure arrays used in nested ternary expressions are properly flattened
|
||||
* Support parameters which use a type-of as the data type
|
||||
* Support typed valued parameters declared in parameter port lists without
|
||||
explicitly providing a leading `parameter` or `localparam` marker
|
||||
|
||||
## v0.0.8
|
||||
|
||||
|
|
|
|||
|
|
@ -570,21 +570,9 @@ PackageImportDeclaration :: { [ModuleItem] }
|
|||
Params :: { [ModuleItem] }
|
||||
: PIParams { map (MIPackageItem . Decl) $1 }
|
||||
PIParams :: { [Decl] }
|
||||
: {- empty -} { [] }
|
||||
| "#" "(" ")" { [] }
|
||||
| "#" "(" ParamsFollow { $3 }
|
||||
ParamsFollow :: { [Decl] }
|
||||
: ParamAsgn ParamsEnd { $1 }
|
||||
| ParamAsgn "," ParamsFollow { $1 ++ $3 }
|
||||
| ParamsDecl { $1 }
|
||||
ParamsDecl :: { [Decl] }
|
||||
: ModuleParameterDecl(ParamsEnd) { $1 }
|
||||
| ModuleParameterDecl(",") ParamsDecl { $1 ++ $2 }
|
||||
ParamAsgn :: { [Decl] }
|
||||
: DeclTrace Identifier "=" Expr { [$1, Param Parameter (Implicit Unspecified []) $2 $4] }
|
||||
ParamsEnd
|
||||
: ")" {}
|
||||
| "," ")" {}
|
||||
: {- empty -} { [] }
|
||||
| "#" "(" ")" { [] }
|
||||
| "#" "(" ParamDeclTokens(")") { parseDTsAsParams $3 }
|
||||
|
||||
PortDecls :: { ([Identifier], [ModuleItem]) }
|
||||
: "(" PortDeclTokens(")") { parseDTsAsPortDecls $2 }
|
||||
|
|
@ -658,8 +646,9 @@ DeclToken :: { DeclToken }
|
|||
DTDelim(delim) :: { DeclToken }
|
||||
: delim { DTEnd (tokenPosition $1) (head $ tokenString $1) }
|
||||
DeclTokenAsgn :: { DeclToken }
|
||||
: "=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpEq $2 $3 }
|
||||
| AsgnBinOpP Expr { uncurry DTAsgn $1 Nothing $2 }
|
||||
: "=" DelayOrEvent Expr { DTAsgn (tokenPosition $1) AsgnOpEq (Just $2) $3 }
|
||||
| "=" Expr { DTAsgn (tokenPosition $1) AsgnOpEq Nothing $2 }
|
||||
| AsgnBinOpP Expr { uncurry DTAsgn $1 Nothing $2 }
|
||||
| "<=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpNonBlocking $2 $3 }
|
||||
PortDeclTokens(delim) :: { [DeclToken] }
|
||||
: DeclTokensBase(PortDeclTokens(delim), delim) { $1 }
|
||||
|
|
@ -673,6 +662,16 @@ ModuleDeclTokens(delim) :: { [DeclToken] }
|
|||
GenericInterfaceDecl :: { [DeclToken] }
|
||||
: "interface" IdentifierP { [DTType (tokenPosition $1) (\Unspecified -> InterfaceT "" ""), uncurry DTIdent $2] }
|
||||
|
||||
ParamDeclTokens(delim) :: { [DeclToken] }
|
||||
: DeclTokensBase(ParamDeclTokens(delim), delim) { $1 }
|
||||
| DeclTokenAsgn "," DTDelim(delim) { [$1, DTComma (tokenPosition $2), $3] }
|
||||
| ParamDeclToken ParamDeclTokens(delim) { $1 ++ $2 }
|
||||
| ParamDeclToken DTDelim(delim) { $1 ++ [$2] }
|
||||
ParamDeclToken :: { [DeclToken] }
|
||||
: "=" PartialTypeP { [DTTypeAsgn (tokenPosition $1), uncurry DTType $2] }
|
||||
| "type" IdentifierP { [DTTypeDecl (tokenPosition $1), uncurry DTIdent $2] }
|
||||
| ParameterDeclKW { [uncurry DTParamKW $1] }
|
||||
|
||||
VariablePortIdentifiers :: { [(Identifier, Expr)] }
|
||||
: VariablePortIdentifier { [$1] }
|
||||
| VariablePortIdentifiers "," VariablePortIdentifier { $1 ++ [$3] }
|
||||
|
|
@ -1130,9 +1129,6 @@ DeclOrStmt :: { ([Decl], [Stmt]) }
|
|||
: DeclTokens(";") { parseDTsAsDeclOrStmt $1 }
|
||||
| ParameterDecl(";") { ($1, []) }
|
||||
|
||||
ModuleParameterDecl(delim) :: { [Decl] }
|
||||
: ParameterDecl(delim) { $1 }
|
||||
| DeclTrace "type" TypeAsgns delim { $1 : map (uncurry $ ParamType Parameter) $3 }
|
||||
ParameterDecl(delim) :: { [Decl] }
|
||||
: ParameterDeclKW DeclAsgns delim { makeParamDecls $1 (Implicit Unspecified []) $2 }
|
||||
| ParameterDeclKW ParamType DeclAsgns delim { makeParamDecls $1 $2 $3 }
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@
|
|||
- portion of a for loop also allows for declarations and assignments, and so a
|
||||
- similar interface is provided for this case.
|
||||
-
|
||||
- Parameter port lists allow the omission of the `parameter` and `localparam`
|
||||
- keywords, and so require special handling in the same vein as other
|
||||
- declarations. However, this custom parsing is not necessary for parameter
|
||||
- declarations outside of parameter port lists because the leading keyword is
|
||||
- otherwise required.
|
||||
-
|
||||
- This parser is very liberal, and so accepts some syntactically invalid files.
|
||||
- In the future, we may add some basic type-checking to complain about
|
||||
- malformed input files. However, we generally assume that users have tested
|
||||
|
|
@ -43,6 +49,7 @@ module Language.SystemVerilog.Parser.ParseDecl
|
|||
, parseDTsAsDecl
|
||||
, parseDTsAsDeclOrStmt
|
||||
, parseDTsAsDeclsOrAsgns
|
||||
, parseDTsAsParams
|
||||
) where
|
||||
|
||||
import Data.List (findIndex, partition, uncons)
|
||||
|
|
@ -73,17 +80,22 @@ data DeclToken
|
|||
| DTLifetime Position Lifetime
|
||||
| DTAttr Position Attr
|
||||
| DTEnd Position Char
|
||||
| DTParamKW Position ParamScope
|
||||
| DTTypeDecl Position
|
||||
| DTTypeAsgn Position
|
||||
|
||||
|
||||
-- [PUBLIC]: parser for module port declarations, including interface ports
|
||||
-- Example: `input foo, bar, One inst`
|
||||
parseDTsAsPortDecls :: [DeclToken] -> ([Identifier], [ModuleItem])
|
||||
parseDTsAsPortDecls = parseDTsAsPortDecls' . dropTrailingComma
|
||||
where
|
||||
dropTrailingComma :: [DeclToken] -> [DeclToken]
|
||||
dropTrailingComma [] = []
|
||||
dropTrailingComma [DTComma{}, end@DTEnd{}] = [end]
|
||||
dropTrailingComma (tok : toks) = tok : dropTrailingComma toks
|
||||
|
||||
-- internal utility to drop a single trailing comma in port or parameter lists,
|
||||
-- which we allow for compatibility with Yosys
|
||||
dropTrailingComma :: [DeclToken] -> [DeclToken]
|
||||
dropTrailingComma [] = []
|
||||
dropTrailingComma [DTComma{}, end@DTEnd{}] = [end]
|
||||
dropTrailingComma (tok : toks) = tok : dropTrailingComma toks
|
||||
|
||||
-- internal parseDTsAsPortDecls after the removal of an optional trailing comma
|
||||
parseDTsAsPortDecls' :: [DeclToken] -> ([Identifier], [ModuleItem])
|
||||
|
|
@ -333,7 +345,6 @@ takeLHSStep curr (DTRange _ m r : toks) = takeLHSStep (LHSRange curr m r) toks
|
|||
takeLHSStep curr (DTDot _ x : toks) = takeLHSStep (LHSDot curr x ) toks
|
||||
takeLHSStep lhs toks = (lhs, toks)
|
||||
|
||||
|
||||
type DeclBase = Identifier -> [Range] -> Expr -> Decl
|
||||
type Triplet = (Identifier, [Range], Expr)
|
||||
|
||||
|
|
@ -369,15 +380,17 @@ parseDTsAsDecls backupDir mode l0 =
|
|||
(tf , l5) = takeType l4
|
||||
(rs , l6) = takeRanges l5
|
||||
(tps, l7) = takeTrips l6 initReason
|
||||
pos = tokPos $ head l0
|
||||
base = von dir t
|
||||
t = case (dir, tf rs) of
|
||||
(Output, Implicit sg _) -> IntegerVector TLogic sg rs
|
||||
(_, typ) -> typ
|
||||
decls =
|
||||
CommentDecl ("Trace: " ++ show pos) :
|
||||
traceComment l0 :
|
||||
map (\(x, a, e) -> base x a e) tps
|
||||
|
||||
traceComment :: [DeclToken] -> Decl
|
||||
traceComment = CommentDecl . ("Trace: " ++) . show . tokPos . head
|
||||
|
||||
hasDriveStrength :: DeclToken -> Bool
|
||||
hasDriveStrength (DTNet _ _ DriveStrength{}) = True
|
||||
hasDriveStrength _ = False
|
||||
|
|
@ -413,6 +426,85 @@ tripLookahead l0 =
|
|||
(_, l2) = takeRanges l1
|
||||
(_, l3) = takeAsgn l2 ""
|
||||
|
||||
|
||||
-- [PUBLIC]: parser for parameter lists in headers of modules, interfaces, etc.
|
||||
parseDTsAsParams :: [DeclToken] -> [Decl]
|
||||
parseDTsAsParams = parseDTsAsParams' Parameter . dropTrailingComma
|
||||
|
||||
-- internal variant of the above, used recursively after the optional trailing
|
||||
-- comma has been removed
|
||||
parseDTsAsParams' :: ParamScope -> [DeclToken] -> [Decl]
|
||||
parseDTsAsParams' _ [] = []
|
||||
parseDTsAsParams' prevParamScope l0 =
|
||||
nextStep paramScope l2
|
||||
where
|
||||
nextStep = if isParamType
|
||||
then parseDTsAsParamType
|
||||
else parseDTsAsParam
|
||||
(paramScope , l1) = takeParamScope l0 prevParamScope
|
||||
(isParamType, l2) = takeParamType l1
|
||||
|
||||
-- parse one or more regular parameter declarations at the beginning of the decl
|
||||
-- token list before continuing on to subsequent declarations
|
||||
parseDTsAsParam :: ParamScope -> [DeclToken] -> [Decl]
|
||||
parseDTsAsParam paramScope l0 =
|
||||
traceComment l0 :
|
||||
map base tps ++
|
||||
parseDTsAsParams' paramScope l3
|
||||
where
|
||||
(tfO, l1) = takeType l0
|
||||
(rsO, l2) = takeRanges l1
|
||||
(tps, l3) = takeTrips l2 ""
|
||||
base :: Triplet -> Decl
|
||||
(tf, rs) = typeRanges $ tfO rsO -- for packing tolerance
|
||||
base (x, a, e) = Param paramScope (tf $ a ++ rs) x e
|
||||
|
||||
-- parse a single type parameter declaration at the beginning of the decl token
|
||||
-- list before continuing on to subsequent declarations
|
||||
parseDTsAsParamType :: ParamScope -> [DeclToken] -> [Decl]
|
||||
parseDTsAsParamType paramScope l0 =
|
||||
traceComment l0 :
|
||||
ParamType paramScope x t :
|
||||
nextStep paramScope l3
|
||||
where
|
||||
nextStep = if typeAsgnLookahead l3
|
||||
then parseDTsAsParamType
|
||||
else parseDTsAsParams'
|
||||
(x, l1) = takeIdent l0
|
||||
(t, l2) = takeTypeAsgn l1
|
||||
l3 = takeCommaOrEnd l2
|
||||
|
||||
-- take the optional default value assignment for a type parameter declaration;
|
||||
-- note that aliases are parsed as regular assignments to avoid conflicts, and
|
||||
-- so are converted to types when encountered
|
||||
takeTypeAsgn :: [DeclToken] -> (Type, [DeclToken])
|
||||
takeTypeAsgn (DTTypeAsgn _ : l0) =
|
||||
(tf rs, l2)
|
||||
where
|
||||
(tf, l1) = takeType l0
|
||||
(rs, l2) = takeRanges l1
|
||||
takeTypeAsgn (DTAsgn pos AsgnOpEq Nothing expr : toks) =
|
||||
case exprToType expr of
|
||||
Nothing -> parseError pos "unexpected non-type parameter assignment"
|
||||
Just t -> (t, toks)
|
||||
takeTypeAsgn toks = (UnknownType, toks)
|
||||
|
||||
-- check whether the front of the tokens could plausibly form a type parameter
|
||||
-- declaration and optional assignment; type parameter declaration assignments
|
||||
-- can only be "escaped" using an explicit non-type parameter/localparam keyword
|
||||
typeAsgnLookahead :: [DeclToken] -> Bool
|
||||
typeAsgnLookahead l0 =
|
||||
not (null l0) &&
|
||||
-- every type assignment *must* begin with an identifier
|
||||
isIdent (head l0) &&
|
||||
-- expecting to see a comma or the ending token after the identifier and
|
||||
-- optional assignment
|
||||
isCommaOrEnd (head l2)
|
||||
where
|
||||
(_, l1) = takeIdent l0
|
||||
(_, l2) = takeTypeAsgn l1
|
||||
|
||||
|
||||
takeDir :: [DeclToken] -> Direction -> (Direction, [DeclToken])
|
||||
takeDir (DTDir _ dir : rest) _ = (dir, rest)
|
||||
takeDir rest dir = (dir, rest)
|
||||
|
|
@ -523,6 +615,15 @@ takeIdent (DTIdent _ x : rest) = (x, rest)
|
|||
takeIdent tokens = parseError (head tokens) "expected identifier"
|
||||
|
||||
|
||||
takeParamScope :: [DeclToken] -> ParamScope -> (ParamScope, [DeclToken])
|
||||
takeParamScope (DTParamKW _ psc : toks) _ = (psc, toks)
|
||||
takeParamScope toks psc = (psc, toks)
|
||||
|
||||
takeParamType :: [DeclToken] -> (Bool, [DeclToken])
|
||||
takeParamType (DTTypeDecl _ : toks) = (True , toks)
|
||||
takeParamType toks = (False, toks)
|
||||
|
||||
|
||||
isAttr :: DeclToken -> Bool
|
||||
isAttr DTAttr{} = True
|
||||
isAttr _ = False
|
||||
|
|
@ -573,6 +674,9 @@ tokPos (DTSigning p _) = p
|
|||
tokPos (DTLifetime p _) = p
|
||||
tokPos (DTAttr p _) = p
|
||||
tokPos (DTEnd p _) = p
|
||||
tokPos (DTParamKW p _) = p
|
||||
tokPos (DTTypeDecl p) = p
|
||||
tokPos (DTTypeAsgn p) = p
|
||||
|
||||
class Loc t where
|
||||
parseError :: t -> String -> a
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
typedef integer integer_t;
|
||||
typedef shortint shortint_t;
|
||||
typedef byte byte_t;
|
||||
|
||||
localparam value_a = 1;
|
||||
localparam value_b = 2;
|
||||
localparam value_c = 3;
|
||||
|
||||
`define DUMP_V(X) initial $display(`"V: X %b %0d %0d`", X, X, $bits(X));
|
||||
`define DUMP_T(X) initial begin : \dump``X \
|
||||
localparam X x = '1; \
|
||||
$display(`"T: X %0d %b`", $bits(X), x); \
|
||||
end
|
||||
|
||||
module mod #(
|
||||
localparam integer_t LV1 = value_a, LV2 = value_b,
|
||||
parameter type PT1 = logic,
|
||||
integer PV1 = 100,
|
||||
parameter type(PV1) PV2 = PV1 + value_c,
|
||||
parameter type PT2 = byte_t,
|
||||
shortint_t PV3 = 4,
|
||||
localparam LV3 = 5,
|
||||
type LT1 = byte_t, LT2 = shortint_t
|
||||
);
|
||||
`DUMP_V(LV1) `DUMP_V(LV2) `DUMP_V(LV3)
|
||||
`DUMP_T(LT1) `DUMP_T(LT2)
|
||||
`DUMP_V(PV1) `DUMP_V(PV2) `DUMP_V(PV3)
|
||||
`DUMP_T(PT1) `DUMP_T(PT2)
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
mod m1();
|
||||
mod #(byte, 7, 10, logic [3:0], 5) m2();
|
||||
mod #(reg [8:0], 8, 11, integer, 6) m3();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
`define DUMP_V(X) initial $display(`"V: X %b %0d %0d`", X, X, $bits(X));
|
||||
`define DUMP_T(X) initial begin : \dump``X \
|
||||
localparam [X - 1:0] x = 1'sb1; \
|
||||
$display(`"T: X %0d %b`", X, x); \
|
||||
end
|
||||
|
||||
module mod;
|
||||
localparam integer LV1 = 1, LV2 = 2;
|
||||
parameter PT1 = 1;
|
||||
parameter integer PV1 = 100;
|
||||
parameter integer PV2 = PV1 + 3;
|
||||
parameter PT2 = 8;
|
||||
parameter [15:0] PV3 = 4;
|
||||
localparam LV3 = 5;
|
||||
localparam LT1 = 8, LT2 = 16;
|
||||
`DUMP_V(LV1) `DUMP_V(LV2) `DUMP_V(LV3)
|
||||
`DUMP_T(LT1) `DUMP_T(LT2)
|
||||
`DUMP_V(PV1) `DUMP_V(PV2) `DUMP_V(PV3)
|
||||
`DUMP_T(PT1) `DUMP_T(PT2)
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
mod m1();
|
||||
mod #(8, 7, 10, 4, 5) m2();
|
||||
mod #(9, 8, 11, 32, 6) m3();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
module fibA #(
|
||||
parameter integer N = 1,
|
||||
parameter integer W [2] = '{ 0, 1 }
|
||||
);
|
||||
initial $display("fibA(%0d) = %0d", N, W[0]);
|
||||
if (N < 11)
|
||||
fibA #(N + 1, '{ W[1], W[0] + W[1] }) f();
|
||||
endmodule
|
||||
module fibB;
|
||||
parameter integer N = 1;
|
||||
parameter integer W [2] = '{ 0, 1 };
|
||||
initial $display("fibB(%0d) = %0d", N, W[0]);
|
||||
if (N < 11)
|
||||
fibB #(N + 1, '{ W[1], W[0] + W[1] }) f();
|
||||
endmodule
|
||||
module top;
|
||||
fibA fA();
|
||||
fibB fB();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
module fib #(
|
||||
parameter VARIANT = "",
|
||||
parameter N = 1,
|
||||
parameter W0 = 0,
|
||||
parameter W1 = 1
|
||||
);
|
||||
initial $display("fib%s(%0d) = %0d", VARIANT, N, W0);
|
||||
if (N < 11)
|
||||
fib #(VARIANT, N + 1, W1, W0 + W1) f();
|
||||
endmodule
|
||||
module top;
|
||||
fib #("A") fA();
|
||||
fib #("B") fB();
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// pattern: parameter_list_not_type\.sv:2:31: Parse error: unexpected non-type parameter assignment
|
||||
module top #(parameter type X = 1); endmodule
|
||||
Loading…
Reference in New Issue