Elaborate task methods as tasks with this arguments.
Generate the code to treat "this" as a hidden argument and have elaborate assign to that argument.
This commit is contained in:
parent
fb23493a98
commit
d0f2a9e961
|
|
@ -214,6 +214,9 @@ class PCallTask : public Statement {
|
||||||
NetProc*elaborate_method_(Design*des, NetScope*scope) const;
|
NetProc*elaborate_method_(Design*des, NetScope*scope) const;
|
||||||
NetProc*elaborate_function_(Design*des, NetScope*scope) const;
|
NetProc*elaborate_function_(Design*des, NetScope*scope) const;
|
||||||
|
|
||||||
|
NetProc*elaborate_build_call_(Design*des, NetScope*scope,
|
||||||
|
NetScope*task, NetExpr*use_this) const;
|
||||||
|
|
||||||
pform_name_t path_;
|
pform_name_t path_;
|
||||||
vector<PExpr*> parms_;
|
vector<PExpr*> parms_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
192
elaborate.cc
192
elaborate.cc
|
|
@ -3112,8 +3112,14 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
|
|
||||||
unsigned parm_count = parms_.size();
|
unsigned parm_count = parms_.size();
|
||||||
|
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << "PCallTask::elaborate_usr: "
|
||||||
|
<< "Elaborate call to task " << task->basename()
|
||||||
|
<< " width " << parm_count << " arguments." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle special case that the definition has no arguments
|
// Handle special case that the definition has no arguments
|
||||||
// but the parser found a simgle nul argument. This is an
|
// but the parser found a single nul argument. This is an
|
||||||
// argument of the parser allowing for the possibility of
|
// argument of the parser allowing for the possibility of
|
||||||
// default values for argumets: The parser cannot tell the
|
// default values for argumets: The parser cannot tell the
|
||||||
// difference between "func()" and "func(<default>)".
|
// difference between "func()" and "func(<default>)".
|
||||||
|
|
@ -3128,16 +3134,100 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetUTask*cur;
|
|
||||||
|
|
||||||
/* Handle non-automatic tasks with no parameters specially. There is
|
/* Handle non-automatic tasks with no parameters specially. There is
|
||||||
no need to make a sequential block to hold the generated code. */
|
no need to make a sequential block to hold the generated code. */
|
||||||
if ((parm_count == 0) && !task->is_auto()) {
|
if ((parm_count == 0) && !task->is_auto()) {
|
||||||
cur = new NetUTask(task);
|
NetUTask*cur = new NetUTask(task);
|
||||||
cur->set_line(*this);
|
cur->set_line(*this);
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return elaborate_build_call_(des, scope, task, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
pform_name_t use_path = path_;
|
||||||
|
perm_string method_name = peek_tail_name(use_path);
|
||||||
|
use_path.pop_back();
|
||||||
|
|
||||||
|
NetNet *net;
|
||||||
|
const NetExpr *par;
|
||||||
|
NetEvent *eve;
|
||||||
|
const NetExpr *ex1, *ex2;
|
||||||
|
|
||||||
|
// There is no signal to search for so this cannot be a method.
|
||||||
|
if (use_path.empty()) return 0;
|
||||||
|
|
||||||
|
symbol_search(this, des, scope, use_path,
|
||||||
|
net, par, eve, ex1, ex2);
|
||||||
|
|
||||||
|
if (net == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Is this a delete method for dynamic arrays?
|
||||||
|
if (net->darray_type() && method_name=="delete") {
|
||||||
|
NetESignal*sig = new NetESignal(net);
|
||||||
|
|
||||||
|
vector<NetExpr*> argv (1);
|
||||||
|
argv[0] = sig;
|
||||||
|
|
||||||
|
NetSTask*sys = new NetSTask("$ivl_darray_method$delete",
|
||||||
|
IVL_SFUNC_AS_TASK_IGNORE, argv);
|
||||||
|
sys->set_line(*this);
|
||||||
|
return sys;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netclass_t*class_type = net->class_type()) {
|
||||||
|
NetScope*task = class_type->method_from_name(method_name);
|
||||||
|
if (task == 0) {
|
||||||
|
cerr << get_fileline() << ": internal error: "
|
||||||
|
<< "Can't find task " << method_name
|
||||||
|
<< " in class " << class_type->get_name() << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PCallTask::elaborate_method_: "
|
||||||
|
<< "Elaborate " << class_type->get_name()
|
||||||
|
<< " method " << task->basename() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetESignal*use_this = new NetESignal(net);
|
||||||
|
use_this->set_line(*this);
|
||||||
|
|
||||||
|
return elaborate_build_call_(des, scope, task, use_this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
NetFuncDef*func = des->find_function(scope, path_);
|
||||||
|
// This is not a function, so this task call cannot be a function
|
||||||
|
// call with a missing return assignment.
|
||||||
|
if (! func) return 0;
|
||||||
|
|
||||||
|
// HERE: Should this be an assign to a dummy variable or something else?
|
||||||
|
cerr << get_fileline() << ": sorry: Icarus cannot currently call "
|
||||||
|
"functions like a tasks." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetProc* PCallTask::elaborate_build_call_(Design*des, NetScope*scope,
|
||||||
|
NetScope*task, NetExpr*use_this) const
|
||||||
|
{
|
||||||
|
NetTaskDef*def = task->task_def();
|
||||||
|
|
||||||
|
/* The caller has checked the parms_ size to make sure it
|
||||||
|
matches the task definition, so we can just use the task
|
||||||
|
definition to get the parm_count. */
|
||||||
|
|
||||||
|
unsigned parm_count = def->port_count();
|
||||||
|
|
||||||
NetBlock*block = new NetBlock(NetBlock::SEQU, 0);
|
NetBlock*block = new NetBlock(NetBlock::SEQU, 0);
|
||||||
block->set_line(*this);
|
block->set_line(*this);
|
||||||
|
|
||||||
|
|
@ -3152,21 +3242,40 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
|
|
||||||
/* If this is an automatic task, generate a statement to
|
/* If this is an automatic task, generate a statement to
|
||||||
allocate the local storage. */
|
allocate the local storage. */
|
||||||
|
|
||||||
if (task->is_auto()) {
|
if (task->is_auto()) {
|
||||||
NetAlloc*ap = new NetAlloc(task);
|
NetAlloc*ap = new NetAlloc(task);
|
||||||
ap->set_line(*this);
|
ap->set_line(*this);
|
||||||
block->append(ap);
|
block->append(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this is a method call, then the use_this pointer will
|
||||||
|
have an expression for the "this" argument. The "this"
|
||||||
|
argument is the first argument of any method, so emit it
|
||||||
|
here. */
|
||||||
|
|
||||||
|
if (use_this) {
|
||||||
|
ivl_assert(*this, def->port_count() >= 1);
|
||||||
|
NetNet*port = def->port(0);
|
||||||
|
ivl_assert(*this, port->port_type()==NetNet::PINPUT);
|
||||||
|
|
||||||
|
NetAssign_*lv = new NetAssign_(port);
|
||||||
|
NetAssign*pr = new NetAssign(lv, use_this);
|
||||||
|
pr->set_line(*this);
|
||||||
|
block->append(pr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate assignment statement statements for the input and
|
/* Generate assignment statement statements for the input and
|
||||||
INOUT ports of the task. These are managed by writing
|
INOUT ports of the task. These are managed by writing
|
||||||
assignments with the task port the l-value and the passed
|
assignments with the task port the l-value and the passed
|
||||||
expression the r-value. We know by definition that the port
|
expression the r-value. We know by definition that the port
|
||||||
is a reg type, so this elaboration is pretty obvious. */
|
is a reg type, so this elaboration is pretty obvious. */
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
for (unsigned idx = use_this?1:0 ; idx < parm_count ; idx += 1) {
|
||||||
|
|
||||||
if (parms_[idx] == 0 && !gn_system_verilog()) {
|
size_t parms_idx = use_this? idx-1 : idx;
|
||||||
|
|
||||||
|
if (parms_[parms_idx] == 0 && !gn_system_verilog()) {
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
<< "Missing argument " << (idx+1)
|
<< "Missing argument " << (idx+1)
|
||||||
<< " of call to task." << endl;
|
<< " of call to task." << endl;
|
||||||
|
|
@ -3174,7 +3283,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parms_[idx] == 0) {
|
if (parms_[parms_idx] == 0) {
|
||||||
cerr << get_fileline() << ": sorry: "
|
cerr << get_fileline() << ": sorry: "
|
||||||
<< "Implicit arguments (arg " << (idx+1)
|
<< "Implicit arguments (arg " << (idx+1)
|
||||||
<< ") not supported." << endl;
|
<< ") not supported." << endl;
|
||||||
|
|
@ -3191,7 +3300,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
unsigned wid = count_lval_width(lv);
|
unsigned wid = count_lval_width(lv);
|
||||||
ivl_variable_type_t lv_type = lv->expr_type();
|
ivl_variable_type_t lv_type = lv->expr_type();
|
||||||
|
|
||||||
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]);
|
NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [parms_idx]);
|
||||||
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
|
if (NetEEvent*evt = dynamic_cast<NetEEvent*> (rv)) {
|
||||||
cerr << evt->get_fileline() << ": error: An event '"
|
cerr << evt->get_fileline() << ": error: An event '"
|
||||||
<< evt->event()->name() << "' can not be a user "
|
<< evt->event()->name() << "' can not be a user "
|
||||||
|
|
@ -3206,11 +3315,10 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the task call proper... */
|
/* Generate the task call proper... */
|
||||||
cur = new NetUTask(task);
|
NetUTask*cur = new NetUTask(task);
|
||||||
cur->set_line(*this);
|
cur->set_line(*this);
|
||||||
block->append(cur);
|
block->append(cur);
|
||||||
|
|
||||||
|
|
||||||
/* Generate assignment statements for the output and INOUT
|
/* Generate assignment statements for the output and INOUT
|
||||||
ports of the task. The l-value in this case is the
|
ports of the task. The l-value in this case is the
|
||||||
expression passed as a parameter, and the r-value is the
|
expression passed as a parameter, and the r-value is the
|
||||||
|
|
@ -3293,70 +3401,6 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope) const
|
|
||||||
{
|
|
||||||
pform_name_t use_path = path_;
|
|
||||||
perm_string method_name = peek_tail_name(use_path);
|
|
||||||
use_path.pop_back();
|
|
||||||
|
|
||||||
NetNet *net;
|
|
||||||
const NetExpr *par;
|
|
||||||
NetEvent *eve;
|
|
||||||
const NetExpr *ex1, *ex2;
|
|
||||||
|
|
||||||
// There is no signal to search for so this cannot be a method.
|
|
||||||
if (use_path.empty()) return 0;
|
|
||||||
|
|
||||||
symbol_search(this, des, scope, use_path,
|
|
||||||
net, par, eve, ex1, ex2);
|
|
||||||
|
|
||||||
if (net == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// Is this a delete method for dynamic arrays?
|
|
||||||
if (net->darray_type() && method_name=="delete") {
|
|
||||||
NetESignal*sig = new NetESignal(net);
|
|
||||||
|
|
||||||
vector<NetExpr*> argv (1);
|
|
||||||
argv[0] = sig;
|
|
||||||
|
|
||||||
NetSTask*sys = new NetSTask("$ivl_darray_method$delete",
|
|
||||||
IVL_SFUNC_AS_TASK_IGNORE, argv);
|
|
||||||
sys->set_line(*this);
|
|
||||||
return sys;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (netclass_t*class_type = net->class_type()) {
|
|
||||||
NetScope*task = class_type->method_from_name(method_name);
|
|
||||||
if (task == 0) {
|
|
||||||
cerr << get_fileline() << ": XXXXX: "
|
|
||||||
<< "Can't find task " << method_name
|
|
||||||
<< " in class " << class_type->get_name() << endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetUTask*tmp = new NetUTask(task);
|
|
||||||
tmp->set_line(*this);
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetProc* PCallTask::elaborate_function_(Design*des, NetScope*scope) const
|
|
||||||
{
|
|
||||||
NetFuncDef*func = des->find_function(scope, path_);
|
|
||||||
// This is not a function, so this task call cannot be a function
|
|
||||||
// call with a missing return assignment.
|
|
||||||
if (! func) return 0;
|
|
||||||
|
|
||||||
// HERE: Should this be an assign to a dummy variable or something else?
|
|
||||||
cerr << get_fileline() << ": sorry: Icarus cannot currently call "
|
|
||||||
"functions like a tasks." << endl;
|
|
||||||
des->errors += 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Elaborate a procedural continuous assign. This really looks very
|
* Elaborate a procedural continuous assign. This really looks very
|
||||||
* much like other procedural assignments, at this point, but there
|
* much like other procedural assignments, at this point, but there
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue