diff --git a/ivtest/ivltests/sv_type_identifier_parameter_decl_name.v b/ivtest/ivltests/sv_type_identifier_parameter_decl_name.v new file mode 100644 index 000000000..f303cfcf1 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_decl_name.v @@ -0,0 +1,35 @@ +// Check that parameter declaration names can shadow visible type identifiers. + +typedef int L; +typedef int P; +typedef int Q; +typedef int R; + +module test; + + reg failed; + + parameter P = 7, R = 13; + localparam Q = 11, L = 17; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(P, 7, "parameter name did not hide typedef"); + `check(R, 13, "parameter list continuation did not hide typedef"); + `check(Q, 11, "localparam name did not hide typedef"); + `check(L, 17, "localparam list continuation did not hide typedef"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_port_name.v b/ivtest/ivltests/sv_type_identifier_parameter_port_name.v new file mode 100644 index 000000000..76429bebd --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_port_name.v @@ -0,0 +1,85 @@ +// Check that parameter port declaration names can shadow visible type identifiers. + +typedef int P; +typedef int Q; +typedef int R; +typedef logic [7:0] T; +typedef int TP; + +package p; + typedef logic [5:0] PT; +endpackage + +`define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + +module M #( + parameter int P = 5, + Q = 9, + int R = 13, + T typed_value = 8'ha5, + T T = 8'h3c, + p::PT pkg_value = 6'h2a, + parameter type TP = logic [5:0] +) (output reg failed); + + TP type_param_value; + + initial begin + failed = 1'b0; + type_param_value = 6'h15; + + `check(P, 5, "parameter port typed value mismatch"); + `check(Q, 9, "parameter port untyped continuation mismatch"); + `check(R, 13, "parameter port atomic type continuation mismatch"); + `check($bits(typed_value), 8, "parameter port typedef type continuation width mismatch"); + `check(typed_value, 8'ha5, "parameter port typedef type continuation value mismatch"); + `check($bits(T), 8, "parameter port type-name continuation did not keep typedef type"); + `check(T, 8'h3c, "parameter port type-name continuation value mismatch"); + `check($bits(pkg_value), 6, "parameter port package type continuation width mismatch"); + `check(pkg_value, 6'h2a, "parameter port package type continuation value mismatch"); + `check($bits(type_param_value), 6, "parameter port type parameter mismatch"); + `check(type_param_value, 6'h15, "parameter port type parameter value mismatch"); + end + +endmodule + +module N #(P = 3, T typed_value = 8'h5a) (output reg failed); + + initial begin + failed = 1'b0; + + `check(P, 3, "omitted parameter keyword mismatch"); + `check($bits(typed_value), 8, "omitted parameter keyword typedef width mismatch"); + `check(typed_value, 8'h5a, "omitted parameter keyword typedef value mismatch"); + end + +endmodule + +module test; + + reg failed; + wire failed_m; + wire failed_n; + + M i_m(failed_m); + N i_n(failed_n); + + initial begin + failed = 1'b0; + + #1; + + `check(failed_m, 1'b0, "parameter port module failed"); + `check(failed_n, 1'b0, "omitted parameter keyword module failed"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_type_decl_name.v b/ivtest/ivltests/sv_type_identifier_parameter_type_decl_name.v new file mode 100644 index 000000000..857dff533 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_type_decl_name.v @@ -0,0 +1,41 @@ +// Check that typed parameter declaration names can shadow visible type identifiers. + +typedef int P; +typedef logic [7:0] T; +typedef logic [6:0] U; + +module test; + + reg failed; + + parameter int P = 13; + parameter T typed_value = 8'ha5; + parameter T T = 8'h3c; + parameter U u0 = 7'h2a, U = 7'h15; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + + `check(P, 13, "typed parameter name did not hide typedef"); + `check($bits(typed_value), 8, "typed parameter width mismatch"); + `check(typed_value, 8'ha5, "typed parameter value mismatch"); + `check($bits(T), 8, "type-name parameter did not keep typedef type"); + `check(T, 8'h3c, "type-name parameter value mismatch"); + `check($bits(u0), 7, "parameter list first declaration did not keep typedef type"); + `check(u0, 7'h2a, "parameter list first value mismatch"); + `check($bits(U), 7, "parameter list continuation did not allow typedef name as parameter name"); + `check(U, 7'h15, "parameter list continuation value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/sv_type_identifier_parameter_type_param_name.v b/ivtest/ivltests/sv_type_identifier_parameter_type_param_name.v new file mode 100644 index 000000000..2494d7b48 --- /dev/null +++ b/ivtest/ivltests/sv_type_identifier_parameter_type_param_name.v @@ -0,0 +1,32 @@ +// Check that type parameter declaration names can shadow visible type identifiers. + +typedef int TP; + +module test; + + reg failed; + + parameter type TP = logic [3:0]; + + TP type_param_value; + + `define check(value, expected, error) \ + if ((value) !== (expected)) begin \ + $display("FAILED(%0d). %s", `__LINE__, error); \ + $display(" expected %0h, got %0h", expected, value); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + type_param_value = 4'hc; + + `check($bits(type_param_value), 4, "type parameter name did not hide typedef"); + `check(type_param_value, 4'hc, "type parameter value mismatch"); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index c023763ad..b7bf85cc5 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -392,6 +392,10 @@ sv_type_identifier_modport_name vvp_tests/sv_type_identifier_modport_name.json sv_type_identifier_module_name vvp_tests/sv_type_identifier_module_name.json sv_type_identifier_net_name vvp_tests/sv_type_identifier_net_name.json sv_type_identifier_package_item vvp_tests/sv_type_identifier_package_item.json +sv_type_identifier_parameter_decl_name vvp_tests/sv_type_identifier_parameter_decl_name.json +sv_type_identifier_parameter_port_name vvp_tests/sv_type_identifier_parameter_port_name.json +sv_type_identifier_parameter_type_decl_name vvp_tests/sv_type_identifier_parameter_type_decl_name.json +sv_type_identifier_parameter_type_param_name vvp_tests/sv_type_identifier_parameter_type_param_name.json sv_type_identifier_port_name vvp_tests/sv_type_identifier_port_name.json sv_type_identifier_specparam_name vvp_tests/sv_type_identifier_specparam_name.json sv_type_identifier_task_function_argument_name vvp_tests/sv_type_identifier_task_function_argument_name.json diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_decl_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_decl_name.json new file mode 100644 index 000000000..9f265426c --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_decl_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_decl_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_port_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_port_name.json new file mode 100644 index 000000000..91cf1e3aa --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_port_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_port_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_type_decl_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_type_decl_name.json new file mode 100644 index 000000000..d51f1988e --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_type_decl_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_type_decl_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/sv_type_identifier_parameter_type_param_name.json b/ivtest/vvp_tests/sv_type_identifier_parameter_type_param_name.json new file mode 100644 index 000000000..fe48a962a --- /dev/null +++ b/ivtest/vvp_tests/sv_type_identifier_parameter_type_param_name.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "sv_type_identifier_parameter_type_param_name.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/parse.y b/parse.y index 35e6c89fb..0803658e8 100644 --- a/parse.y +++ b/parse.y @@ -139,12 +139,16 @@ static data_type_t *pform_make_parray_type(const struct vlltype&loc, template static void set_type_id_range(T&value, data_type_t *type, char *id, - unsigned lexical_pos, + const YYLTYPE&loc, std::list *ranges) { value.type = type; value.id = id; - value.lexical_pos = lexical_pos; + value.lexical_pos = loc.lexical_pos; + value.first_line = loc.first_line; + value.first_column = loc.first_column; + value.last_line = loc.last_line; + value.last_column = loc.last_column; value.ranges = ranges; } @@ -299,6 +303,29 @@ static decl_assignment_t *pform_make_net_decl(const YYLTYPE&loc, char *id, return pform_make_net_decl(loc, id, loc.lexical_pos, udims, init); } +static void pform_set_parameter(const YYLTYPE&loc, char *id, unsigned lexical_pos, + bool is_local, bool is_type, + type_restrict_t type_restrict, + data_type_t*data_type, const list*udims, + PExpr*expr, LexicalScope::range_t*value_range) +{ + YYLTYPE id_loc = loc; + id_loc.lexical_pos = lexical_pos; + pform_set_parameter(id_loc, lex_strings.make(id), is_local, is_type, + type_restrict, data_type, udims, expr, value_range); + delete[] id; +} + +static void pform_set_parameter(const YYLTYPE&loc, char *id, + bool is_local, bool is_type, + type_restrict_t type_restrict, + data_type_t*data_type, const list*udims, + PExpr*expr, LexicalScope::range_t*value_range) +{ + pform_set_parameter(loc, id, loc.lexical_pos, is_local, is_type, + type_restrict, data_type, udims, expr, value_range); +} + template void append(vector&out, const std::vector&in) { for (size_t idx = 0 ; idx < in.size() ; idx += 1) @@ -699,6 +726,10 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type, data_type_t *type; char *id; unsigned lexical_pos; + int first_line; + int first_column; + int last_line; + int last_column; std::list*ranges; } type_id_range; @@ -2721,25 +2752,26 @@ tf_port_declaration /* IEEE1800-2005: A.2.7 */ // dimensions followed by a separate declaration name. data_type_or_implicit_plus_id_base : IDENTIFIER - { set_type_id_range($$, nullptr, $1, @1.lexical_pos, nullptr); + { set_type_id_range($$, nullptr, $1, @1, nullptr); } | atomic_type identifier_name - { set_type_id_range($$, $1, $2, @2.lexical_pos, nullptr); + { set_type_id_range($$, $1, $2, @2, nullptr); } | implicit_type identifier_name - { set_type_id_range($$, $1, $2, @2.lexical_pos, nullptr); + { set_type_id_range($$, $1, $2, @2, nullptr); } | ps_type_identifier_dim identifier_name - { set_type_id_range($$, $1, $2, @2.lexical_pos, nullptr); + { set_type_id_range($$, $1, $2, @2, nullptr); } ; data_type_or_implicit_plus_id_dim : TYPE_IDENTIFIER dimensions_opt - { set_type_id_range($$, nullptr, $1.text, @1.lexical_pos, $2); + { set_type_id_range($$, nullptr, $1.text, @1, $2); } | data_type_or_implicit_plus_id_base dimensions_opt - { set_type_id_range($$, $1.type, $1.id, $1.lexical_pos, $2); + { $$ = $1; + $$.ranges = $2; } ; @@ -2749,19 +2781,19 @@ data_type_or_implicit_plus_id_dim // still parsed as a continuation of the previous port declaration. partial_port_type_plus_id_dim : atomic_type identifier_name dimensions_opt - { set_type_id_range($$, $1, $2, @2.lexical_pos, $3); + { set_type_id_range($$, $1, $2, @2, $3); } | implicit_type identifier_name dimensions_opt - { set_type_id_range($$, $1, $2, @2.lexical_pos, $3); + { set_type_id_range($$, $1, $2, @2, $3); } ; partial_port_name_dim : IDENTIFIER dimensions_opt - { set_type_id_range($$, nullptr, $1, @1.lexical_pos, $2); + { set_type_id_range($$, nullptr, $1, @1, $2); } | TYPE_IDENTIFIER dimensions_opt - { set_type_id_range($$, nullptr, $1.text, @1.lexical_pos, $2); + { set_type_id_range($$, nullptr, $1.text, @1, $2); } ; @@ -2772,7 +2804,7 @@ partial_port_typedef_plus_id_dim FILE_NAME(tmp, @1); delete[]$1.text; tmp = pform_make_parray_type(@2, tmp, $2); - set_type_id_range($$, tmp, $3, @3.lexical_pos, $4); + set_type_id_range($$, tmp, $3, @3, $4); } | package_scope TYPE_IDENTIFIER dimensions_opt identifier_name dimensions_opt { lex_in_package_scope(nullptr); @@ -2780,7 +2812,7 @@ partial_port_typedef_plus_id_dim FILE_NAME(tmp, @2); delete[]$2.text; tmp = pform_make_parray_type(@3, tmp, $3); - set_type_id_range($$, tmp, $4, @4.lexical_pos, $5); + set_type_id_range($$, tmp, $4, @4, $5); } ; @@ -5202,38 +5234,27 @@ type_param ; module_parameter - : parameter param_type parameter_assign - | localparam param_type parameter_assign + : parameter parameter_assign_with_type + | localparam parameter_assign_with_type { pform_requires_sv(@1, "Local parameter in module parameter port list"); } ; module_parameter_port_list : module_parameter - | data_type_opt - { param_data_type = $1; - param_is_local = false; - param_is_type = false; - param_type_restrict = {}; - } - parameter_assign - { pform_requires_sv(@3, "Omitting initial `parameter` in parameter port " + | value_parameter_assign_with_type + { pform_requires_sv(@1, "Omitting initial `parameter` in parameter port " "list"); } | type_param { param_is_local = false; } parameter_assign | module_parameter_port_list ',' module_parameter - | module_parameter_port_list ',' data_type_opt - { if ($3) { - pform_requires_sv(@3, "Omitting `parameter`/`localparam` before " - "data type in parameter port list"); - param_data_type = $3; - param_is_type = false; - param_type_restrict = {}; - } + | module_parameter_port_list ',' parameter_assign + | module_parameter_port_list ',' value_parameter_assign_with_explicit_type + { pform_requires_sv(@3, "Omitting `parameter`/`localparam` before " + "data type in parameter port list"); } - parameter_assign | module_parameter_port_list ',' type_param parameter_assign ; @@ -5847,19 +5868,6 @@ net_type_or_var_opt | K_var { $$ = NetNet::REG; } ; - /* The param_type rule is just the data_type_or_implicit rule wrapped - with an assignment to para_data_type with the figured data type. - This is used by parameter_assign, which is found to the right of - the param_type in various rules. */ - -param_type - : data_type_or_implicit - { param_is_type = false; - param_data_type = $1; - param_type_restrict = {}; - } - | type_param - parameter : K_parameter { param_is_local = false; } @@ -5871,7 +5879,7 @@ localparam ; parameter_declaration - : parameter_or_localparam param_type parameter_assign_list ';' + : parameter_or_localparam parameter_assign_list_with_type ';' parameter_or_localparam : parameter @@ -5883,17 +5891,73 @@ parameter_or_localparam handling code. localparams parse the same as parameters, they just behave differently when someone tries to override them. */ -parameter_assign_list - : parameter_assign - | parameter_assign_list ',' parameter_assign + // The first parameter assignment is parsed together with the optional type + // so `parameter T` can shadow a typedef name, while `parameter T p` still + // parses T as the parameter type. Continuations keep the previous type, so a + // bare typedef name after a comma is still a parameter name. +parameter_assign_list_with_type + : parameter_assign_with_type + | parameter_assign_list_with_type ',' parameter_assign + ; + +parameter_assign_with_type + : value_parameter_assign_with_type + | type_param parameter_assign + ; + +value_parameter_assign_with_type + : data_type_or_implicit_plus_id_dim initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1.type; + YYLTYPE id_loc = @1; + id_loc.first_line = $1.first_line; + id_loc.first_column = $1.first_column; + id_loc.last_line = $1.last_line; + id_loc.last_column = $1.last_column; + id_loc.lexical_pos = $1.lexical_pos; + pform_set_parameter(id_loc, $1.id, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $1.ranges, $2, $3); + } + ; + + // Parameter port lists allow an explicit type after a comma without + // repeating `parameter`, e.g. `#(parameter p = 1, int q = 2)`. Keep this + // narrower than value_parameter_assign_with_type so a bare typedef name + // after a comma remains a parameter name that inherits the previous type. +value_parameter_assign_with_explicit_type + : atomic_type identifier_name dimensions_opt initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1; + pform_set_parameter(@2, $2, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $3, $4, $5); + } + | implicit_type identifier_name dimensions_opt initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1; + pform_set_parameter(@2, $2, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $3, $4, $5); + } + | ps_type_identifier_dim identifier_name dimensions_opt initializer_opt parameter_value_ranges_opt + { param_is_type = false; + param_type_restrict = {}; + param_data_type = $1; + pform_set_parameter(@2, $2, param_is_local, + param_is_type, param_type_restrict, + param_data_type, $3, $4, $5); + } ; parameter_assign - : IDENTIFIER dimensions_opt initializer_opt parameter_value_ranges_opt - { pform_set_parameter(@1, lex_strings.make($1), param_is_local, + : identifier_name dimensions_opt initializer_opt parameter_value_ranges_opt + { pform_set_parameter(@1, $1, param_is_local, param_is_type, param_type_restrict, param_data_type, $2, $3, $4); - delete[]$1; } ;