From 4c3dcf52194c9f327223dba82e5d1c3e354191f2 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Fri, 10 Dec 2021 13:16:34 -0700 Subject: [PATCH] support for enumerated type ranges --- CHANGELOG.md | 1 + src/Language/SystemVerilog/AST/Type.hs | 7 ++-- src/Language/SystemVerilog/Parser/Parse.y | 44 ++++++++++++++++++----- test/core/enum.sv | 35 ++++++++++++++++++ test/core/enum.v | 23 ++++++++++++ test/error/enum_range_neg.sv | 6 ++++ test/error/enum_range_x.sv | 6 ++++ test/error/enum_range_zero.sv | 6 ++++ 8 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 test/error/enum_range_neg.sv create mode 100644 test/error/enum_range_x.sv create mode 100644 test/error/enum_range_zero.sv diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fea307..c1e3bc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * 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] }`) ### Other Enhancements diff --git a/src/Language/SystemVerilog/AST/Type.hs b/src/Language/SystemVerilog/AST/Type.hs index 3c2ecb2..1f423a3 100644 --- a/src/Language/SystemVerilog/AST/Type.hs +++ b/src/Language/SystemVerilog/AST/Type.hs @@ -9,6 +9,7 @@ module Language.SystemVerilog.AST.Type ( Identifier + , EnumItem , Field , Type (..) , Signing (..) @@ -33,7 +34,7 @@ import Language.SystemVerilog.AST.ShowHelp type Identifier = String -type Item = (Identifier, Expr) +type EnumItem = (Identifier, Expr) type Field = (Type, Identifier) data Type @@ -44,7 +45,7 @@ data Type | Alias Identifier [Range] | PSAlias Identifier Identifier [Range] | CSAlias Identifier [ParamBinding] Identifier [Range] - | Enum Type [Item] [Range] + | Enum Type [EnumItem] [Range] | Struct Packing [Field] [Range] | Union Packing [Field] [Range] | InterfaceT Identifier Identifier [Range] @@ -66,7 +67,7 @@ instance Show Type where show (Enum t vals r) = printf "enum %s{%s}%s" tStr (commas $ map showVal vals) (showRanges r) where tStr = showPad t - showVal :: (Identifier, Expr) -> String + showVal :: EnumItem -> String showVal (x, e) = x ++ (showAssignment e) show (Struct p items r) = printf "struct %s{\n%s\n}%s" (showPad p) (showFields items) (showRanges r) show (Union p items r) = printf "union %s{\n%s\n}%s" (showPad p) (showFields items) (showRanges r) diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index ee42ba1..a755144 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -519,8 +519,17 @@ NonIntegerTypeP :: { (Position, NonIntegerType) } | "string" { withPos $1 TString } | "event" { withPos $1 TEvent } -EnumItems :: { [(Identifier, Expr)] } - : VariablePortIdentifiers { $1 } +EnumItems :: { [EnumItem] } + : EnumItem { $1 } + | EnumItem "," EnumItems { $1 ++ $3 } +EnumItem :: { [EnumItem] } + : Identifier OptAsgn { [($1, $2)] } + | IdentifierP IntegralDimension OptAsgn {% makeEnumItems $1 $2 $3 } +IntegralDimension :: { (Integer, Integer) } + : "[" IntegralNumber "]" { ( 0, $2 - 1) } + | "[" IntegralNumber ":" IntegralNumber "]" { ($2, $4) } +IntegralNumber :: { Integer } + : number {% readIntegralNumber (tokenPosition $1) (tokenString $1) } StructItems :: { [(Type, Identifier)] } : StructItem { $1 } @@ -672,12 +681,6 @@ ParamDeclToken :: { [DeclToken] } | "type" IdentifierP { [DTTypeDecl (tokenPosition $1), uncurry DTIdent $2] } | ParameterDeclKW { [uncurry DTParamKW $1] } -VariablePortIdentifiers :: { [(Identifier, Expr)] } - : VariablePortIdentifier { [$1] } - | VariablePortIdentifiers "," VariablePortIdentifier { $1 ++ [$3] } -VariablePortIdentifier :: { (Identifier, Expr) } - : Identifier OptAsgn { ($1,$2) } - Direction :: { Direction } : DirectionP { snd $1 } DirectionP :: { (Position, Direction) } @@ -1714,4 +1717,29 @@ expectZeroDelay tok a = do _ -> parseError pos $ "expected 0 after #, but found " ++ str where Token { tokenString = str, tokenPosition = pos } = tok +readIntegralNumber :: Position -> String -> ParseState Integer +readIntegralNumber pos str = do + num <- readNumber pos str + case numberToInteger num of + Nothing -> + parseError pos $ "expected an integral number, but found " ++ str + Just integer | integer < 0 -> + parseError pos $ "expected a non-negative number, but found " ++ str + Just integer -> + return integer + +makeEnumItems :: (Position, Identifier) -> (Integer, Integer) -> Expr + -> ParseState [EnumItem] +makeEnumItems (pos, _) (0, -1) _ = + parseError pos "expected a positive number, but found zero" +makeEnumItems (_, root) (l, r) base = + return $ (name, base) : map (, Nil) names + where + name : names = + map (root ++) $ + map show $ + if l >= r + then reverse [r..l] + else [l..r] + } diff --git a/test/core/enum.sv b/test/core/enum.sv index d7c4c52..ae851b4 100644 --- a/test/core/enum.sv +++ b/test/core/enum.sv @@ -43,6 +43,18 @@ typedef enum int { Z_1, Z_2, Z_3 } EnumZ; +typedef enum int { + K_A, + K_B = 10, + K_C[3], + K_D[3] = 20, + K_E[4:6], + K_F[4:6] = 30, + K_G[6:4], + K_H[6:4] = 40, + K_I[3:3] = 50 +} EnumK; + `define PRINT(name, val) \ dummy``name = name``_``val; \ $display(`"name %h %h %0d %0d`", \ @@ -58,6 +70,7 @@ module top; EnumG dummyG; EnumH dummyH; EnumI dummyI; + EnumK dummyK; initial begin @@ -96,6 +109,28 @@ module top; `PRINT(I, 1) `PRINT(I, 2) + `PRINT(K, A) + `PRINT(K, B) + `PRINT(K, C0) + `PRINT(K, C1) + `PRINT(K, C2) + `PRINT(K, D0) + `PRINT(K, D1) + `PRINT(K, D2) + `PRINT(K, E4) + `PRINT(K, E5) + `PRINT(K, E6) + `PRINT(K, F4) + `PRINT(K, F5) + `PRINT(K, F6) + `PRINT(K, G6) + `PRINT(K, G5) + `PRINT(K, G4) + `PRINT(K, H6) + `PRINT(K, H5) + `PRINT(K, H4) + `PRINT(K, I3) + end parameter USE_J = 1; diff --git a/test/core/enum.v b/test/core/enum.v index b53d314..3aee5dc 100644 --- a/test/core/enum.v +++ b/test/core/enum.v @@ -14,6 +14,7 @@ module top; reg [0:0] dummyG; reg [3:0] dummyH; reg [31:0] dummyI; + reg [31:0] dummyK; initial begin @@ -52,6 +53,28 @@ module top; `PRINT(I, 'b0) `PRINT(I, 'b1) + `PRINT(K, 0) + `PRINT(K, 10) + `PRINT(K, 11) + `PRINT(K, 12) + `PRINT(K, 13) + `PRINT(K, 20) + `PRINT(K, 21) + `PRINT(K, 22) + `PRINT(K, 23) + `PRINT(K, 24) + `PRINT(K, 25) + `PRINT(K, 30) + `PRINT(K, 31) + `PRINT(K, 32) + `PRINT(K, 33) + `PRINT(K, 34) + `PRINT(K, 35) + `PRINT(K, 40) + `PRINT(K, 41) + `PRINT(K, 42) + `PRINT(K, 50) + end parameter USE_J = 1; diff --git a/test/error/enum_range_neg.sv b/test/error/enum_range_neg.sv new file mode 100644 index 0000000..ca947ae --- /dev/null +++ b/test/error/enum_range_neg.sv @@ -0,0 +1,6 @@ +// pattern: expected a non-negative number, but found 1'sd1 +module top; + enum { + A[1'sd1] + } x; +endmodule diff --git a/test/error/enum_range_x.sv b/test/error/enum_range_x.sv new file mode 100644 index 0000000..c7bf977 --- /dev/null +++ b/test/error/enum_range_x.sv @@ -0,0 +1,6 @@ +// pattern: expected an integral number, but found 'x +module top; + enum { + A['x] + } x; +endmodule diff --git a/test/error/enum_range_zero.sv b/test/error/enum_range_zero.sv new file mode 100644 index 0000000..c0f548f --- /dev/null +++ b/test/error/enum_range_zero.sv @@ -0,0 +1,6 @@ +// pattern: expected a positive number, but found zero +module top; + enum { + A[0] + } x; +endmodule