Merge pull request #623 from larsclausen/task-ports-sv

Support SystemVerilog non-ansi task/function port declarations
This commit is contained in:
Stephen Williams 2022-02-26 09:16:33 -08:00 committed by GitHub
commit 978717f914
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 132 additions and 119 deletions

View File

@ -1254,21 +1254,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
sig = new NetNet(scope, name_, wtype, unpacked_dimensions, sig = new NetNet(scope, name_, wtype, unpacked_dimensions,
&netstring_t::type_string); &netstring_t::type_string);
} else if (set_data_type_==0 && data_type_==IVL_VT_STRING) {
// Signal declared as: string foo;
if (debug_elaborate) {
cerr << get_fileline() << ": PWire::elaborate_sig: "
<< "Create signal " << wtype
<< " string "
<< name_ << " in scope " << scope_path(scope)
<< " without set_data_type_"
<< endl;
}
sig = new NetNet(scope, name_, wtype, unpacked_dimensions,
&netstring_t::type_string);
} else if (parray_type_t*parray_type = dynamic_cast<parray_type_t*>(set_data_type_)) { } else if (parray_type_t*parray_type = dynamic_cast<parray_type_t*>(set_data_type_)) {
// The pform gives us a parray_type_t for packed arrays // The pform gives us a parray_type_t for packed arrays
// that show up in type definitions. This can be handled // that show up in type definitions. This can be handled
@ -1315,6 +1300,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
} }
} }
ivl_assert(*this, use_data_type == IVL_VT_LOGIC ||
use_data_type == IVL_VT_BOOL ||
use_data_type == IVL_VT_REAL);
netvector_t*vec = new netvector_t(packed_dimensions, use_data_type); netvector_t*vec = new netvector_t(packed_dimensions, use_data_type);
vec->set_signed(get_signed()); vec->set_signed(get_signed());
vec->set_isint(get_isint()); vec->set_isint(get_isint());

View File

@ -0,0 +1,35 @@
// Check that it is possible to use SV data types for ANSI style task ports
module test;
typedef logic [7:0] T1;
typedef struct packed { int i; } T2;
typedef enum { A } T3;
task t(input reg a,
input logic b,
input bit c,
input logic [3:0] d,
input bit [3:0][3:0] e,
input byte f,
input int g,
input T1 h,
input T2 i,
input T3 j,
input real k,
input shortreal l,
input string m,
input int n[],
input int o[$],
input x,
input [3:0] y,
input signed z
);
$display("PASSED");
endtask
initial begin
t('0, '0, '0, '0, '0, '0, '0, '0, '0, A, 0.0, 0.0, "", '{0}, '{0}, '0, '0, '0);
end
endmodule

View File

@ -0,0 +1,35 @@
// Check that it is possible to use SV data types for non-ANSI style task ports
module test;
typedef logic [7:0] T1;
typedef struct packed { int i; } T2;
typedef enum { A } T3;
task t;
input reg a;
input logic b;
input bit c;
input logic [3:0] d;
input bit [3:0][3:0] e;
input byte f;
input int g;
input T1 h;
input T2 i;
input T3 j;
input real k;
input shortreal l;
input string m;
input int n[];
input int o[$];
input x;
input [3:0] y;
input signed z;
$display("PASSED");
endtask
initial begin
t('0, '0, '0, '0, '0, '0, '0, '0, '0, A, 0.0, 0.0, "", '{0}, '{0}, '0, '0, '0);
end
endmodule

View File

@ -581,6 +581,8 @@ task_init_assign normal,-g2009 ivltests
task_init_var1 normal,-g2009 ivltests task_init_var1 normal,-g2009 ivltests
task_init_var2 normal,-g2009 ivltests task_init_var2 normal,-g2009 ivltests
task_init_var3 normal,-g2009 ivltests task_init_var3 normal,-g2009 ivltests
task_port_types1 normal,-g2009 ivltests
task_port_types2 normal,-g2009 ivltests
task_scope2 normal,-g2009 ivltests task_scope2 normal,-g2009 ivltests
test_inc_dec normal,-g2009 ivltests test_inc_dec normal,-g2009 ivltests
test_tliteral normal,-g2009 ivltests test_tliteral normal,-g2009 ivltests

View File

