/* * Copyright (c) 2012-2018 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "netlist.h" # include "netmisc.h" # include "compiler.h" # include # include "ivl_assert.h" #if __cplusplus < 201103L #define unique_ptr auto_ptr #endif 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); if (ce == 0) return rhs; unsigned lhs_width = lhs->vector_width(); unsigned rhs_width = rhs->expr_width(); if (rhs_width < lhs_width) { rhs = pad_to_width(rhs, lhs_width, *rhs); } else if (rhs_width > lhs_width) { verinum value(ce->value(), lhs_width); ce = new NetEConst(value); ce->set_line(*rhs); delete rhs; rhs = ce; } rhs->cast_signed(lhs->get_signed()); return rhs; } NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector&args) const { // Make the context map. map::iterator ptr; mapcontext_map; if (debug_eval_tree) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Evaluate function " << scope()->basename() << endl; } // Put the return value into the map... LocalVar&return_var = context_map[scope()->basename()]; return_var.nwords = 0; return_var.value = 0; // Load the input ports into the map... ivl_assert(loc, port_count() == args.size()); for (size_t idx = 0 ; idx < port_count() ; idx += 1) { const NetNet*pnet = port(idx); perm_string aname = pnet->name(); LocalVar&input_var = context_map[aname]; input_var.nwords = 0; input_var.value = fix_assign_value(pnet, args[idx]); if (debug_eval_tree) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << " input " << aname << " = " << *args[idx] << endl; } } // Ask the scope to collect definitions for local values. This // fills in the context_map with local variables held by the scope. scope()->evaluate_function_find_locals(loc, context_map); // Execute any variable initialization statements. if (const NetProc*init_proc = scope()->var_init()) init_proc->evaluate_function(loc, context_map); if (debug_eval_tree && proc_==0) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Function " << scope_path(scope()) << " has no statement?" << endl; } // Perform the evaluation. Note that if there were errors // when compiling the function definition, we may not have // a valid statement. bool flag = proc_ && proc_->evaluate_function(loc, context_map); if (debug_eval_tree && !flag) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Cannot evaluate " << scope_path(scope()) << "." << endl; } // Extract the result... ptr = context_map.find(scope()->basename()); NetExpr*res = ptr->second.value; context_map.erase(ptr); // Cleanup the rest of the context. for (ptr = context_map.begin() ; ptr != context_map.end() ; ++ptr) { unsigned nwords = ptr->second.nwords; if (nwords > 0) { NetExpr**array = ptr->second.array; for (unsigned idx = 0 ; idx < nwords ; idx += 1) { delete array[idx]; } delete [] ptr->second.array; } else { delete ptr->second.value; } } if (disable) { if (debug_eval_tree) cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "disable of " << scope_path(disable) << " trapped in function " << scope_path(scope()) << "." << endl; ivl_assert(loc, disable==scope()); disable = 0; } // Done. if (flag) { if (debug_eval_tree) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Evaluated to "; if (res) cerr << *res; else cerr << ""; cerr << endl; } return res; } if (debug_eval_tree) { cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Evaluation failed." << endl; } delete res; return 0; } void NetScope::evaluate_function_find_locals(const LineInfo&loc, map&context_map) const { for (map::const_iterator cur = signals_map_.begin() ; cur != signals_map_.end() ; ++cur) { const NetNet*tmp = cur->second; // Skip ports, which are handled elsewhere. if (tmp->port_type() != NetNet::NOT_A_PORT) continue; unsigned nwords = 0; if (tmp->unpacked_dimensions() > 0) nwords = tmp->unpacked_count(); LocalVar&local_var = context_map[tmp->name()]; local_var.nwords = nwords; if (nwords > 0) { NetExpr**array = new NetExpr*[nwords]; for (unsigned idx = 0 ; idx < nwords ; idx += 1) { array[idx] = 0; } local_var.array = array; } else { local_var.value = 0; } if (debug_eval_tree) { cerr << loc.get_fileline() << ": debug: " << " (local) " << tmp->name() << (nwords > 0 ? "[]" : "") << endl; } } } NetExpr* NetExpr::evaluate_function(const LineInfo&, map&) const { cerr << get_fileline() << ": sorry: I don't know how to evaluate this expression at compile time." << endl; cerr << get_fileline() << ": : Expression type:" << typeid(*this).name() << endl; return 0; } bool NetProc::evaluate_function(const LineInfo&, map&) const { cerr << get_fileline() << ": sorry: I don't know how to evaluate this statement at compile time." << endl; cerr << get_fileline() << ": : Statement type:" << typeid(*this).name() << endl; return false; } void NetAssign::eval_func_lval_op_real_(const LineInfo&loc, verireal&lv, verireal&rv) const { switch (op_) { case '+': lv = lv + rv; break; case '-': lv = lv - rv; break; case '*': lv = lv * rv; break; case '/': lv = lv / rv; break; case '%': lv = lv % rv; break; default: cerr << "Illegal assignment operator: " << human_readable_op(op_) << endl; ivl_assert(loc, 0); } } void NetAssign::eval_func_lval_op_(const LineInfo&loc, verinum&lv, verinum&rv) const { unsigned lv_width = lv.len(); bool lv_sign = lv.has_sign(); switch (op_) { case 'l': case 'R': // The left operand is self-determined. break; case 'r': // The left operand is self-determined, but we need to // cast it to unsigned to get a logical shift. lv.has_sign(false); break; default: // The left operand must be cast to the expression type/size lv.has_sign(rv.has_sign()); lv = cast_to_width(lv, rv.len()); } switch (op_) { case '+': lv = lv + rv; break; case '-': lv = lv - rv; break; case '*': lv = lv * rv; break; case '/': lv = lv / rv; break; case '%': lv = lv % rv; break; case '&': for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) lv.set(idx, lv[idx] & rv[idx]); break; case '|': for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) lv.set(idx, lv[idx] | rv[idx]); break; case '^': for (unsigned idx = 0 ; idx < lv.len() ; idx += 1) lv.set(idx, lv[idx] ^ rv[idx]); break; case 'l': lv = lv << rv.as_unsigned(); break; case 'r': lv = lv >> rv.as_unsigned(); break; case 'R': lv = lv >> rv.as_unsigned(); break; default: cerr << "Illegal assignment operator: " << human_readable_op(op_) << endl; ivl_assert(loc, 0); } lv = cast_to_width(lv, lv_width); lv.has_sign(lv_sign); } bool NetAssign::eval_func_lval_(const LineInfo&loc, map&context_map, const NetAssign_*lval, NetExpr*rval_result) const { map::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; int word = 0; if (var->nwords > 0) { NetExpr*word_result = lval->word()->evaluate_function(loc, context_map); if (word_result == 0) { delete rval_result; return false; } NetEConst*word_const = dynamic_cast(word_result); ivl_assert(loc, word_const); if (!word_const->value().is_defined()) return true; word = word_const->value().as_long(); if (word >= var->nwords) return true; old_lval = var->array[word]; } else { assert(var->nwords == 0); old_lval = var->value; } if (const NetExpr*base_expr = lval->get_base()) { NetExpr*base_result = base_expr->evaluate_function(loc, context_map); if (base_result == 0) { delete rval_result; return false; } NetEConst*base_const = dynamic_cast(base_result); ivl_assert(loc, base_const); long base = base_const->value().as_long(); listprefix (0); base = lval->sig()->sb_to_idx(prefix, base); if (old_lval == 0) old_lval = make_const_x(lval->sig()->vector_width()); ivl_assert(loc, base + lval->lwidth() <= old_lval->expr_width()); NetEConst*lval_const = dynamic_cast(old_lval); ivl_assert(loc, lval_const); verinum lval_v = lval_const->value(); NetEConst*rval_const = dynamic_cast(rval_result); ivl_assert(loc, rval_const); verinum rval_v = rval_const->value(); verinum lpart(verinum::Vx, lval->lwidth()); if (op_) { for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1) lpart.set(idx, lval_v[base+idx]); eval_func_lval_op_(loc, lpart, rval_v); } else { lpart = cast_to_width(rval_v, lval->lwidth()); } for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1) lval_v.set(idx+base, lpart[idx]); delete base_result; delete rval_result; rval_result = new NetEConst(lval_v); } else { if (op_ == 0) { rval_result = fix_assign_value(lval->sig(), rval_result); } else if (dynamic_cast(rval_result)) { NetECReal*lval_const = dynamic_cast(old_lval); ivl_assert(loc, lval_const); verireal lval_r = lval_const->value(); NetECReal*rval_const = dynamic_cast(rval_result); ivl_assert(loc, rval_const); verireal rval_r = rval_const->value(); eval_func_lval_op_real_(loc, lval_r, rval_r); delete rval_result; rval_result = new NetECReal(lval_r); } else { NetEConst*lval_const = dynamic_cast(old_lval); ivl_assert(loc, lval_const); verinum lval_v = lval_const->value(); NetEConst*rval_const = dynamic_cast(rval_result); ivl_assert(loc, rval_const); verinum rval_v = rval_const->value(); eval_func_lval_op_(loc, lval_v, rval_v); delete rval_result; rval_result = new NetEConst(lval_v); } } if (old_lval) delete old_lval; if (debug_eval_tree) { cerr << get_fileline() << ": NetAssign::evaluate_function: " << lval->name() << " = " << *rval_result << endl; } if (var->nwords > 0) { var->array[word] = rval_result; } else { assert(var->nwords == 0); var->value = rval_result; } return true; } bool NetAssign::evaluate_function(const LineInfo&loc, map&context_map) const { // Evaluate the r-value expression. NetExpr*rval_result = rval()->evaluate_function(loc, context_map); if (rval_result == 0) return false; // Handle the easy case of a single variable on the LHS. if (l_val_count() == 1) return eval_func_lval_(loc, context_map, l_val(0), rval_result); // If we get here, the LHS must be a concatenation, so we // expect the RHS to be a vector value. NetEConst*rval_const = dynamic_cast(rval_result); ivl_assert(*this, rval_const); if (op_) { cerr << get_fileline() << ": sorry: Assignment operators " "inside a constant function are not currently " "supported if the LHS is a concatenation." << endl; return false; } verinum rval_full = rval_const->value(); delete rval_result; unsigned base = 0; for (unsigned ldx = 0 ; ldx < l_val_count() ; ldx += 1) { const NetAssign_*lval = l_val(ldx); verinum rval_part(verinum::Vx, lval->lwidth()); for (unsigned idx = 0 ; idx < rval_part.len() ; idx += 1) rval_part.set(idx, rval_full[base+idx]); bool flag = eval_func_lval_(loc, context_map, lval, new NetEConst(rval_part)); if (!flag) return false; base += lval->lwidth(); } return true; } /* * Evaluating a NetBlock in a function is a simple matter of * evaluating the statements in order. */ bool NetBlock::evaluate_function(const LineInfo&loc, map&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. maplocal_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::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; // Execute any variable initialization statements. if (const NetProc*init_proc = subscope_->var_init()) init_proc->evaluate_function(loc, local_context_map); } // Now use the local context map if there is any local // context, or the containing context map. map&use_context_map = use_local_context_map? local_context_map : context_map; bool flag = true; NetProc*cur = last_; do { cur = cur->next_; 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 (debug_eval_tree) { cerr << get_fileline() << ": NetBlock::evaluate_function: " << "subscope_=" << subscope_ << ", disable=" << disable << ", flag=" << (flag?"true":"false") << endl; } if (disable == subscope_) disable = 0; return flag; } bool NetCase::evaluate_function_vect_(const LineInfo&loc, map&context_map) const { NetExpr*case_expr = expr_->evaluate_function(loc, context_map); if (case_expr == 0) return false; NetEConst*case_const = dynamic_cast (case_expr); ivl_assert(loc, case_const); verinum case_val = case_const->value(); delete case_expr; NetProc*default_statement = 0; for (unsigned cnt = 0 ; cnt < items_.size() ; cnt += 1) { const Item*item = &items_[cnt]; if (item->guard == 0) { default_statement = item->statement; continue; } NetExpr*item_expr = item->guard->evaluate_function(loc, context_map); if (item_expr == 0) return false; NetEConst*item_const = dynamic_cast (item_expr); ivl_assert(loc, item_const); verinum item_val = item_const->value(); delete item_expr; ivl_assert(loc, item_val.len() == case_val.len()); bool match = true; for (unsigned idx = 0 ; idx < item_val.len() ; idx += 1) { verinum::V bit_a = case_val.get(idx); verinum::V bit_b = item_val.get(idx); if (bit_a == verinum::Vx && type_ == EQX) continue; if (bit_b == verinum::Vx && type_ == EQX) continue; if (bit_a == verinum::Vz && type_ != EQ) continue; if (bit_b == verinum::Vz && type_ != EQ) continue; if (bit_a != bit_b) { match = false; break; } } if (!match) continue; return item->statement->evaluate_function(loc, context_map); } if (default_statement) return default_statement->evaluate_function(loc, context_map); return true; } bool NetCase::evaluate_function_real_(const LineInfo&loc, map&context_map) const { NetExpr*case_expr = expr_->evaluate_function(loc, context_map); if (case_expr == 0) return false; NetECReal*case_const = dynamic_cast (case_expr); ivl_assert(loc, case_const); double case_val = case_const->value().as_double(); delete case_expr; NetProc*default_statement = 0; for (unsigned cnt = 0 ; cnt < items_.size() ; cnt += 1) { const Item*item = &items_[cnt]; if (item->guard == 0) { default_statement = item->statement; continue; } NetExpr*item_expr = item->guard->evaluate_function(loc, context_map); if (item_expr == 0) return false; NetECReal*item_const = dynamic_cast (item_expr); ivl_assert(loc, item_const); double item_val = item_const->value().as_double(); delete item_expr; if (item_val != case_val) continue; return item->statement->evaluate_function(loc, context_map); } if (default_statement) return default_statement->evaluate_function(loc, context_map); return true; } bool NetCase::evaluate_function(const LineInfo&loc, map&context_map) const { if (expr_->expr_type() == IVL_VT_REAL) return evaluate_function_real_(loc, context_map); else return evaluate_function_vect_(loc, context_map); } bool NetCondit::evaluate_function(const LineInfo&loc, map&context_map) const { NetExpr*cond = expr_->evaluate_function(loc, context_map); if (cond == 0) { if (debug_eval_tree) { cerr << get_fileline() << ": NetCondit::evaluate_function: " << "Unable to evaluate condition (" << *expr_ <<")" << endl; } return false; } NetEConst*cond_const = dynamic_cast (cond); ivl_assert(loc, cond_const); long val = cond_const->value().as_long(); delete cond; bool flag; if (val) // The condition is true, so evaluate the if clause flag = (if_ == 0) || if_->evaluate_function(loc, context_map); else // The condition is false, so evaluate the else clause flag = (else_ == 0) || else_->evaluate_function(loc, context_map); if (debug_eval_tree) { cerr << get_fileline() << ": NetCondit::evaluate_function: " << "Finished, flag=" << (flag?"true":"false") << endl; } return flag; } bool NetDisable::evaluate_function(const LineInfo&, map&) const { disable = target_; if (debug_eval_tree) { cerr << get_fileline() << ": NetDisable::evaluate_function: " << "disable " << scope_path(disable) << endl; } return true; } bool NetDoWhile::evaluate_function(const LineInfo&loc, map&context_map) const { bool flag = true; if (debug_eval_tree) { cerr << get_fileline() << ": NetDoWhile::evaluate_function: " << "Start loop" << endl; } while (!disable) { // Evaluate the statement. flag = proc_->evaluate_function(loc, context_map); if (! flag) break; // Evaluate the condition expression to try and get the // condition for the loop. NetExpr*cond = cond_->evaluate_function(loc, context_map); if (cond == 0) { flag = false; break; } NetEConst*cond_const = dynamic_cast (cond); ivl_assert(loc, cond_const); long val = cond_const->value().as_long(); delete cond; // If the condition is false, then the loop is done. if (val == 0) break; } if (debug_eval_tree) { cerr << get_fileline() << ": NetDoWhile::evaluate_function: " << "Done loop, flag=" << (flag?"true":"false") << endl; } return flag; } bool NetForever::evaluate_function(const LineInfo&loc, map&context_map) const { bool flag = true; if (debug_eval_tree) { cerr << get_fileline() << ": debug: NetForever::evaluate_function: " << "Start loop" << endl; } while (flag && !disable) { flag = flag && statement_->evaluate_function(loc, context_map); } if (debug_eval_tree) { cerr << get_fileline() << ": debug: NetForever::evaluate_function: " << "Done loop" << endl; } return flag; } /* * For now, resort to the block form of the statement until we learn * to do this directly. */ bool NetForLoop::evaluate_function(const LineInfo&loc, map&context_map) const { return as_block_->evaluate_function(loc, context_map); } bool NetRepeat::evaluate_function(const LineInfo&loc, map&context_map) const { bool flag = true; // Evaluate the condition expression to try and get the // condition for the loop. NetExpr*count_expr = expr_->evaluate_function(loc, context_map); if (count_expr == 0) return false; NetEConst*count_const = dynamic_cast (count_expr); ivl_assert(loc, count_const); long count = count_const->value().as_long(); delete count_expr; if (debug_eval_tree) { cerr << get_fileline() << ": debug: NetRepeat::evaluate_function: " << "Repeating " << count << " times." << endl; } while ((count > 0) && flag && !disable) { flag = flag && statement_->evaluate_function(loc, context_map); count -= 1; } if (debug_eval_tree) { cerr << get_fileline() << ": debug: NetRepeat::evaluate_function: " << "Finished loop" << endl; } return flag; } 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 { bool flag = true; if (debug_eval_tree) { cerr << get_fileline() << ": NetWhile::evaluate_function: " << "Start loop" << endl; } while (flag && !disable) { // Evaluate the condition expression to try and get the // condition for the loop. NetExpr*cond = cond_->evaluate_function(loc, context_map); if (cond == 0) { flag = false; break; } NetEConst*cond_const = dynamic_cast (cond); ivl_assert(loc, cond_const); long val = cond_const->value().as_long(); delete cond; // If the condition is false, then break. if (val == 0) break; // The condition is true, so evaluate the statement // another time. bool tmp_flag = proc_->evaluate_function(loc, context_map); if (! tmp_flag) flag = false; } if (debug_eval_tree) { cerr << get_fileline() << ": NetWhile::evaluate_function: " << "Done loop, flag=" << (flag?"true":"false") << endl; } return flag; } NetExpr* NetEBinary::evaluate_function(const LineInfo&loc, map&context_map) const { NetExpr*lval = left_->evaluate_function(loc, context_map); NetExpr*rval = right_->evaluate_function(loc, context_map); if (lval == 0 || rval == 0) { delete lval; delete rval; return 0; } NetExpr*res = eval_arguments_(lval, rval); delete lval; delete rval; return res; } NetExpr* NetEConcat::evaluate_function(const LineInfo&loc, map&context_map) const { vectorvals(parms_.size()); unsigned gap = 0; unsigned valid_vals = 0; for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { ivl_assert(*this, parms_[idx]); vals[idx] = parms_[idx]->evaluate_function(loc, context_map); if (vals[idx] == 0) continue; gap += vals[idx]->expr_width(); valid_vals += 1; } NetExpr*res = 0; if (valid_vals == parms_.size()) { res = eval_arguments_(vals, gap); } for (unsigned idx = 0 ; idx < vals.size() ; idx += 1) { delete vals[idx]; } return res; } NetExpr* NetEConst::evaluate_function(const LineInfo&, map&) const { NetEConst*res = new NetEConst(value_); res->set_line(*this); return res; } NetExpr* NetECReal::evaluate_function(const LineInfo&, map&) const { NetECReal*res = new NetECReal(value_); res->set_line(*this); return res; } NetExpr* NetESelect::evaluate_function(const LineInfo&loc, map&context_map) const { NetExpr*sub_exp = expr_->evaluate_function(loc, context_map); ivl_assert(loc, sub_exp); NetEConst*sub_const = dynamic_cast (sub_exp); ivl_assert(loc, sub_exp); verinum sub = sub_const->value(); delete sub_exp; long base = 0; if (base_) { NetExpr*base_val = base_->evaluate_function(loc, context_map); ivl_assert(loc, base_val); NetEConst*base_const = dynamic_cast(base_val); ivl_assert(loc, base_const); base = base_const->value().as_long(); delete base_val; } else { sub.has_sign(has_sign()); sub = pad_to_width(sub, expr_width()); } verinum res (verinum::Vx, expr_width()); for (unsigned idx = 0 ; idx < res.len() ; idx += 1) res.set(idx, sub[base+idx]); NetEConst*res_const = new NetEConst(res); return res_const; } NetExpr* NetESignal::evaluate_function(const LineInfo&loc, map&context_map) const { map::iterator ptr = context_map.find(name()); if (ptr == context_map.end()) { cerr << get_fileline() << ": error: Cannot evaluate " << name() << " in this context." << endl; 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 (var->nwords > 0) { ivl_assert(loc, word_); NetExpr*word_result = word_->evaluate_function(loc, context_map); if (word_result == 0) return 0; NetEConst*word_const = dynamic_cast(word_result); ivl_assert(loc, word_const); int word = word_const->value().as_long(); if (word_const->value().is_defined() && (word < var->nwords)) value = var->array[word]; } else { value = var->value; } if (value == 0) { switch (expr_type()) { case IVL_VT_REAL: return new NetECReal( verireal(0.0) ); case IVL_VT_BOOL: return make_const_0(expr_width()); case IVL_VT_LOGIC: return make_const_x(expr_width()); default: cerr << get_fileline() << ": sorry: I don't know how to initialize " << *this << endl; return 0; } } return value->dup_expr(); } NetExpr* NetETernary::evaluate_function(const LineInfo&loc, map&context_map) const { unique_ptr cval (cond_->evaluate_function(loc, context_map)); switch (const_logical(cval.get())) { case C_0: return false_val_->evaluate_function(loc, context_map); case C_1: return true_val_->evaluate_function(loc, context_map); case C_X: break; default: cerr << get_fileline() << ": error: Condition expression is not constant here." << endl; return 0; } NetExpr*tval = true_val_->evaluate_function(loc, context_map); NetExpr*fval = false_val_->evaluate_function(loc, context_map); NetExpr*res = blended_arguments_(tval, fval); delete tval; delete fval; return res; } NetExpr* NetEUnary::evaluate_function(const LineInfo&loc, map&context_map) const { NetExpr*val = expr_->evaluate_function(loc, context_map); if (val == 0) return 0; NetExpr*res = eval_arguments_(val); delete val; return res; } NetExpr* NetESFunc::evaluate_function(const LineInfo&loc, map&context_map) const { ID id = built_in_id_(); ivl_assert(*this, id != NOT_BUILT_IN); NetExpr*val0 = 0; NetExpr*val1 = 0; NetExpr*res = 0; switch (parms_.size()) { case 1: val0 = parms_[0]->evaluate_function(loc, context_map); if (val0 == 0) break; res = evaluate_one_arg_(id, val0); break; case 2: val0 = parms_[0]->evaluate_function(loc, context_map); val1 = parms_[1]->evaluate_function(loc, context_map); if (val0 == 0 || val1 == 0) break; res = evaluate_two_arg_(id, val0, val1); break; default: ivl_assert(*this, 0); break; } delete val0; delete val1; return res; } NetExpr* NetEUFunc::evaluate_function(const LineInfo&loc, map&context_map) const { NetFuncDef*def = func_->func_def(); ivl_assert(*this, def); vectorargs(parms_.size()); for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) args[idx] = parms_[idx]->evaluate_function(loc, context_map); NetExpr*res = def->evaluate_function(*this, args); return res; }