Parse SystemVerilog syntax for task calls.
Tasks call arguments may be dropped in favor of default values. Allow for that in the syntax. This requires a little handling of the non-SystemVerilog case during elaboration.
This commit is contained in:
parent
da743c3b2c
commit
dbc6f0cff2
12
Statement.h
12
Statement.h
|
|
@ -196,18 +196,6 @@ class PCallTask : public Statement {
|
|||
|
||||
const pform_name_t& path() const;
|
||||
|
||||
unsigned nparms() const { return parms_.size(); }
|
||||
|
||||
PExpr*&parm(unsigned idx)
|
||||
{ assert(idx < parms_.size());
|
||||
return parms_[idx];
|
||||
}
|
||||
|
||||
PExpr* parm(unsigned idx) const
|
||||
{ assert(idx < parms_.size());
|
||||
return parms_[idx];
|
||||
}
|
||||
|
||||
virtual void dump(ostream&out, unsigned ind) const;
|
||||
virtual NetProc* elaborate(Design*des, NetScope*scope) const;
|
||||
|
||||
|
|
|
|||
43
elaborate.cc
43
elaborate.cc
|
|
@ -2825,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
des->errors += 1;
|
||||
}
|
||||
|
||||
unsigned parm_count = nparms();
|
||||
unsigned parm_count = parms_.size();
|
||||
|
||||
/* Catch the special case that the system task has no
|
||||
parameters. The "()" string will be parsed as a single
|
||||
empty parameter, when we really mean no parameters at all. */
|
||||
if ((nparms() == 1) && (parm(0) == 0))
|
||||
if ((parm_count== 1) && (parms_[0] == 0))
|
||||
parm_count = 0;
|
||||
|
||||
svector<NetExpr*>eparms (parm_count);
|
||||
|
|
@ -2838,7 +2838,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
perm_string name = peek_tail_name(path_);
|
||||
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
PExpr*ex = parm(idx);
|
||||
PExpr*ex = parms_[idx];
|
||||
if (ex != 0) {
|
||||
eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex);
|
||||
} else {
|
||||
|
|
@ -2930,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
}
|
||||
assert(def);
|
||||
|
||||
if (nparms() != def->port_count()) {
|
||||
|
||||
unsigned parm_count = parms_.size();
|
||||
|
||||
// Handle special case that the definition has no arguments
|
||||
// but the parser found a simgle nul argument. This is an
|
||||
// argument of the parser allowing for the possibility of
|
||||
// default values for argumets: The parser cannot tell the
|
||||
// difference between "func()" and "func(<default>)".
|
||||
if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0)
|
||||
parm_count = 0;
|
||||
|
||||
if (parm_count != def->port_count()) {
|
||||
cerr << get_fileline() << ": error: Port count mismatch in call to ``"
|
||||
<< path_ << "''. Got " << nparms()
|
||||
<< path_ << "''. Got " << parm_count
|
||||
<< " ports, expecting " << def->port_count() << " ports." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
|
|
@ -2942,7 +2953,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
|
||||
/* Handle non-automatic tasks with no parameters specially. There is
|
||||
no need to make a sequential block to hold the generated code. */
|
||||
if ((nparms() == 0) && !task->is_auto()) {
|
||||
if ((parm_count == 0) && !task->is_auto()) {
|
||||
cur = new NetUTask(task);
|
||||
cur->set_line(*this);
|
||||
return cur;
|
||||
|
|
@ -2974,7 +2985,23 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
expression the r-value. We know by definition that the port
|
||||
is a reg type, so this elaboration is pretty obvious. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
|
||||
if (parms_[idx] == 0 && !gn_system_verilog()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Missing argument " << (idx+1)
|
||||
<< " of call to task." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parms_[idx] == 0) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Implicit arguments (arg " << (idx+1)
|
||||
<< ") not supported." << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
NetNet*port = def->port(idx);
|
||||
assert(port->port_type() != NetNet::NOT_A_PORT);
|
||||
|
|
@ -3015,7 +3042,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
|||
expression that can be a target to a procedural
|
||||
assignment, including a memory word. */
|
||||
|
||||
for (unsigned idx = 0 ; idx < nparms() ; idx += 1) {
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
|
||||
NetNet*port = def->port(idx);
|
||||
|
||||
|
|
|
|||
136
parse.y
136
parse.y
|
|
@ -513,8 +513,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
|||
%type <enum_type> enum_data_type
|
||||
|
||||
%type <wires> task_item task_item_list task_item_list_opt
|
||||
%type <wires> task_port_item tf_port_item tf_port_list tf_port_list_opt
|
||||
%type <wires> function_item function_item_list
|
||||
%type <wires> tf_port_declaration tf_port_item tf_port_list tf_port_list_opt
|
||||
%type <wires> function_item function_item_list function_item_list_opt
|
||||
|
||||
%type <named_pexpr> port_name parameter_value_byname
|
||||
%type <named_pexprs> port_name_list parameter_value_byname_list
|
||||
|
|
@ -719,6 +719,7 @@ class_item /* IEEE1800-2005: A.1.8 */
|
|||
|
||||
/* IEEE1800 A.1.8: class_constructor_declaration */
|
||||
: method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';'
|
||||
function_item_list_opt
|
||||
statement_or_null_list_opt
|
||||
K_endfunction endnew_opt
|
||||
{ yyerror(@3, "sorry: Class constructors not supported yet.");
|
||||
|
|
@ -730,6 +731,7 @@ class_item /* IEEE1800-2005: A.1.8 */
|
|||
be K_super ("this.new" makes little sense) but that would
|
||||
cause a conflict. */
|
||||
| method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';'
|
||||
function_item_list_opt
|
||||
implicit_class_handle '.' K_new '(' expression_list_with_nuls ')'
|
||||
statement_or_null_list_opt
|
||||
K_endfunction endnew_opt
|
||||
|
|
@ -1454,6 +1456,45 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
|||
;
|
||||
|
||||
|
||||
tf_port_declaration /* IEEE1800-2005: A.2.7 */
|
||||
: port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
|
||||
{ svector<PWire*>*tmp = pform_make_task_ports(@1, $1,
|
||||
$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 ';'
|
||||
{ list<index_component_t>*range_stub = make_range_from_width(integer_width);
|
||||
svector<PWire*>*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 ';'
|
||||
{ list<index_component_t>*range_stub = make_range_from_width(64);
|
||||
svector<PWire*>*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 ';'
|
||||
{ svector<PWire*>*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false,
|
||||
0, $3);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
|
||||
/* These rules for tf_port_item are slightly expanded from the
|
||||
strict rules in the LRM to help with LALR parsing.
|
||||
|
||||
|
|
@ -3071,12 +3112,20 @@ expr_primary
|
|||
|
||||
/* A function_item_list borrows the task_port_item run to match
|
||||
declarations of ports. We check later to make sure there are no
|
||||
output or inout ports actually used. */
|
||||
output or inout ports actually used.
|
||||
|
||||
The function_item is the same as tf_item_declaration. */
|
||||
function_item_list_opt
|
||||
: function_item_list { $$ = $1; }
|
||||
| { $$ = 0; }
|
||||
;
|
||||
|
||||
function_item_list
|
||||
: function_item
|
||||
{ $$ = $1; }
|
||||
| function_item_list function_item
|
||||
{ if ($1 && $2) {
|
||||
{ /* */
|
||||
if ($1 && $2) {
|
||||
svector<PWire*>*tmp = new svector<PWire*>(*$1, *$2);
|
||||
delete $1;
|
||||
delete $2;
|
||||
|
|
@ -3090,7 +3139,7 @@ function_item_list
|
|||
;
|
||||
|
||||
function_item
|
||||
: task_port_item
|
||||
: tf_port_declaration
|
||||
{ $$ = $1; }
|
||||
| block_item_decl
|
||||
{ $$ = 0; }
|
||||
|
|
@ -5700,7 +5749,7 @@ statement /* This is roughly statement_item in the LRM */
|
|||
$$ = tmp;
|
||||
}
|
||||
|
||||
| hierarchy_identifier '(' expression_list_proper ')' ';'
|
||||
| hierarchy_identifier '(' expression_list_with_nuls ')' ';'
|
||||
{ PCallTask*tmp = new PCallTask(*$1, *$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
|
|
@ -5708,7 +5757,7 @@ statement /* This is roughly statement_item in the LRM */
|
|||
$$ = tmp;
|
||||
}
|
||||
|
||||
| implicit_class_handle '.' hierarchy_identifier '(' expression_list_proper ')' ';'
|
||||
| implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';'
|
||||
{ PCallTask*tmp = new PCallTask(*$3, *$5);
|
||||
yyerror(@1, "sorry: Implicit class handle not supported in front of task names.");
|
||||
FILE_NAME(tmp, @1);
|
||||
|
|
@ -5717,28 +5766,6 @@ statement /* This is roughly statement_item in the LRM */
|
|||
$$ = tmp;
|
||||
}
|
||||
|
||||
/* NOTE: The standard doesn't really support an empty argument list
|
||||
between parentheses, but it seems natural, and people commonly
|
||||
want it. So accept it explicitly. */
|
||||
|
||||
| hierarchy_identifier '(' ')' ';'
|
||||
{ list<PExpr*>pt;
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
|
||||
| implicit_class_handle '.' hierarchy_identifier '(' ')' ';'
|
||||
{ list<PExpr*>pt;
|
||||
yyerror(@1, "sorry: Implicit class handle not supported in front of task names.");
|
||||
PCallTask*tmp = new PCallTask(*$3, pt);
|
||||
FILE_NAME(tmp, @3);
|
||||
delete $3;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| hierarchy_identifier ';'
|
||||
{ list<PExpr*>pt;
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
|
|
@ -5746,11 +5773,22 @@ statement /* This is roughly statement_item in the LRM */
|
|||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| hierarchy_identifier '(' error ')' ';'
|
||||
{ yyerror(@3, "error: Syntax error in task arguments.");
|
||||
list<PExpr*>pt;
|
||||
PCallTask*tmp = new PCallTask(*$1, pt);
|
||||
FILE_NAME(tmp, @1);
|
||||
delete $1;
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| error ';'
|
||||
{ yyerror(@2, "error: malformed statement");
|
||||
yyerrok;
|
||||
$$ = new PNoop;
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
compressed_statement
|
||||
|
|
@ -5841,45 +5879,7 @@ analog_statement
|
|||
other block items. */
|
||||
task_item
|
||||
: block_item_decl { $$ = new svector<PWire*>(0); }
|
||||
| task_port_item { $$ = $1; }
|
||||
;
|
||||
|
||||
task_port_item
|
||||
: port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
|
||||
{ svector<PWire*>*tmp = pform_make_task_ports(@1, $1,
|
||||
$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 ';'
|
||||
{ list<index_component_t>*range_stub = make_range_from_width(integer_width);
|
||||
svector<PWire*>*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 ';'
|
||||
{ list<index_component_t>*range_stub = make_range_from_width(64);
|
||||
svector<PWire*>*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 ';'
|
||||
{ svector<PWire*>*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false,
|
||||
0, $3);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
||||
| tf_port_declaration { $$ = $1; }
|
||||
;
|
||||
|
||||
task_item_list
|
||||
|
|
|
|||
Loading…
Reference in New Issue