diff --git a/elab_expr.cc b/elab_expr.cc index c88663e81..5f3183ae0 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -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 " diff --git a/elaborate.cc b/elaborate.cc index 1011d0430..09e0f38aa 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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; diff --git a/eval_tree.cc b/eval_tree.cc index ebd6218a2..1fc452bfe 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -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 diff --git a/net_func_eval.cc b/net_func_eval.cc index 039f20e54..a9d281754 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -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(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&) const +{ + disable = target_; + return true; +} + +bool NetSTask::evaluate_function(const LineInfo&, + map&) const +{ + // system tasks within a constant function are ignored + return true; +} + bool NetWhile::evaluate_function(const LineInfo&loc, map&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); diff --git a/net_scope.cc b/net_scope.cc index eed6af6b8..4147f1362 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -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; diff --git a/netlist.h b/netlist.h index 0ae436754..b0628cc6e 100644 --- a/netlist.h +++ b/netlist.h @@ -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 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&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&ctx) const; + virtual NexusSet* nex_input(bool rem_out = true); virtual void nex_output(NexusSet&); virtual bool emit_proc(struct target_t*) const;