Merge pull request #1424 from larsclausen/type-id-parameter-declarations
Support shadowing type identifiers in parameter declarations
This commit is contained in:
commit
60a81493cd
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_parameter_decl_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_parameter_port_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_parameter_type_decl_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_type_identifier_parameter_type_param_name.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
168
parse.y
168
parse.y
|
|
@ -139,12 +139,16 @@ static data_type_t *pform_make_parray_type(const struct vlltype&loc,
|
|||
|
||||
template <class T>
|
||||
static void set_type_id_range(T&value, data_type_t *type, char *id,
|
||||
unsigned lexical_pos,
|
||||
const YYLTYPE&loc,
|
||||
std::list<pform_range_t> *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<pform_range_t>*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<pform_range_t>*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 <class T> void append(vector<T>&out, const std::vector<T>&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<pform_range_t>*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 "
|
||||
| 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");
|
||||
param_data_type = $3;
|
||||
param_is_type = false;
|
||||
param_type_restrict = {};
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue