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,
&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_)) {
// The pform gives us a parray_type_t for packed arrays
// 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);
vec->set_signed(get_signed());
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_var2 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
test_inc_dec 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_var2 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
vhdl_elab_range 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 <flag> signing unsigned_signed_opt signed_unsigned_opt
%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 <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%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(); }
;
/* 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 */
: K_signed { $$ = true; }
| K_unsigned { $$ = false; }
@ -2355,50 +2348,9 @@ task_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 ';'
{ std::vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1,
$2 ? IVL_VT_LOGIC :
IVL_VT_NO_TYPE,
$3, $4, $5);
$$ = tmp;
: port_direction data_type_or_implicit list_of_port_identifiers ';'
{ $$ = pform_make_task_ports(@1, $1, $2, $3, true);
}
/* 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;
if ((use_port_type == NetNet::PIMPLICIT) && (gn_system_verilog() || ($2 == 0)))
use_port_type = port_declaration_context.port_type;
perm_string name = lex_strings.make($3);
list<perm_string>* ilist = list_from_identifier($3);
list<pform_port_t>* port_list = make_port_list($3, $4, 0);
if (use_port_type == NetNet::PIMPLICIT) {
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,
port_declaration_context.data_type,
ilist);
port_list);
} else {
// Otherwise, the decorations for this identifier
@ -2445,12 +2396,7 @@ tf_port_item /* IEEE1800-2005: A.2.7 */
FILE_NAME($2, @3);
}
port_declaration_context.data_type = $2;
tmp = pform_make_task_ports(@3, use_port_type, $2, ilist);
}
if ($4 != 0) {
if (pform_requires_sv(@4, "Task/function port with unpacked dimensions")) {
pform_set_reg_idx(name, $4);
}
tmp = pform_make_task_ports(@3, use_port_type, $2, port_list);
}
$$ = tmp;
@ -7249,6 +7195,5 @@ unique_priority
collect those rules here. */
K_genvar_opt : K_genvar { $$ = true; } | { $$ = false; } ;
K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ;
K_static_opt : K_static { $$ = 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
* no output or inout ports.
*/
vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t vtype,
bool signed_flag,
list<pform_range_t>*range,
list<perm_string>*names,
bool isint)
static vector<pform_tf_port_t>*pform_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t vtype,
bool signed_flag,
list<pform_range_t>*range,
list<pform_port_t>*ports,
bool isint = false)
{
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);
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
perm_string name = *cur;
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
perm_string &name = cur->name;
/* Look for a preexisting wire. If it exists, set the
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);
}
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));
}
@ -2972,15 +2976,16 @@ static vector<pform_tf_port_t>*do_make_task_ports(const struct vlltype&loc,
NetNet::PortType pt,
ivl_variable_type_t var_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(names);
assert(ports);
vector<pform_tf_port_t>*res = new vector<pform_tf_port_t>(0);
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++cur) {
perm_string name = *cur;
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++cur) {
perm_string &name = cur->name;
PWire*curw = pform_get_wire_in_scope(name);
if (curw) {
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);
}
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));
}
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,
NetNet::PortType pt,
data_type_t*vtype,
list<perm_string>*names)
list<pform_port_t>*ports,
bool allow_implicit)
{
vector<pform_tf_port_t>*ret = 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);
ret = pform_make_task_ports(loc, pt, IVL_VT_BOOL,
atype->signed_flag,
range_tmp, names);
range_tmp, ports);
}
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,
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)) {
ret = pform_make_task_ports(loc, pt, IVL_VT_REAL,
true, 0, names);
true, 0, ports);
}
if (dynamic_cast<string_type_t*> (vtype)) {
ret = pform_make_task_ports(loc, pt, IVL_VT_STRING,
false, 0, names);
ret = do_make_task_ports(loc, pt, IVL_VT_STRING, vtype, ports);
}
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) {
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) {
for (list<perm_string>::iterator cur = names->begin()
; cur != names->end() ; ++ cur ) {
PWire*wire = pform_get_wire_in_scope(*cur);
for (list<pform_port_t>::iterator cur = ports->begin()
; cur != ports->end() ; ++ cur ) {
PWire*wire = pform_get_wire_in_scope(cur->name);
wire->set_unpacked_idx(*unpacked_dims);
}
}
delete names;
delete ports;
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,
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,
NetNet::PortType pt,
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

View File

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