Commit da2d4117 by Zachary Snow

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.
parent 109964bf
......@@ -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
......
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
`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
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
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
// pattern: parameter_list_not_type\.sv:2:31: Parse error: unexpected non-type parameter assignment
module top #(parameter type X = 1); endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment