Merge pull request #965 from larsclausen/sv-partial-module-ports
Support SystemVerilog style partial ANSI port declarations
This commit is contained in:
commit
272771d183
|
|
@ -0,0 +1,33 @@
|
|||
// Check that partial module ANSI port declarations are supported. Check that it
|
||||
// is possible to redefine the data type only.
|
||||
|
||||
module test (input [3:0] a, [1:0] b, integer c, wire d);
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(val, exp) do begin \
|
||||
if ((val) !== (exp)) begin \
|
||||
$display("FAILED(%0d): Expected `%d`, got `%d`.", `__LINE__, \
|
||||
(exp), (val)); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
end while (0)
|
||||
|
||||
initial begin
|
||||
`check($bits(a), 4);
|
||||
`check($bits(b), 2);
|
||||
`check($bits(c), $bits(integer));
|
||||
`check($bits(d), 1);
|
||||
|
||||
// They should all be wires
|
||||
`check(a, 'z);
|
||||
`check(b, 'z);
|
||||
`check(c, 'z);
|
||||
`check(d, 'z);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Check that partial module ANSI port declarations are supported. Check that it
|
||||
// is possible to redefine the unpacked dimensions only.
|
||||
|
||||
module test (input integer a, b[1:0], c[2:0][3:0]);
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(val, exp) do begin \
|
||||
if ((val) !== (exp)) begin \
|
||||
$display("FAILED(%0d): Expected `%d`, got `%d`.", `__LINE__, \
|
||||
(exp), (val)); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
end while (0)
|
||||
|
||||
initial begin
|
||||
`check($dimensions(a), 1);
|
||||
`check($dimensions(b), 2);
|
||||
`check($dimensions(c), 3);
|
||||
`check($bits(a), $bits(integer));
|
||||
`check($bits(b), $bits(integer) * 2);
|
||||
`check($bits(c), $bits(integer) * 3 * 4);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Check that it is possible to declare module ports without specifing the
|
||||
// direction.
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(val, exp) do begin \
|
||||
if ((val) !== (exp)) begin \
|
||||
$display("FAILED(%0d): Expected `%d`, got `%d`.", `__LINE__, \
|
||||
(exp), (val)); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
end while (0)
|
||||
|
||||
// All ports should be inout if no direction is specified
|
||||
module M (wire [31:0] a, b, c);
|
||||
|
||||
assign c = a ^ b;
|
||||
|
||||
initial begin
|
||||
`check($bits(a), 32);
|
||||
`check($bits(b), 32);
|
||||
`check($bits(c), 32);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module test;
|
||||
|
||||
wire [31:0] a, b, c;
|
||||
|
||||
M i_m (a, b, c);
|
||||
|
||||
`define A 'h01234567
|
||||
`define B 'hfedcba98
|
||||
|
||||
assign a = `A;
|
||||
assign b = `B;
|
||||
|
||||
initial begin
|
||||
#1
|
||||
|
||||
`check(c, `A ^ `B);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Check that partial module ANSI port declarations are supported. Check that it
|
||||
// is possible to redefine the port kind only.
|
||||
|
||||
|
||||
|
||||
module test(
|
||||
output [3:0] a,
|
||||
var b, c,
|
||||
wire d);
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(val, exp) do begin \
|
||||
if ((val) !== (exp)) begin \
|
||||
$display("FAILED(%0d): Expected `%d`, got `%d`.", `__LINE__, \
|
||||
(exp), (val)); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
end while (0)
|
||||
|
||||
initial begin
|
||||
`check($bits(a), 4);
|
||||
`check($bits(b), 1);
|
||||
`check($bits(c), 1);
|
||||
`check($bits(d), 1);
|
||||
|
||||
// a and d are wires, b and c are variables
|
||||
`check(a, 4'bzzzz);
|
||||
`check(b, 1'bx);
|
||||
`check(c, 1'bx);
|
||||
`check(d, 1'bz);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -62,6 +62,10 @@ sv_array_cassign6 vvp_tests/sv_array_cassign6.json
|
|||
sv_array_cassign7 vvp_tests/sv_array_cassign7.json
|
||||
sv_foreach9 vvp_tests/sv_foreach9.json
|
||||
sv_foreach10 vvp_tests/sv_foreach10.json
|
||||
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_wildcard_import8 vvp_tests/sv_wildcard_import8.json
|
||||
sdf_header vvp_tests/sdf_header.json
|
||||
task_return1 vvp_tests/task_return1.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_module_port1.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_module_port2.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_module_port3.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_module_port4.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ]
|
||||
}
|
||||
238
parse.y
238
parse.y
|
|
@ -352,6 +352,72 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
|
|||
current_function->set_statement(tmp);
|
||||
}
|
||||
|
||||
static void port_declaration_context_init(void)
|
||||
{
|
||||
port_declaration_context.port_type = NetNet::PINOUT;
|
||||
port_declaration_context.port_net_type = NetNet::IMPLICIT;
|
||||
port_declaration_context.data_type = nullptr;
|
||||
}
|
||||
|
||||
Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
|
||||
NetNet::PortType port_type,
|
||||
NetNet::Type net_type,
|
||||
data_type_t *data_type,
|
||||
std::list<pform_range_t> *unpacked_dims,
|
||||
PExpr *default_value,
|
||||
std::list<named_pexpr_t> *attributes)
|
||||
{
|
||||
perm_string name = lex_strings.make(id);
|
||||
delete[] id;
|
||||
|
||||
Module::port_t *port = pform_module_port_reference(loc, name);
|
||||
|
||||
switch (port_type) {
|
||||
case NetNet::PINOUT:
|
||||
if (default_value)
|
||||
yyerror(loc, "error: Default port value not allowed for inout ports.");
|
||||
if (unpacked_dims) {
|
||||
yyerror(loc, "sorry: Inout ports with unpacked dimensions are not supported.");
|
||||
delete unpacked_dims;
|
||||
unpacked_dims = nullptr;
|
||||
}
|
||||
break;
|
||||
case NetNet::PINPUT:
|
||||
if (default_value) {
|
||||
pform_requires_sv(loc, "Input port default value");
|
||||
port->default_value = default_value;
|
||||
}
|
||||
break;
|
||||
case NetNet::POUTPUT:
|
||||
if (default_value)
|
||||
pform_make_var_init(loc, name, default_value);
|
||||
|
||||
// Output types without an implicit net type but with a data type
|
||||
// are variables. Unlike the other port types, which are nets in
|
||||
// that case.
|
||||
if (net_type == NetNet::IMPLICIT) {
|
||||
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> (data_type)) {
|
||||
if (!dtype->implicit_flag)
|
||||
net_type = NetNet::IMPLICIT_REG;
|
||||
} else if (data_type) {
|
||||
net_type = NetNet::IMPLICIT_REG;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pform_module_define_port(loc, name, port_type, net_type, data_type,
|
||||
unpacked_dims, attributes);
|
||||
|
||||
port_declaration_context.port_type = port_type;
|
||||
port_declaration_context.port_net_type = net_type;
|
||||
port_declaration_context.data_type = data_type;
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
|
|
@ -646,6 +712,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
|
|||
%type <decl_assignments> list_of_variable_decl_assignments
|
||||
|
||||
%type <data_type> data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void
|
||||
%type <data_type> data_type_or_implicit_no_opt
|
||||
%type <data_type> simple_type_or_string let_formal_type
|
||||
%type <data_type> packed_array_data_type
|
||||
%type <data_type> ps_type_identifier
|
||||
|
|
@ -1278,7 +1345,11 @@ scalar_vector_opt /*IEEE1800-2005: optional support for packed array */
|
|||
;
|
||||
|
||||
data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */
|
||||
: data_type_opt
|
||||
: data_type_or_implicit_no_opt
|
||||
| { $$ = nullptr; }
|
||||
|
||||
data_type_or_implicit_no_opt
|
||||
: data_type
|
||||
{ $$ = $1; }
|
||||
| signing dimensions_opt
|
||||
{ vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2);
|
||||
|
|
@ -4407,39 +4478,16 @@ list_of_port_declarations
|
|||
tmp->push_back($3);
|
||||
$$ = tmp;
|
||||
}
|
||||
| list_of_port_declarations ',' IDENTIFIER initializer_opt
|
||||
{ Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($3);
|
||||
ptmp = pform_module_port_reference(@3, name);
|
||||
std::vector<Module::port_t*>*tmp = $1;
|
||||
tmp->push_back(ptmp);
|
||||
| list_of_port_declarations ',' attribute_list_opt IDENTIFIER dimensions_opt initializer_opt
|
||||
{ std::vector<Module::port_t*> *ports = $1;
|
||||
|
||||
if ($4) {
|
||||
switch (port_declaration_context.port_type) {
|
||||
case NetNet::PINOUT:
|
||||
yyerror(@4, "error: Default port value not allowed for inout ports.");
|
||||
break;
|
||||
case NetNet::PINPUT:
|
||||
pform_requires_sv(@4, "Default port value");
|
||||
ptmp->default_value = $4;
|
||||
break;
|
||||
case NetNet::POUTPUT:
|
||||
pform_make_var_init(@3, name, $4);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Get the port declaration details, the port type
|
||||
and what not, from context data stored by the
|
||||
last port_declaration rule. */
|
||||
pform_module_define_port(@3, name,
|
||||
port_declaration_context.port_type,
|
||||
port_declaration_context.port_net_type,
|
||||
port_declaration_context.data_type,
|
||||
nullptr, nullptr);
|
||||
delete[]$3;
|
||||
$$ = tmp;
|
||||
Module::port_t* port;
|
||||
port = module_declare_port(@4, $4, port_declaration_context.port_type,
|
||||
port_declaration_context.port_net_type,
|
||||
port_declaration_context.data_type,
|
||||
$5, $6, $3);
|
||||
ports->push_back(port);
|
||||
$$ = ports;
|
||||
}
|
||||
| list_of_port_declarations ','
|
||||
{ yyerror(@2, "error: Superfluous comma in port declaration list."); }
|
||||
|
|
@ -4447,112 +4495,27 @@ list_of_port_declarations
|
|||
{ yyerror(@2, "error: ';' is an invalid port declaration separator."); }
|
||||
;
|
||||
|
||||
// All of port direction, port kind and data type are optional, but at least
|
||||
// one has to be specified, so we need multiple rules.
|
||||
port_declaration
|
||||
: attribute_list_opt K_input net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt
|
||||
{ if ($7)
|
||||
pform_requires_sv(@7, "Input port default value");
|
||||
Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($5);
|
||||
ptmp = pform_module_port_reference(@2, name);
|
||||
ptmp->default_value = $7;
|
||||
pform_module_define_port(@2, name, NetNet::PINPUT, $3, $4, $6, nullptr,
|
||||
$1);
|
||||
port_declaration_context.port_type = NetNet::PINPUT;
|
||||
port_declaration_context.port_net_type = $3;
|
||||
port_declaration_context.data_type = $4;
|
||||
delete[]$5;
|
||||
$$ = ptmp;
|
||||
: attribute_list_opt port_direction net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt
|
||||
{ $$ = module_declare_port(@5, $5, $2, $3, $4, $6, $7, $1);
|
||||
}
|
||||
| attribute_list_opt
|
||||
K_input K_wreal IDENTIFIER
|
||||
{ Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($4);
|
||||
ptmp = pform_module_port_reference(@2, name);
|
||||
real_type_t*real_type = new real_type_t(real_type_t::REAL);
|
||||
| attribute_list_opt net_type_or_var data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt
|
||||
{ pform_requires_sv(@4, "Partial ANSI port declaration");
|
||||
$$ = module_declare_port(@4, $4, port_declaration_context.port_type,
|
||||
$2, $3, $5, $6, $1);
|
||||
}
|
||||
| attribute_list_opt data_type_or_implicit_no_opt IDENTIFIER dimensions_opt initializer_opt
|
||||
{ pform_requires_sv(@3, "Partial ANSI port declaration");
|
||||
$$ = module_declare_port(@3, $3, port_declaration_context.port_type,
|
||||
NetNet::IMPLICIT, $2, $4, $5, $1);
|
||||
}
|
||||
| attribute_list_opt port_direction K_wreal IDENTIFIER
|
||||
{ real_type_t*real_type = new real_type_t(real_type_t::REAL);
|
||||
FILE_NAME(real_type, @3);
|
||||
pform_module_define_port(@2, name, NetNet::PINPUT, NetNet::WIRE,
|
||||
real_type, nullptr, $1);
|
||||
port_declaration_context.port_type = NetNet::PINPUT;
|
||||
port_declaration_context.port_net_type = NetNet::WIRE;
|
||||
port_declaration_context.data_type = real_type;
|
||||
delete[]$4;
|
||||
$$ = ptmp;
|
||||
}
|
||||
| attribute_list_opt K_inout net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
|
||||
{ Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($5);
|
||||
ptmp = pform_module_port_reference(@2, name);
|
||||
pform_module_define_port(@2, name, NetNet::PINOUT, $3, $4, nullptr,
|
||||
$1);
|
||||
port_declaration_context.port_type = NetNet::PINOUT;
|
||||
port_declaration_context.port_net_type = $3;
|
||||
port_declaration_context.data_type = $4;
|
||||
delete[]$5;
|
||||
if ($6) {
|
||||
yyerror(@6, "sorry: Inout ports with unpacked dimensions not supported.");
|
||||
delete $6;
|
||||
}
|
||||
$$ = ptmp;
|
||||
}
|
||||
| attribute_list_opt
|
||||
K_inout K_wreal IDENTIFIER
|
||||
{ Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($4);
|
||||
ptmp = pform_module_port_reference(@2, name);
|
||||
real_type_t*real_type = new real_type_t(real_type_t::REAL);
|
||||
FILE_NAME(real_type, @3);
|
||||
pform_module_define_port(@2, name, NetNet::PINOUT, NetNet::WIRE,
|
||||
real_type, nullptr, $1);
|
||||
port_declaration_context.port_type = NetNet::PINOUT;
|
||||
port_declaration_context.port_net_type = NetNet::WIRE;
|
||||
port_declaration_context.data_type = real_type;
|
||||
delete[]$4;
|
||||
$$ = ptmp;
|
||||
}
|
||||
| attribute_list_opt K_output net_type_or_var_opt data_type_or_implicit IDENTIFIER dimensions_opt initializer_opt
|
||||
{ Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($5);
|
||||
NetNet::Type use_type = $3;
|
||||
if (use_type == NetNet::IMPLICIT) {
|
||||
if (vector_type_t*dtype = dynamic_cast<vector_type_t*> ($4)) {
|
||||
if (dtype->implicit_flag)
|
||||
use_type = NetNet::IMPLICIT;
|
||||
else
|
||||
use_type = NetNet::IMPLICIT_REG;
|
||||
|
||||
// The SystemVerilog types that can show up as
|
||||
// output ports are implicitly (on the inside)
|
||||
// variables because "reg" is not valid syntax
|
||||
// here.
|
||||
} else if ($4) {
|
||||
use_type = NetNet::IMPLICIT_REG;
|
||||
}
|
||||
}
|
||||
ptmp = pform_module_port_reference(@2, name);
|
||||
pform_module_define_port(@2, name, NetNet::POUTPUT, use_type, $4, $6, $1);
|
||||
port_declaration_context.port_type = NetNet::POUTPUT;
|
||||
port_declaration_context.port_net_type = use_type;
|
||||
port_declaration_context.data_type = $4;
|
||||
|
||||
if ($7)
|
||||
pform_make_var_init(@5, name, $7);
|
||||
delete[]$5;
|
||||
$$ = ptmp;
|
||||
}
|
||||
| attribute_list_opt
|
||||
K_output K_wreal IDENTIFIER
|
||||
{ Module::port_t*ptmp;
|
||||
perm_string name = lex_strings.make($4);
|
||||
ptmp = pform_module_port_reference(@2, name);
|
||||
real_type_t*real_type = new real_type_t(real_type_t::REAL);
|
||||
FILE_NAME(real_type, @3);
|
||||
pform_module_define_port(@2, name, NetNet::POUTPUT, NetNet::WIRE,
|
||||
real_type, nullptr, $1);
|
||||
port_declaration_context.port_type = NetNet::POUTPUT;
|
||||
port_declaration_context.port_net_type = NetNet::WIRE;
|
||||
port_declaration_context.data_type = real_type;
|
||||
delete[]$4;
|
||||
$$ = ptmp;
|
||||
$$ = module_declare_port(@4, $4, $2, NetNet::WIRE,
|
||||
real_type, nullptr, nullptr, $1);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -4651,7 +4614,8 @@ cont_assign_list
|
|||
|
||||
module
|
||||
: attribute_list_opt module_start lifetime_opt IDENTIFIER
|
||||
{ pform_startmodule(@2, $4, $2==K_program, $2==K_interface, $3, $1); }
|
||||
{ pform_startmodule(@2, $4, $2==K_program, $2==K_interface, $3, $1);
|
||||
port_declaration_context_init(); }
|
||||
module_package_import_list_opt
|
||||
module_parameter_port_list_opt
|
||||
module_port_list_opt
|
||||
|
|
|
|||
Loading…
Reference in New Issue