@ -95,6 +95,8 @@ recursive_task CE ivltests
task_init_var1 CE,-pallowsigned=1 ivltests task_init_var1 CE,-pallowsigned=1 ivltests
task_init_var2 CE,-pallowsigned=1 ivltests task_init_var2 CE,-pallowsigned=1 ivltests
task_init_var3 CE,-pallowsigned=1 ivltests task_init_var3 CE,-pallowsigned=1 ivltests
task_port_types1 CE,-pallowsigned=1 ivltests
task_port_types2 CE,-pallowsigned=1 ivltests
test_work14 CE ivltests test_work14 CE ivltests
vhdl_elab_range CE ivltests vhdl_elab_range CE ivltests
vhdl_notfunc_stdlogic CE ivltests vhdl_notfunc_stdlogic CE ivltests

67
parse.y
View File

@ -590,7 +590,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector<Statem
%type <number> number pos_neg_number %type <number> number pos_neg_number
%type <flag> signing unsigned_signed_opt signed_unsigned_opt %type <flag> signing unsigned_signed_opt signed_unsigned_opt
%type <flag> import_export %type <flag> import_export
%type <flag> K_genvar_opt K_reg_opt K_static_opt K_virtual_opt %type <flag> K_genvar_opt K_static_opt K_virtual_opt
%type <flag> udp_reg_opt edge_operator %type <flag> udp_reg_opt edge_operator
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1 %type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> udp_input_sym udp_output_sym %type <letter> udp_input_sym udp_output_sym
@ -2106,13 +2106,6 @@ random_qualifier /* IEEE1800-2005 A.1.8 */
| K_randc { $$ = property_qualifier_t::make_randc(); } | K_randc { $$ = property_qualifier_t::make_randc(); }
; ;
/* real and realtime are exactly the same so save some code
* with a common matching rule. */
real_or_realtime
: K_real
| K_realtime
;
signing /* IEEE1800-2005: A.2.2.1 */ signing /* IEEE1800-2005: A.2.2.1 */
: K_signed { $$ = true; } : K_signed { $$ = true; }
| K_unsigned { $$ = false; } | K_unsigned { $$ = false; }
@ -2355,50 +2348,9 @@ task_declaration /* IEEE1800-2005: A.2.7 */
tf_port_declaration /* IEEE1800-2005: A.2.7 */ tf_port_declaration /* IEEE1800-2005: A.2.7 */
: port_direction K_reg_opt unsigned_signed_opt dimensions_opt list_of_identifiers ';' : port_direction data_type_or_implicit list_of_port_identifiers ';'
{ std::vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1, { $$ = pform_make_task_ports(@1, $1, $2, $3, true);
$2 ? IVL_VT_LOGIC :
IVL_VT_NO_TYPE,
$3, $4, $5);
$$ = tmp;
} }
/* When the port is an integer, infer a signed vector of the integer
shape. Generate a range ([31:0]) to make it work. */
| port_direction K_integer list_of_identifiers ';'
{ std::list<pform_range_t>*range_stub = make_range_from_width(integer_width);
vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true,
range_stub, $3, true);
$$ = tmp;
}
/* Ports can be time with a width of [63:0] (unsigned). */
| port_direction K_time list_of_identifiers ';'
{ std::list<pform_range_t>*range_stub = make_range_from_width(64);
vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false,
range_stub, $3);
$$ = tmp;
}
/* Ports can be real or realtime. */
| port_direction real_or_realtime list_of_identifiers ';'
{ std::vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, true,
0, $3);
$$ = tmp;
}
/* Ports can be string. */
| port_direction K_string list_of_identifiers ';'
{ std::vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1, IVL_VT_STRING, true,
0, $3);
$$ = tmp;
}
; ;
@ -2417,8 +2369,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
NetNet::PortType use_port_type = $1; NetNet::PortType use_port_type = $1;
if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($2 == 0))) if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($2 == 0)))
use_port_type = port_declaration_context.port_type; use_port_type = port_declaration_context.port_type;
perm_string name = lex_strings.make($3); list<pform_port_t>* port_list = make_port_list($3, $4, 0);
list<perm_string>* ilist = list_from_identifier($3);
if (use_port_type == NetNet::PIMPLICIT) { if (use_port_type == NetNet::PIMPLICIT) {
yyerror(@1, "error: missing task/function port direction."); yyerror(@1, "error: missing task/function port direction.");
@ -2433,7 +2384,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
} }
tmp = pform_make_task_ports(@3, use_port_type, tmp = pform_make_task_ports(@3, use_port_type,
port_declaration_context.data_type, port_declaration_context.data_type,
ilist); port_list);
} else { } else {
// Otherwise, the decorations for this identifier // Otherwise, the decorations for this identifier
@ -2445,12 +2396,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
FILE_NAME($2, @3); FILE_NAME($2, @3);
} }
port_declaration_context.data_type = $2; port_declaration_context.data_type = $2;
tmp = pform_make_task_ports(@3, use_port_type, $2, ilist); tmp = pform_make_task_ports(@3, use_port_type, $2, port_list);
}
if ($4 != 0) {
if (pform_requires_sv(@4, "Task/function port with unpacked dimensions")) {
pform_set_reg_idx(name, $4);
}
} }
$$ = tmp; $$ = tmp;
@ -7249,6 +7195,5 @@ unique_priority
collect those rules here. */ collect those rules here. */
K_genvar_opt : K_genvar { $$ = true; } | { $$ = false; } ; K_genvar_opt : K_genvar { $$ = true; } | { $$ = false; } ;
K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ;
K_static_opt : K_static { $$ = true; } | { $$ = false; } ; K_static_opt : K_static { $$ = true; } | { $$ = false; } ;
K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ;

