diff --git a/ivtest/ivltests/sv_net_array_decl_assign.v b/ivtest/ivltests/sv_net_array_decl_assign.v new file mode 100644 index 000000000..48658d317 --- /dev/null +++ b/ivtest/ivltests/sv_net_array_decl_assign.v @@ -0,0 +1,27 @@ +// Check that net arrays can be initialized during declaration. + +module test; + + reg failed; + + wire [3:0] a[0:1] = '{4'h1, 4'h2}; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(a[0], 4'h1) + `check(a[1], 4'h2) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_net_decl_assign.v b/ivtest/ivltests/sv_net_decl_assign.v new file mode 100644 index 000000000..31ec9b22b --- /dev/null +++ b/ivtest/ivltests/sv_net_decl_assign.v @@ -0,0 +1,33 @@ +// Check that net declarations can mix initialized and uninitialized entries. + +module test; + + reg failed; + + wire [3:0] a, b = 4'h5; + wire [3:0] c = 4'ha, d; + + assign a = b; + assign d = c; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(a, 4'h5) + `check(b, 4'h5) + `check(c, 4'ha) + `check(d, 4'ha) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 33ab7bda9..36d22f512 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -342,6 +342,8 @@ sv_module_port1 vvp_tests/sv_module_port1.json sv_module_port2 vvp_tests/sv_module_port2.json sv_module_port3 vvp_tests/sv_module_port3.json sv_module_port4 vvp_tests/sv_module_port4.json +sv_net_array_decl_assign vvp_tests/sv_net_array_decl_assign.json +sv_net_decl_assign vvp_tests/sv_net_decl_assign.json sv_package_lifetime vvp_tests/sv_package_lifetime.json sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json sv_parameter_type vvp_tests/sv_parameter_type.json diff --git a/ivtest/vvp_tests/sv_net_array_decl_assign.json b/ivtest/vvp_tests/sv_net_array_decl_assign.json new file mode 100644 index 000000000..7e4cdb535 --- /dev/null +++ b/ivtest/vvp_tests/sv_net_array_decl_assign.json @@ -0,0 +1,9 @@ +{ + "type" : "normal", + "source" : "sv_net_array_decl_assign.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "__comment" : "Array nets are not supported", + "type" : "CE" + } +} diff --git a/ivtest/vvp_tests/sv_net_decl_assign.json b/ivtest/vvp_tests/sv_net_decl_assign.json new file mode 100644 index 000000000..ded9a2672 --- /dev/null +++ b/ivtest/vvp_tests/sv_net_decl_assign.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_net_decl_assign.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/parse.y b/parse.y index 54a7d2be4..8c94dd4b5 100644 --- a/parse.y +++ b/parse.y @@ -101,6 +101,29 @@ static pform_name_t* pform_create_super(void) return res; } +static void check_net_decl_assigns(const struct vlltype&loc, + const std::list*assign_list) +{ + if (gn_system_verilog()) + return; + + bool has_initializer = false; + bool has_no_initializer = false; + + for (const auto*cur : *assign_list) { + if (cur->expr) + has_initializer = true; + else + has_no_initializer = true; + + if (has_initializer && has_no_initializer) { + pform_requires_sv(loc, "Mixing initialized and uninitialized " + "net declaration entries"); + return; + } + } +} + /* The rules sometimes push attributes into a global context where sub-rules may grab them. This makes parser rules a little easier to write in some cases. */ @@ -720,9 +743,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt -%type net_variable -%type net_variable_list - %type event_variable label_opt class_declaration_endlabel_opt %type block_identifier_opt %type identifier_name @@ -731,9 +751,6 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type loop_variables %type list_of_port_identifiers list_of_variable_port_identifiers -%type net_decl_assigns -%type net_decl_assign - %type port port_opt port_reference port_reference_list %type port_declaration %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign @@ -780,7 +797,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type assignment_pattern expression expression_opt expr_mintypmax %type expr_primary_or_typename expr_primary %type class_new dynamic_array_new -%type var_decl_initializer_opt initializer_opt +%type net_decl_initializer_opt var_decl_initializer_opt initializer_opt %type inc_or_dec_expression inside_expression lpvalue %type branch_probe_expression streaming_concatenation %type delay_value delay_value_simple @@ -788,8 +805,8 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, %type expression_list_with_nuls expression_list_proper %type cont_assign cont_assign_list -%type variable_decl_assignment -%type list_of_variable_decl_assignments +%type net_decl_assign variable_decl_assignment +%type net_decl_assigns list_of_variable_decl_assignments %type data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void %type data_type_or_implicit_no_opt @@ -4983,70 +5000,30 @@ module_item /* Modules can contain further sub-module definitions. */ : module - | attribute_list_opt net_type data_type_or_implicit delay3_opt net_variable_list ';' - - { data_type_t*data_type = $3; - pform_check_net_data_type(@2, $2, $3); - if (data_type == 0) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); - } - pform_set_data_type(@2, data_type, $5, $2, $1); - if ($4 != 0) { - yyerror(@2, "sorry: Net delays not supported."); - delete $4; - } - delete $1; - } - - | attribute_list_opt K_wreal delay3 net_variable_list ';' - { real_type_t*tmpt = new real_type_t(real_type_t::REAL); - pform_set_data_type(@2, tmpt, $4, NetNet::WIRE, $1); - if ($3 != 0) { - yyerror(@3, "sorry: Net delays not supported."); - delete $3; - } - delete $1; - } - - | attribute_list_opt K_wreal net_variable_list ';' - { real_type_t*tmpt = new real_type_t(real_type_t::REAL); - pform_set_data_type(@2, tmpt, $3, NetNet::WIRE, $1); - delete $1; - } - /* Very similar to the rule above, but this takes a list of net_decl_assigns, which are = assignment declarations. */ - | attribute_list_opt net_type data_type_or_implicit delay3_opt net_decl_assigns ';' - { data_type_t*data_type = $3; - pform_check_net_data_type(@2, $2, $3); - if (data_type == 0) { - data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); - FILE_NAME(data_type, @2); - } - pform_makewire(@2, $4, str_strength, $5, $2, data_type, $1); - delete $1; - } - - /* This form doesn't have the range, but does have strengths. This - gives strength to the assignment drivers. */ - - | attribute_list_opt net_type drive_strength data_type_or_implicit net_decl_assigns ';' + | attribute_list_opt net_type drive_strength_opt data_type_or_implicit delay3_opt net_decl_assigns ';' { data_type_t*data_type = $4; pform_check_net_data_type(@2, $2, $4); + check_net_decl_assigns(@6, $6); if (data_type == 0) { data_type = new vector_type_t(IVL_VT_LOGIC, false, 0); FILE_NAME(data_type, @2); } - pform_makewire(@2, 0, $3, $5, $2, data_type, $1); + pform_makewire(@2, $5, $3, $6, $2, data_type, $1); delete $1; } - | attribute_list_opt K_wreal net_decl_assigns ';' + | attribute_list_opt K_wreal delay3_opt net_decl_assigns ';' { real_type_t*data_type = new real_type_t(real_type_t::REAL); - pform_makewire(@2, 0, str_strength, $3, NetNet::WIRE, data_type, $1); + check_net_decl_assigns(@4, $4); + if ($3) { + yyerror(@2, "error: wreal net does not support delay."); + delete $3; + } + pform_makewire(@2, 0, str_strength, $4, NetNet::WIRE, data_type, $1); delete $1; } @@ -5550,10 +5527,21 @@ generate_block Note that the continuous assignment statement is generated as a side effect, and all I pass up is the name of the l-value. */ +net_decl_initializer_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; + net_decl_assign - : IDENTIFIER '=' expression + : IDENTIFIER dimensions_opt net_decl_initializer_opt { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = { lex_strings.make($1), @1.lexical_pos }; + if ($2) { + tmp->index = *$2; + if ($3) + pform_requires_sv(@$, "Assignment of net array during declaration"); + delete $2; + } tmp->expr.reset($3); delete[]$1; $$ = tmp; @@ -6026,26 +6014,6 @@ dimensions } ; -net_variable - : IDENTIFIER dimensions_opt - { pform_ident_t name = { lex_strings.make($1), @1.lexical_pos }; - $$ = pform_makewire(@1, name, NetNet::IMPLICIT, $2); - delete [] $1; - } - ; - -net_variable_list - : net_variable - { std::vector *tmp = new std::vector; - tmp->push_back($1); - $$ = tmp; - } - | net_variable_list ',' net_variable - { $1->push_back($3); - $$ = $1; - } - ; - event_variable : IDENTIFIER dimensions_opt { if ($2) { diff --git a/pform.cc b/pform.cc index 17a6bdbac..d7c476532 100644 --- a/pform.cc +++ b/pform.cc @@ -49,6 +49,10 @@ using namespace std; +static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, + std::vector *wires, + list*attr, bool is_const = false); + /* * The "// synthesis translate_on/off" meta-comments cause this flag * to be turned off or on. The pform_make_behavior and similar @@ -2709,22 +2713,24 @@ void pform_makewire(const struct vlltype&li, wires->push_back(wire); } - pform_set_data_type(li, data_type, wires, type, attr, is_const); + pform_set_data_type(li, data_type, wires, attr, is_const); while (! assign_list->empty()) { decl_assignment_t*first = assign_list->front(); assign_list->pop_front(); - if (PExpr*expr = first->expr.release()) { - if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { - pform_make_var_init(li, first->name, expr); - } else { - PEIdent*lval = new PEIdent(first->name.first, + if (PExpr*expr = first->expr.release()) { + if (type == NetNet::REG || type == NetNet::IMPLICIT_REG) { + pform_make_var_init(li, first->name, expr); + } else { + PEIdent*lval = new PEIdent(first->name.first, first->name.second); - FILE_NAME(lval, li); - PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); - FILE_NAME(ass, li); - } - } + FILE_NAME(lval, li); + PGAssign*ass = pform_make_pgassign(lval, expr, delay, str); + FILE_NAME(ass, li); + } + } else if (delay) { + VLerror(li, "sorry: net delays not supported."); + } delete first; } } @@ -3272,9 +3278,9 @@ void pform_set_port_type(const struct vlltype&li, * This function detects the derived class for the given type and * dispatches the type to the proper subtype function. */ -void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, - std::vector *wires, NetNet::Type net_type, - list*attr, bool is_const) +static void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, + std::vector *wires, + list*attr, bool is_const) { if (data_type == 0) { VLerror(li, "internal error: data_type==0."); @@ -3289,11 +3295,6 @@ void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, pform_set_net_range(wire, vec_type); - // If these fail there is a bug somewhere else. pform_set_data_type() - // is only ever called on a fresh wire that already exists. - bool rc = wire->set_wire_type(net_type); - ivl_assert(li, rc); - wire->set_data_type(data_type); wire->set_const(is_const); diff --git a/pform.h b/pform.h index 781743258..5fb7e5035 100644 --- a/pform.h +++ b/pform.h @@ -384,13 +384,6 @@ extern void pform_set_port_type(const struct vlltype&li, data_type_t*dt, std::list*attr); -extern void pform_set_data_type(const struct vlltype&li, - data_type_t *data_type, - std::vector *wires, - NetNet::Type net_type, - std::list*attr, - bool is_const = false); - extern void pform_set_string_type(const struct vlltype&li, const string_type_t*string_type, std::list*names, NetNet::Type net_type, std::list*attr); extern void pform_set_class_type(const struct vlltype&li, class_type_t*class_type, std::list*names, NetNet::Type net_type, std::list*addr);