Support compile-time evaluation of named blocks.

This commit is contained in:
Stephen Williams 2013-06-05 19:28:51 -07:00
parent af304fea65
commit 3446455055
3 changed files with 73 additions and 29 deletions

View File

@ -2793,14 +2793,6 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
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;
}

View File

@ -215,9 +215,15 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
map<perm_string,LocalVar>::iterator ptr = context_map.find(lval->name());
ivl_assert(*this, ptr != context_map.end());
LocalVar*var = & ptr->second;
while (var->nwords == -1) {
assert(var->ref);
var = var->ref;
}
NetExpr*old_lval;
unsigned word = 0;
if (ptr->second.nwords > 0) {
int word = 0;
if (var->nwords > 0) {
NetExpr*word_result = lval->word()->evaluate_function(loc, context_map);
if (word_result == 0) {
delete rval_result;
@ -232,12 +238,13 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
word = word_const->value().as_long();
if (word >= ptr->second.nwords)
if (word >= var->nwords)
return true;
old_lval = ptr->second.array[word];
old_lval = var->array[word];
} else {
old_lval = ptr->second.value;
assert(var->nwords == 0);
old_lval = var->value;
}
if (const NetExpr*base_expr = lval->get_base()) {
@ -283,10 +290,12 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
<< lval->name() << " = " << *rval_result << endl;
}
if (ptr->second.nwords > 0)
ptr->second.array[word] = rval_result;
else
ptr->second.value = rval_result;
if (var->nwords > 0) {
var->array[word] = rval_result;
} else {
assert(var->nwords == 0);
var->value = rval_result;
}
return true;
}
@ -336,23 +345,58 @@ bool NetAssign::evaluate_function(const LineInfo&loc,
bool NetBlock::evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&context_map) const
{
if (last_ == 0) return true;
// If we need to make a local scope, then this context map
// will be filled in and used for statements within this block.
map<perm_string,LocalVar>local_context_map;
bool use_local_context_map = false;
if (subscope_!=0) {
// First, copy the containing scope symbols into the new
// scope as references.
for (map<perm_string,LocalVar>::iterator cur = context_map.begin()
; cur != context_map.end() ; ++cur) {
LocalVar&cur_var = local_context_map[cur->first];
cur_var.nwords = -1;
if (cur->second.nwords == -1)
cur_var.ref = cur->second.ref;
else
cur_var.ref = &cur->second;
}
// Now collect the new locals.
subscope_->evaluate_function_find_locals(loc, local_context_map);
use_local_context_map = true;
}
// Now use the local context map if there is any local
// context, or the containing context map.
map<perm_string,LocalVar>&use_context_map = use_local_context_map? local_context_map : context_map;
bool flag = true;
NetProc*cur = last_;
if (cur == 0) return true;
do {
cur = cur->next_;
bool cur_flag = cur->evaluate_function(loc, context_map);
if (debug_eval_tree) {
cerr << get_fileline() << ": NetBlock::evaluate_function: "
<< "Execute statement (" << typeid(*cur).name()
<< ") at " << cur->get_fileline() << "." << endl;
}
bool cur_flag = cur->evaluate_function(loc, use_context_map);
flag = flag && cur_flag;
} while (cur != last_ && !disable);
if (disable == subscope_) disable = 0;
if (debug_eval_tree) {
cerr << get_fileline() << ": NetBlock::evaluate_function: "
<< "flag=" << (flag?"true":"false") << endl;
<< "subscope_=" << subscope_
<< ", disable=" << disable
<< ", flag=" << (flag?"true":"false") << endl;
}
if (disable == subscope_) disable = 0;
return flag;
}
@ -731,8 +775,15 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
return 0;
}
// Follow indirect references to the actual variable.
LocalVar*var = & ptr->second;
while (var->nwords == -1) {
assert(var->ref);
var = var->ref;
}
NetExpr*value = 0;
if (ptr->second.nwords > 0) {
if (var->nwords > 0) {
ivl_assert(loc, word_);
NetExpr*word_result = word_->evaluate_function(loc, context_map);
if (word_result == 0)
@ -741,12 +792,12 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
NetEConst*word_const = dynamic_cast<NetEConst*>(word_result);
ivl_assert(loc, word_const);
unsigned word = word_const->value().as_long();
int word = word_const->value().as_long();
if (word_const->value().is_defined() && (word < ptr->second.nwords))
value = ptr->second.array[word];
if (word_const->value().is_defined() && (word < var->nwords))
value = var->array[word];
} else {
value = ptr->second.value;
value = var->value;
}
if (value == 0) {

View File

@ -760,10 +760,11 @@ class NetNet : public NetObj, public PortType {
* evaluating constant user functions.
*/
struct LocalVar {
unsigned nwords; // zero for a simple variable
int nwords; // zero for a simple variable, -1 for reference
union {
NetExpr* value; // a simple variable
NetExpr** array; // an array variable
LocalVar* ref; // A reference to a previous scope
};
};