sv: improve support for wire and var with user-defined types
authorBrett Witherspoon <brett@witherspoondesign.com>
Tue, 22 Jun 2021 14:51:41 +0000 (09:51 -0500)
committerZachary Snow <zachary.j.snow@gmail.com>
Fri, 13 Aug 2021 04:41:41 +0000 (22:41 -0600)
- User-defined types must be data types. Using a net type (e.g. wire) is
  a syntax error.
- User-defined types without a net type are always variables (i.e.
  logic).
- Nets and variables can now be explicitly declared using user-defined
  types:

    typedef logic [1:0] W;
    wire W w;

    typedef logic [1:0] V;
    var V v;

Fixes #2846

frontends/verilog/verilog_parser.y
tests/svtypes/typedef_initial_and_assign.sv [new file with mode: 0644]
tests/svtypes/typedef_initial_and_assign.ys [new file with mode: 0644]

index a5227cb092cac7d67a7133473b9610cba2b10a82..b0c16c0f44ff9ea994ce8bd22a0c28f40c07b6a9 100644 (file)
@@ -127,6 +127,15 @@ struct specify_rise_fall {
        specify_triple fall;
 };
 
+static void addWiretypeNode(std::string *name, AstNode *node)
+{
+       log_assert(node);
+       node->is_custom_type = true;
+       node->children.push_back(new AstNode(AST_WIRETYPE));
+       node->children.back()->str = *name;
+       delete name;
+}
+
 static void addTypedefNode(std::string *name, AstNode *node)
 {
        log_assert(node);
@@ -305,10 +314,10 @@ static void checkLabelsMatch(const char *element, const std::string *before, con
 %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type
 %type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number
 %type <string> type_name
-%type <ast> opt_enum_init enum_type struct_type non_wire_data_type func_return_type
+%type <ast> opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type
 %type <boolean> opt_property always_comb_or_latch always_or_always_ff
 %type <boolean> opt_signedness_default_signed opt_signedness_default_unsigned
-%type <integer> integer_atom_type
+%type <integer> integer_atom_type integer_vector_type
 %type <al> attr case_attr
 %type <ast> struct_union
 %type <ast_node_type> asgn_binop
@@ -763,12 +772,6 @@ opt_wire_type_token:
        wire_type_token | %empty;
 
 wire_type_token:
-       hierarchical_type_id {
-               astbuf3->is_custom_type = true;
-               astbuf3->children.push_back(new AstNode(AST_WIRETYPE));
-               astbuf3->children.back()->str = *$1;
-               delete $1;
-       } |
        TOK_WOR {
                astbuf3->is_wor = true;
        } |
@@ -812,6 +815,9 @@ logic_type:
                astbuf3->range_left = $1 - 1;
                astbuf3->range_right = 0;
                astbuf3->is_signed = true;
+       } |
+       hierarchical_type_id {
+               addWiretypeNode($1, astbuf3);
        };
 
 integer_atom_type:
@@ -821,6 +827,10 @@ integer_atom_type:
        TOK_LONGINT     { $$ = 64; } |
        TOK_BYTE        { $$ =  8; } ;
 
+integer_vector_type:
+       TOK_LOGIC { $$ = TOK_LOGIC; } |
+       TOK_REG   { $$ = TOK_REG; } ;
+
 non_opt_range:
        '[' expr ':' expr ']' {
                $$ = new AstNode(AST_RANGE);
@@ -1985,7 +1995,7 @@ type_name: TOK_ID         // first time seen
         ;
 
 typedef_decl:
-       TOK_TYPEDEF non_io_wire_type range type_name range_or_multirange ';' {
+       TOK_TYPEDEF typedef_base_type range type_name range_or_multirange ';' {
                astbuf1 = $2;
                astbuf2 = checkRange(astbuf1, $3);
                if (astbuf2)
@@ -1998,10 +2008,33 @@ typedef_decl:
                        rewriteAsMemoryNode(astbuf1, $5);
                }
                addTypedefNode($4, astbuf1); }
-       | TOK_TYPEDEF non_wire_data_type type_name ';'   { addTypedefNode($3, $2); }
+       | TOK_TYPEDEF enum_struct_type type_name ';'   { addTypedefNode($3, $2); }
        ;
 
-non_wire_data_type:
+typedef_base_type:
+       hierarchical_type_id {
+               $$ = new AstNode(AST_WIRE);
+               $$->is_logic = true;
+               addWiretypeNode($1, $$);
+       } |
+       integer_vector_type opt_signedness_default_unsigned {
+               $$ = new AstNode(AST_WIRE);
+               if ($1 == TOK_REG) {
+                       $$->is_reg = true;
+               } else {
+                       $$->is_logic = true;
+               }
+               $$->is_signed = $2;
+       } |
+       integer_atom_type opt_signedness_default_signed {
+               $$ = new AstNode(AST_WIRE);
+               $$->is_logic = true;
+               $$->is_signed = $2;
+               $$->range_left = $1 - 1;
+               $$->range_right = 0;
+       };
+
+enum_struct_type:
          enum_type
        | struct_type
        ;
diff --git a/tests/svtypes/typedef_initial_and_assign.sv b/tests/svtypes/typedef_initial_and_assign.sv
new file mode 100644 (file)
index 0000000..0557994
--- /dev/null
@@ -0,0 +1,94 @@
+package pkg;
+       typedef logic pkg_user_t;
+endpackage
+
+module top;
+       typedef logic user_t;
+
+       // Continuous assignment to a variable is legal
+       user_t var_1;
+       assign var_1 = 0;
+       assert property (var_1 == 0);
+
+       var user_t var_2;
+       assign var_2 = 0;
+       assert property (var_2 == 0);
+
+       var pkg::pkg_user_t var_3;
+       assign var_3 = 0;
+       assert property (var_3 == 0);
+
+       // Procedural assignment to a variable is legal
+       user_t var_4 = 0;
+       assert property (var_4 == 0);
+
+       user_t var_5;
+       initial var_5 = 0;
+       assert property (var_5 == 0);
+
+       var user_t var_6 = 0;
+       assert property (var_6 == 0);
+
+       var user_t var_7;
+       initial var_7 = 0;
+       assert property (var_7 == 0);
+
+       pkg::pkg_user_t var_8 = 0;
+       assert property (var_8 == 0);
+
+       pkg::pkg_user_t var_9;
+       initial var_9 = 0;
+       assert property (var_9 == 0);
+
+       var pkg::pkg_user_t var_10 = 0;
+       assert property (var_10 == 0);
+
+       var pkg::pkg_user_t var_11;
+       initial var_11 = 0;
+       assert property (var_11 == 0);
+
+       // Continuous assignment to a net is legal
+       wire user_t wire_1 = 0;
+       assert property (wire_3 == 0);
+
+       wire user_t wire_2;
+       assign wire_2 = 0;
+       assert property (wire_2 == 0);
+
+       wire pkg::pkg_user_t wire_3 = 0;
+       assert property (wire_3 == 0);
+
+       wire pkg::pkg_user_t wire_4;
+       assign wire_4 = 0;
+       assert property (wire_4 == 0);
+
+       // Mixing continuous and procedural assignments is illegal
+       user_t var_12 = 0;
+       assign var_12 = 1; // warning: reg assigned in a continuous assignment
+
+       user_t var_13;
+       initial var_13 = 0;
+       assign var_13 = 1; // warning: reg assigned in a continuous assignment
+
+       var user_t var_14 = 0;
+       assign var_14 = 1; // warning: reg assigned in a continuous assignment
+
+       var user_t var_15;
+       initial var_15 = 0;
+       assign var_15 = 1; // warning: reg assigned in a continuous assignment
+
+       pkg::pkg_user_t var_16 = 0;
+       assign var_16 = 1; // warning: reg assigned in a continuous assignment
+
+       pkg::pkg_user_t var_17;
+       initial var_17 = 0;
+       assign var_17 = 1; // warning: reg assigned in a continuous assignment
+
+       var pkg::pkg_user_t var_18 = 0;
+       assign var_18 = 1; // warning: reg assigned in a continuous assignment
+
+       var pkg::pkg_user_t var_19;
+       initial var_19 = 0;
+       assign var_19 = 1; // warning: reg assigned in a continuous assignment
+
+endmodule
diff --git a/tests/svtypes/typedef_initial_and_assign.ys b/tests/svtypes/typedef_initial_and_assign.ys
new file mode 100644 (file)
index 0000000..de456bb
--- /dev/null
@@ -0,0 +1,14 @@
+logger -expect-no-warnings
+logger -expect warning "reg '\\var_12' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_13' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_14' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_15' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_16' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_17' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_18' is assigned in a continuous assignment" 1
+logger -expect warning "reg '\\var_19' is assigned in a continuous assignment" 1
+
+read_verilog -sv typedef_initial_and_assign.sv
+hierarchy; proc; opt
+select -module top
+sat -verify -seq 1 -tempinduct -prove-asserts -show-all
\ No newline at end of file