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:
Stephen Williams 2012-03-10 09:50:41 -08:00
parent da743c3b2c
commit dbc6f0cff2
3 changed files with 121 additions and 106 deletions

View File

@ -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;

View File

@ -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
View File

@ -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