Merge pull request #623 from larsclausen/task-ports-sv
Support SystemVerilog non-ansi task/function port declarations
This commit is contained in:
commit
978717f914
19
elab_sig.cc
19
elab_sig.cc
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
67
parse.y
|
|
@ -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; } ;
|
||||
|
|
|
|||
74
pform.cc
74
pform.cc
|
|
@ -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
13
pform.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue