Support disable statements and system task calls in constant functions.

This patch implements the evaluate_function method for the NetDisable
and NetSTask classes. It also makes the checks for a function being
constant work when the function contains nested scopes (named blocks).
This commit is contained in:
Martin Whitaker 2013-03-09 12:24:50 +00:00 committed by Stephen Williams
parent 09f90ab4e1
commit 1bcd3a97ad
6 changed files with 60 additions and 7 deletions

View File

@ -2767,7 +2767,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
des->errors += 1;
return 0;
}
if (net->scope() != scope) {
if (net->scope()->type() == NetScope::MODULE) {
if (scope->need_const_func()) {
cerr << get_fileline() << ": error: A reference to a "
"non-local wire or reg (`" << path_ << "') is "

View File

@ -2784,6 +2784,20 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
cur->append(tmp);
}
// Update flags in parent scope.
if (!nscope->is_const_func())
scope->is_const_func(false);
if (nscope->calls_sys_task())
scope->calls_sys_task(true);
if (!wires.empty()) {
if (scope->need_const_func()) {
cerr << get_fileline() << ": sorry: Block variables inside "
"a constant function are not yet supported." << endl;
}
scope->is_const_func(false);
}
cur->set_line(*this);
return cur;
}
@ -3010,6 +3024,8 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
return noop;
}
scope->calls_sys_task(true);
NetSTask*cur = new NetSTask(name, def_sfunc_as_task, eparms);
cur->set_line(*this);
return cur;

View File

@ -1982,7 +1982,7 @@ NetExpr* NetEUFunc::eval_tree()
{
// If we know the function cannot be evaluated as a constant,
// give up now.
if (!func()->is_const_func())
if (!func()->is_const_func() || (func()->calls_sys_task() && !need_const_))
return 0;
// If we neither want nor need to evaluate the function at

View File

@ -25,6 +25,14 @@
using namespace std;
/*
* We only evaluate one function at a time, so to support the disable
* statement, we just need to record the target block and then early
* terminate each enclosing block or loop statement until we get back
* to the target block.
*/
static const NetScope*disable = 0;
static NetExpr* fix_assign_value(const NetNet*lhs, NetExpr*rhs)
{
NetEConst*ce = dynamic_cast<NetEConst*>(rhs);
@ -221,7 +229,9 @@ bool NetBlock::evaluate_function(const LineInfo&loc,
cur = cur->next_;
bool cur_flag = cur->evaluate_function(loc, context_map);
flag = flag && cur_flag;
} while (cur != last_);
} while (cur != last_ && !disable);
if (disable == subscope_) disable = 0;
return flag;
}
@ -247,6 +257,20 @@ bool NetCondit::evaluate_function(const LineInfo&loc,
return (else_ == 0) || else_->evaluate_function(loc, context_map);
}
bool NetDisable::evaluate_function(const LineInfo&,
map<perm_string,NetExpr*>&) const
{
disable = target_;
return true;
}
bool NetSTask::evaluate_function(const LineInfo&,
map<perm_string,NetExpr*>&) const
{
// system tasks within a constant function are ignored
return true;
}
bool NetWhile::evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&context_map) const
{
@ -257,7 +281,7 @@ bool NetWhile::evaluate_function(const LineInfo&loc,
<< "Start loop" << endl;
}
while (flag) {
while (flag && !disable) {
// Evaluate the condition expression to try and get the
// condition for the loop.
NetExpr*cond = cond_->evaluate_function(loc, context_map);

View File

@ -44,19 +44,22 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bo
{
events_ = 0;
lcounter_ = 0;
need_const_func_ = false;
is_const_func_ = false;
is_auto_ = false;
is_cell_ = false;
calls_stask_ = false;
in_final_ = false;
if (up) {
need_const_func_ = up->need_const_func_;
is_const_func_ = up->is_const_func_;
time_unit_ = up->time_unit();
time_prec_ = up->time_precision();
time_from_timescale_ = up->time_from_timescale();
// Need to check for duplicate names?
up_->children_[name_] = this;
} else {
need_const_func_ = false;
is_const_func_ = false;
time_unit_ = 0;
time_prec_ = 0;
time_from_timescale_ = false;

View File

@ -909,6 +909,10 @@ class NetScope : public Attrib {
void is_cell(bool is_cell__) { is_cell_ = is_cell__; };
bool is_cell() const { return is_cell_; };
/* Is there a call to a system task in this scope. */
void calls_sys_task(bool calls_stask__) { calls_stask_ = calls_stask__; };
bool calls_sys_task() const { return calls_stask_; };
/* Is this scope elaborating a final procedure? */
void in_final(bool in_final__) { in_final_ = in_final__; };
bool in_final() const { return in_final_; };
@ -1096,7 +1100,7 @@ class NetScope : public Attrib {
map<hname_t,NetScope*> children_;
unsigned lcounter_;
bool need_const_func_, is_const_func_, is_auto_, is_cell_;
bool need_const_func_, is_const_func_, is_auto_, is_cell_, calls_stask_;
/* Final procedures sets this to notify statements that
they are part of a final procedure. */
@ -2827,6 +2831,9 @@ class NetDisable : public NetProc {
const NetScope*target() const;
bool evaluate_function(const LineInfo&loc,
std::map<perm_string,NetExpr*>&ctx) const;
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
@ -3239,6 +3246,9 @@ class NetSTask : public NetProc {
const NetExpr* parm(unsigned idx) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,NetExpr*>&ctx) const;
virtual NexusSet* nex_input(bool rem_out = true);
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;