View File

@ -2923,21 +2923,20 @@ void pform_makewire(const struct vlltype&li,
* constraints as those of tasks, so this works fine. Functions have * constraints as those of tasks, so this works fine. Functions have
* no output or inout ports. * no output or inout ports.
*/ */
vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc, static vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt, NetNet::PortType pt,
ivl_variable_type_t vtype, ivl_variable_type_t vtype,
bool signed_flag, bool signed_flag,
list<pform_range_t>*range, list<pform_range_t>*range,
list<perm_string>*names, list<pform_port_t>*ports,
bool isint) bool isint = false)
{ {
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(names); assert(ports);
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0); vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
for (list<perm_string>::iterator cur = names->begin() for (list<pform_port_t>::iterator cur = ports->begin()
; cur != names->end() ; ++ cur ) { ; cur != ports->end() ; ++ cur ) {
perm_string &name = cur->name;
perm_string name = *cur;
/* Look for a preexisting wire. If it exists, set the /* Look for a preexisting wire. If it exists, set the
port direction. If not, create it. */ port direction. If not, create it. */
@ -2961,6 +2960,11 @@ vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
curw->set_range(*range, SR_PORT); curw->set_range(*range, SR_PORT);
} }
if (cur->udims) {
if (pform_requires_sv(loc, "Task/function port with unpacked dimensions"))
curw->set_unpacked_idx(*cur->udims);
}
res->push_back(pform_tf_port_t(curw)); res->push_back(pform_tf_port_t(curw));
} }
@ -2972,15 +2976,16 @@ static vector<pform_tf_port_t>*do_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt, NetNet::PortType pt,
ivl_variable_type_t var_type, ivl_variable_type_t var_type,
data_type_t*data_type, data_type_t*data_type,
list<perm_string>*names) list<pform_port_t>*ports)
{ {
assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT);
assert(names); assert(ports);
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0); vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
for (list<perm_string>::iterator cur = names->begin() for (list<pform_port_t>::iterator cur = ports->begin()
; cur != names->end() ; ++cur) { ; cur != ports->end() ; ++cur) {
perm_string name = *cur; perm_string &name = cur->name;
PWire*curw = pform_get_wire_in_scope(name); PWire*curw = pform_get_wire_in_scope(name);
if (curw) { if (curw) {
curw->set_port_type(pt); curw->set_port_type(pt);
@ -2991,6 +2996,11 @@ static vector<pform_tf_port_t>*do_make_task_ports(const struct vlltype&loc,
pform_put_wire_in_scope(name, curw); pform_put_wire_in_scope(name, curw);
} }
if (cur->udims) {
if (pform_requires_sv(loc, "Task/function port with unpacked dimensions"))
curw->set_unpacked_idx(*cur->udims);
}
res->push_back(pform_tf_port_t(curw)); res->push_back(pform_tf_port_t(curw));
} }
return res; return res;
@ -2999,7 +3009,8 @@ static vector<pform_tf_port_t>*do_make_task_ports(const struct vlltype&loc,
vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc, vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt, NetNet::PortType pt,
data_type_t*vtype, data_type_t*vtype,
list<perm_string>*names) list<pform_port_t>*ports,
bool allow_implicit)
{ {
vector<pform_tf_port_t>*ret = NULL; vector<pform_tf_port_t>*ret = NULL;
std::list<pform_range_t>*unpacked_dims = NULL; std::list<pform_range_t>*unpacked_dims = NULL;
@ -3013,43 +3024,46 @@ vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
list<pform_range_t>*range_tmp = make_range_from_width(atype->type_code); list<pform_range_t>*range_tmp = make_range_from_width(atype->type_code);
ret = pform_make_task_ports(loc, pt, IVL_VT_BOOL, ret = pform_make_task_ports(loc, pt, IVL_VT_BOOL,
atype->signed_flag, atype->signed_flag,
range_tmp, names); range_tmp, ports);
} }
if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) { if (vector_type_t*vec_type = dynamic_cast<vector_type_t*> (vtype)) {
ret = pform_make_task_ports(loc, pt, vec_type->base_type, ivl_variable_type_t base_type = vec_type->base_type;
if (allow_implicit && vec_type->implicit_flag)
base_type = IVL_VT_NO_TYPE;
ret = pform_make_task_ports(loc, pt, base_type,
vec_type->signed_flag, vec_type->signed_flag,
copy_range(vec_type->pdims.get()), copy_range(vec_type->pdims.get()),
names, vec_type->integer_flag); ports, vec_type->integer_flag);
} }
if (/*real_type_t*real_type = */ dynamic_cast<real_type_t*> (vtype)) { if (/*real_type_t*real_type = */ dynamic_cast<real_type_t*> (vtype)) {
ret = pform_make_task_ports(loc, pt, IVL_VT_REAL, ret = pform_make_task_ports(loc, pt, IVL_VT_REAL,
true, 0, names); true, 0, ports);
} }
if (dynamic_cast<string_type_t*> (vtype)) { if (dynamic_cast<string_type_t*> (vtype)) {
ret = pform_make_task_ports(loc, pt, IVL_VT_STRING, ret = do_make_task_ports(loc, pt, IVL_VT_STRING, vtype, ports);
false, 0, names);
} }
if (class_type_t*class_type = dynamic_cast<class_type_t*> (vtype)) { if (class_type_t*class_type = dynamic_cast<class_type_t*> (vtype)) {
ret = do_make_task_ports(loc, pt, IVL_VT_CLASS, class_type, names); ret = do_make_task_ports(loc, pt, IVL_VT_CLASS, class_type, ports);
} }
if (! ret) { if (! ret) {
ret = do_make_task_ports(loc, pt, IVL_VT_NO_TYPE, vtype, names); ret = do_make_task_ports(loc, pt, IVL_VT_NO_TYPE, vtype, ports);
} }
if (unpacked_dims) { if (unpacked_dims) {
for (list<perm_string>::iterator cur = names->begin() for (list<pform_port_t>::iterator cur = ports->begin()
; cur != names->end() ; ++ cur ) { ; cur != ports->end() ; ++ cur ) {
PWire*wire = pform_get_wire_in_scope(*cur); PWire*wire = pform_get_wire_in_scope(cur->name);
wire->set_unpacked_idx(*unpacked_dims); wire->set_unpacked_idx(*unpacked_dims);
} }
} }
delete names; delete ports;
return ret; return ret;
} }

13
pform.h
View File

@ -493,20 +493,11 @@ extern void pform_make_pgassign_list(std::list<PExpr*>*alist,
struct str_pair_t str, struct str_pair_t str,
const char* fn, unsigned lineno); const char* fn, unsigned lineno);
/* Given a port type and a list of names, make a list of wires that
can be used as task port information. */
extern std::vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t vtype,
bool signed_flag,
std::list<pform_range_t>*range,
std::list<perm_string>*names,
bool isint = false);
extern std::vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc, extern std::vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt, NetNet::PortType pt,
data_type_t*vtype, data_type_t*vtype,
std::list<perm_string>*names); std::list<pform_port_t>*ports,
bool allow_implicit = false);
/* /*
* The parser uses this function to convert a unary * The parser uses this function to convert a unary

View File

@ -106,8 +106,8 @@ void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net)
if (pform_cur_class == 0) if (pform_cur_class == 0)
return; return;
list<perm_string>*this_name = new list<perm_string>; list<pform_port_t>*this_name = new list<pform_port_t>;
this_name->push_back(perm_string::literal(THIS_TOKEN)); this_name->push_back(pform_port_t(perm_string::literal(THIS_TOKEN), 0, 0));
vector<pform_tf_port_t>*this_port = pform_make_task_ports(loc, vector<pform_tf_port_t>*this_port = pform_make_task_ports(loc,
NetNet::PINPUT, NetNet::PINPUT,
pform_cur_class->type, pform_cur_class->type,