/* * Copyright (c) 2000-2008 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ # include "config.h" # include # include # include "Module.h" # include "PExpr.h" # include "PGate.h" # include "PGenerate.h" # include "PTask.h" # include "PWire.h" # include "Statement.h" # include "compiler.h" # include "netlist.h" # include "netmisc.h" # include "util.h" # include "ivl_assert.h" static bool get_const_argument(NetExpr*exp, verinum&res) { switch (exp->expr_type()) { case IVL_VT_REAL: { NetECReal*cv = dynamic_cast(exp); if (cv == 0) return false; verireal tmp = cv->value(); res = verinum(tmp.as_long()); break; } case IVL_VT_BOOL: case IVL_VT_LOGIC: { NetEConst*cv = dynamic_cast(exp); if (cv == 0) return false; res = cv->value(); break; } default: assert(0);; } return true; } void Statement::elaborate_sig(Design*des, NetScope*scope) const { } bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const { bool flag = true; for (map::const_iterator wt = wires.begin() ; wt != wires.end() ; wt ++ ) { PWire*cur = (*wt).second; NetNet*sig = cur->elaborate_sig(des, scope); /* If the signal is an input and is also declared as a reg, then report an error. */ if (sig && (sig->scope() == scope) && (scope->type() == NetScope::MODULE) && (sig->port_type() == NetNet::PINPUT) && (sig->type() == NetNet::REG)) { cerr << cur->get_fileline() << ": error: " << cur->basename() << " in " << scope->module_name() << " declared as input and as a reg type." << endl; des->errors += 1; } if (sig && (sig->scope() == scope) && (scope->type() == NetScope::MODULE) && (sig->port_type() == NetNet::PINOUT) && (sig->type() == NetNet::REG)) { cerr << cur->get_fileline() << ": error: " << cur->basename() << " in " << scope->module_name() << " declared as inout and as a reg type." << endl; des->errors += 1; } } return flag; } static void elaborate_sig_funcs(Design*des, NetScope*scope, const map&funcs) { typedef map::const_iterator mfunc_it_t; for (mfunc_it_t cur = funcs.begin() ; cur != funcs.end() ; cur ++) { hname_t use_name ( (*cur).first ); NetScope*fscope = scope->child(use_name); if (scope == 0) { cerr << (*cur).second->get_fileline() << ": internal error: " << "Child scope for function " << (*cur).first << " missing in " << scope_path(scope) << "." << endl; des->errors += 1; continue; } (*cur).second->elaborate_sig(des, fscope); } } static void elaborate_sig_tasks(Design*des, NetScope*scope, const map&tasks) { typedef map::const_iterator mtask_it_t; for (mtask_it_t cur = tasks.begin() ; cur != tasks.end() ; cur ++) { NetScope*tscope = scope->child( hname_t((*cur).first) ); assert(tscope); (*cur).second->elaborate_sig(des, tscope); } } bool Module::elaborate_sig(Design*des, NetScope*scope) const { bool flag = true; // Scan all the ports of the module, and make sure that each // is connected to wires that have port declarations. for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) { Module::port_t*pp = ports[idx]; if (pp == 0) continue; // The port has a name and an array of expressions. The // expression are all identifiers that should reference // wires within the scope. map::const_iterator wt; for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) { pform_name_t port_path (pp->expr[cc]->path()); // A concatenated wire of a port really should not // have any hierarchy. if (port_path.size() != 1) { cerr << get_fileline() << ": internal error: " << "Port " << port_path << " has a funny name?" << endl; des->errors += 1; } wt = wires.find(peek_tail_name(port_path)); if (wt == wires.end()) { cerr << get_fileline() << ": error: " << "Port " << port_path << " (" << (idx+1) << ") of module " << mod_name() << " is not declared within module." << endl; des->errors += 1; continue; } if ((*wt).second->get_port_type() == NetNet::NOT_A_PORT) { cerr << get_fileline() << ": error: " << "Port " << pp->expr[cc]->path() << " (" << (idx+1) << ") of module " << mod_name() << " has no direction declaration." << endl; des->errors += 1; } } } flag = elaborate_sig_wires_(des, scope) && flag; // Run through all the generate schemes to elaborate the // signals that they hold. Note that the generate schemes hold // the scopes that they instantiated, so we don't pass any // scope in. typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; cur ++ ) { (*cur) -> elaborate_sig(des, scope); } // Get all the gates of the module and elaborate them by // connecting them to the signals. The gate may be simple or // complex. What we are looking for is gates that are modules // that can create scopes and signals. const list&gl = get_gates(); for (list::const_iterator gt = gl.begin() ; gt != gl.end() ; gt ++ ) { flag &= (*gt)->elaborate_sig(des, scope); } // After all the wires are elaborated, we are free to // elaborate the ports of the tasks defined within this // module. Run through them now. elaborate_sig_funcs(des, scope, funcs); elaborate_sig_tasks(des, scope, tasks); // initial and always blocks may contain begin-end and // fork-join blocks that can introduce scopes. Therefore, I // get to scan processes here. typedef list::const_iterator proc_it_t; for (proc_it_t cur = behaviors.begin() ; cur != behaviors.end() ; cur ++ ) { (*cur) -> statement() -> elaborate_sig(des, scope); } return flag; } bool PExpr::elaborate_sig(Design*des, NetScope*scope) const { return true; } bool PEConcat::elaborate_sig(Design*des, NetScope*scope) const { bool flag = true; for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) flag = parms_[idx]->elaborate_sig(des, scope) && flag; return flag; } bool PEIdent::elaborate_sig(Design*des, NetScope*scope) const { NetNet* sig = 0; const NetExpr*par = 0; NetEvent* eve = 0; // If implicit net creation is turned off, then stop now. if (scope->default_nettype() == NetNet::NONE) return true; if (error_implicit) return true; symbol_search(des, scope, path_, sig, par, eve); if (eve != 0) return false; if (par != 0) return true; if (sig == 0) sig = make_implicit_net_(des, scope); return sig != 0; } bool PEBinary::elaborate_sig(Design*des, NetScope*scope) const { bool flag = true; flag = left_->elaborate_sig(des, scope) && flag; flag = right_->elaborate_sig(des, scope) && flag; return flag; } bool PETernary::elaborate_sig(Design*des, NetScope*scope) const { bool flag = true; flag = tru_->elaborate_sig(des, scope) && flag; flag = fal_->elaborate_sig(des, scope) && flag; return flag; } bool PEUnary::elaborate_sig(Design*des, NetScope*scope) const { return expr_->elaborate_sig(des, scope); } bool PGate::elaborate_sig(Design*des, NetScope*scope) const { return true; } bool PGBuiltin::elaborate_sig(Design*des, NetScope*scope) const { bool flag = true; for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { const PExpr* pin_expr = pin(idx); if (pin_expr == 0) { // If there is no pin expression for this port, // then skip it. Do not bother generating an error // message here, that will be done during // elaboration where these semantic details are tested. continue; } ivl_assert(*this, pin_expr); flag = pin_expr->elaborate_sig(des, scope) && flag; } return flag; } bool PGAssign::elaborate_sig(Design*des, NetScope*scope) const { /* Normally, l-values to continuous assignments are NOT allowed to implicitly declare nets. However, so many tools do allow it that Icarus Verilog will allow it, at least if extensions are enabled. */ if (gn_icarus_misc_flag) return pin(0)->elaborate_sig(des, scope); return true; } bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, Module*rmod) const { bool flag = true; // First, elaborate the signals that may be created implicitly // by ports to this module instantiation. Handle the case that // the ports are passed by name (pins_ != 0) or position. if (pins_) for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { const PExpr*tmp = pins_[idx].parm; if (tmp == 0) continue; flag = tmp->elaborate_sig(des, scope) && flag; } else for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { const PExpr*tmp = pin(idx); if (tmp == 0) continue; flag = tmp->elaborate_sig(des, scope) && flag; } NetScope::scope_vec_t instance = scope->instance_arrays[get_name()]; for (unsigned idx = 0 ; idx < instance.count() ; idx += 1) { // I know a priori that the elaborate_scope created the scope // already, so just look it up as a child of the current scope. NetScope*my_scope = instance[idx]; assert(my_scope); if (my_scope->parent() != scope) { cerr << get_fileline() << ": internal error: " << "Instance " << scope_path(my_scope) << " is in parent " << scope_path(my_scope->parent()) << " instead of " << scope_path(scope) << endl; } assert(my_scope->parent() == scope); if (! rmod->elaborate_sig(des, my_scope)) flag = false; } return flag; } bool PGModule::elaborate_sig_udp_(Design*des, NetScope*scope, PUdp*udp) const { bool flag = true; if (pins_) for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { const PExpr*tmp = pins_[idx].parm; if (tmp == 0) continue; flag = tmp->elaborate_sig(des, scope) && flag; } else for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { const PExpr*tmp = pin(idx); if (tmp == 0) continue; flag = tmp->elaborate_sig(des, scope) && flag; } return flag; } bool PGenerate::elaborate_sig(Design*des, NetScope*container) const { bool flag = true; // Handle the special case that this is a CASE scheme. In this // case the PGenerate itself does not have the generated // item. Look instead for the case ITEM that has a scope // generated for it. if (scheme_type == PGenerate::GS_CASE) { if (debug_elaborate) cerr << get_fileline() << ": debug: generate case" << " elaborate_sig in scope " << scope_path(container) << "." << endl; typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; cur ++) { PGenerate*item = *cur; if (! item->scope_list_.empty()) { flag &= item->elaborate_sig(des, container); } } return flag; } typedef list::const_iterator scope_list_it_t; for (scope_list_it_t cur = scope_list_.begin() ; cur != scope_list_.end() ; cur ++ ) { NetScope*scope = *cur; if (scope->parent() != container) continue; if (debug_elaborate) cerr << get_fileline() << ": debug: Elaborate nets in " << "scope " << scope_path(*cur) << " in generate " << id_number << endl; flag = elaborate_sig_(des, *cur) & flag; } return flag; } bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const { // Scan the declared PWires to elaborate the obvious signals // in the current scope. typedef map::const_iterator wires_it_t; for (wires_it_t wt = wires.begin() ; wt != wires.end() ; wt ++ ) { PWire*cur = (*wt).second; if (debug_elaborate) cerr << get_fileline() << ": debug: Elaborate PWire " << cur->basename() << " in scope " << scope_path(scope) << endl; cur->elaborate_sig(des, scope); } elaborate_sig_funcs(des, scope, funcs); elaborate_sig_tasks(des, scope, tasks); typedef list::const_iterator generate_it_t; for (generate_it_t cur = generate_schemes.begin() ; cur != generate_schemes.end() ; cur ++ ) { (*cur) -> elaborate_sig(des, scope); } typedef list::const_iterator pgate_list_it_t; for (pgate_list_it_t cur = gates.begin() ; cur != gates.end() ; cur ++) { (*cur) ->elaborate_sig(des, scope); } return true; } /* * A function definition exists within an elaborated module. This * matters when elaborating signals, as the ports of the function are * created as signals/variables for each instance of the * function. That is why PFunction has an elaborate_sig method. */ void PFunction::elaborate_sig(Design*des, NetScope*scope) const { perm_string fname = scope->basename(); assert(scope->type() == NetScope::FUNC); elaborate_sig_wires_(des, scope); /* Make sure the function has at least one input port. If it fails this test, print an error message. Keep going so we can find more errors. */ if (ports_ == 0) { cerr << get_fileline() << ": error: Function " << fname << " has no ports." << endl; cerr << get_fileline() << ": : Functions must have" << " at least one input port." << endl; des->errors += 1; } NetNet*ret_sig = 0; /* Create the signals/variables of the return value and write them into the function scope. */ switch (return_type_.type) { case PTF_REG: case PTF_REG_S: if (return_type_.range) { NetExpr*me = elab_and_eval(des, scope, (*return_type_.range)[0], -1); assert(me); NetExpr*le = elab_and_eval(des, scope, (*return_type_.range)[1], -1); assert(le); long mnum = 0, lnum = 0; if (NetEConst*tmp = dynamic_cast(me)) { mnum = tmp->value().as_long(); } else { cerr << me->get_fileline() << ": error: " "Unable to evaluate constant expression " << *me << "." << endl; des->errors += 1; } if (NetEConst*tmp = dynamic_cast(le)) { lnum = tmp->value().as_long(); } else { cerr << le->get_fileline() << ": error: " "Unable to evaluate constant expression " << *le << "." << endl; des->errors += 1; } ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum); } else { ret_sig = new NetNet(scope, fname, NetNet::REG); } ret_sig->set_line(*this); ret_sig->set_signed(return_type_.type == PTF_REG_S); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_LOGIC); break; case PTF_INTEGER: ret_sig = new NetNet(scope, fname, NetNet::REG, integer_width); ret_sig->set_line(*this); ret_sig->set_signed(true); ret_sig->set_isint(true); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_LOGIC); break; case PTF_TIME: ret_sig = new NetNet(scope, fname, NetNet::REG, 64); ret_sig->set_line(*this); ret_sig->set_signed(false); ret_sig->set_isint(false); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_LOGIC); break; case PTF_REAL: case PTF_REALTIME: ret_sig = new NetNet(scope, fname, NetNet::REG, 1); ret_sig->set_line(*this); ret_sig->set_signed(true); ret_sig->set_isint(false); ret_sig->port_type(NetNet::POUTPUT); ret_sig->data_type(IVL_VT_REAL); break; default: if (ports_) { cerr << get_fileline() << ": internal error: I don't know " << "how to deal with return type of function " << scope->basename() << "." << endl; } else { /* If we do not have any ports or a return type this * is probably a bad function definition. */ cerr << get_fileline() << ": error: Bad definition for " << "function " << scope->basename() << "?" << endl; return; } } svectorports (ports_? ports_->count() : 0); if (ports_) for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { /* Parse the port name into the task name and the reg name. We know by design that the port name is given as two components: .. */ perm_string pname = (*ports_)[idx]->basename(); NetNet*tmp = scope->find_signal(pname); ports[idx] = 0; if (tmp == 0) { cerr << get_fileline() << ": internal error: function " << scope_path(scope) << " is missing port " << pname << "." << endl; scope->dump(cerr); cerr << get_fileline() << ": Continuing..." << endl; des->errors += 1; continue; } if (tmp->port_type() == NetNet::NOT_A_PORT) { cerr << get_fileline() << ": internal error: function " << scope_path(scope) << " port " << pname << " is a port but is not a port?" << endl; des->errors += 1; scope->dump(cerr); continue; } ports[idx] = tmp; if (tmp->port_type() != NetNet::PINPUT) { cerr << tmp->get_fileline() << ": error: function " << scope_path(scope) << " port " << pname << " is not an input port." << endl; cerr << tmp->get_fileline() << ": : Function arguments " << "must be input ports." << endl; des->errors += 1; } } NetFuncDef*def = 0; if (ret_sig) def = new NetFuncDef(scope, ret_sig, ports); assert(def); if (debug_elaborate) cerr << get_fileline() << ": debug: " << "Attach function definition to scope " << scope_path(scope) << "." << endl; scope->set_func_def(def); // Look for further signals in the sub-statement if (statement_) statement_->elaborate_sig(des, scope); } /* * A task definition is a scope within an elaborated module. When we * are elaborating signals, the scopes have already been created, as * have the reg objects that are the parameters of this task. The * elaborate_sig method of PTask is therefore left to connect the * signals to the ports of the NetTaskDef definition. We know for * certain that signals exist (They are in my scope!) so the port * binding is sure to work. */ void PTask::elaborate_sig(Design*des, NetScope*scope) const { assert(scope->type() == NetScope::TASK); elaborate_sig_wires_(des, scope); svectorports (ports_? ports_->count() : 0); for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) { perm_string port_name = (*ports_)[idx]->basename(); /* Find the signal for the port. We know by definition that it is in the scope of the task, so look only in the scope. */ NetNet*tmp = scope->find_signal(port_name); if (tmp == 0) { cerr << get_fileline() << ": internal error: " << "Could not find port " << port_name << " in scope " << scope_path(scope) << endl; scope->dump(cerr); des->errors += 1; } ports[idx] = tmp; } NetTaskDef*def = new NetTaskDef(scope, ports); scope->set_task_def(def); // Look for further signals in the sub-statement if (statement_) statement_->elaborate_sig(des, scope); } void PBlock::elaborate_sig(Design*des, NetScope*scope) const { NetScope*my_scope = scope; if (pscope_name() != 0) { hname_t use_name (pscope_name()); my_scope = scope->child(use_name); if (my_scope == 0) { cerr << get_fileline() << ": internal error: " << "Unable to find child scope " << pscope_name() << " in this context?" << endl; des->errors += 1; my_scope = scope; } else { if (debug_elaborate) cerr << get_fileline() << ": debug: " << "elaborate_sig descending into " << scope_path(my_scope) << "." << endl; elaborate_sig_wires_(des, my_scope); } } // elaborate_sig in the statements included in the // block. There may be named blocks in there. for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) list_[idx] -> elaborate_sig(des, my_scope); } void PCase::elaborate_sig(Design*des, NetScope*scope) const { if (items_ == 0) return; for (unsigned idx = 0 ; idx < items_->count() ; idx += 1) { if ( (*items_)[idx]->stat ) (*items_)[idx]->stat ->elaborate_sig(des,scope); } } void PCondit::elaborate_sig(Design*des, NetScope*scope) const { if (if_) if_->elaborate_sig(des, scope); if (else_) else_->elaborate_sig(des, scope); } void PDelayStatement::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) statement_->elaborate_sig(des, scope); } void PEventStatement::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) statement_->elaborate_sig(des, scope); } void PForever::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) statement_->elaborate_sig(des, scope); } void PForStatement::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) statement_->elaborate_sig(des, scope); } void PRepeat::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) statement_->elaborate_sig(des, scope); } void PWhile::elaborate_sig(Design*des, NetScope*scope) const { if (statement_) statement_->elaborate_sig(des, scope); } /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the * multiple properties of a wire (i.e., "input wire") so come the * elaboration this creates an object in the design that represent the * defined item. */ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const { NetNet::Type wtype = type_; if (wtype == NetNet::IMPLICIT) wtype = NetNet::WIRE; if (wtype == NetNet::IMPLICIT_REG) wtype = NetNet::REG; unsigned wid = 1; long lsb = 0, msb = 0; des->errors += error_cnt_; if (port_set_ || net_set_) { long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; /* If they exist get the port definition MSB and LSB */ if (port_set_ && port_msb_ != 0) { NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1); if (! eval_as_long(pmsb, texpr)) { cerr << port_msb_->get_fileline() << ": error: " "Unable to evaluate MSB constant expression ``" << *port_msb_ << "''." << endl; des->errors += 1; return 0; } delete texpr; texpr = elab_and_eval(des, scope, port_lsb_, -1); if (! eval_as_long(plsb, texpr)) { cerr << port_lsb_->get_fileline() << ": error: " "Unable to evaluate LSB constant expression ``" << *port_lsb_ << "''." << endl; des->errors += 1; return 0; } delete texpr; nmsb = pmsb; nlsb = plsb; } if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0); if (port_msb_ == 0) assert(port_lsb_ == 0); if (port_lsb_ == 0) assert(port_msb_ == 0); /* If they exist get the net/etc. definition MSB and LSB */ if (net_set_ && net_msb_ != 0) { NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1); if (! eval_as_long(nmsb, texpr)) { cerr << net_msb_->get_fileline() << ": error: " "Unable to evaluate MSB constant expression ``" << *net_msb_ << "''." << endl; des->errors += 1; return 0; } delete texpr; texpr = elab_and_eval(des, scope, net_lsb_, -1); if (! eval_as_long(nlsb, texpr)) { cerr << net_lsb_->get_fileline() << ": error: " "Unable to evaluate LSB constant expression ``" << *net_lsb_ << "''." << endl; des->errors += 1; return 0; } delete texpr; } if (!net_set_) assert(net_msb_ == 0 && net_lsb_ == 0); if (net_msb_ == 0) assert(net_lsb_ == 0); if (net_lsb_ == 0) assert(net_msb_ == 0); /* We have a port size error */ if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) { /* Scalar port with a vector net/etc. definition */ if (port_msb_ == 0) { if (!gn_io_range_error_flag) { cerr << get_fileline() << ": warning: Scalar port ``" << name_ << "'' has a vectored net declaration [" << nmsb << ":" << nlsb << "]." << endl; } else { cerr << get_fileline() << ": error: Scalar port ``" << name_ << "'' has a vectored net declaration [" << nmsb << ":" << nlsb << "]." << endl; des->errors += 1; return 0; } } /* Vectored port with a scalar net/etc. definition */ if (net_msb_ == 0) { cerr << port_msb_->get_fileline() << ": error: Vectored port ``" << name_ << "'' [" << pmsb << ":" << plsb << "] has a scalar net declaration at " << get_fileline() << "." << endl; des->errors += 1; return 0; } /* Both vectored, but they have different ranges. */ if (port_msb_ != 0 && net_msb_ != 0) { cerr << port_msb_->get_fileline() << ": error: Vectored port ``" << name_ << "'' [" << pmsb << ":" << plsb << "] has a net declaration [" << nmsb << ":" << nlsb << "] at " << net_msb_->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; } } lsb = nlsb; msb = nmsb; if (nmsb > nlsb) wid = nmsb - nlsb + 1; else wid = nlsb - nmsb + 1; } unsigned nattrib = 0; attrib_list_t*attrib_list = evaluate_attributes(attributes, nattrib, des, scope); long array_s0 = 0; long array_e0 = 0; unsigned array_dimensions = 0; /* If the ident has idx expressions, then this is a memory. It can only have the idx registers after the msb and lsb expressions are filled. And, if it has one index, it has both. */ if (lidx_ || ridx_) { assert(lidx_ && ridx_); NetExpr*lexp = elab_and_eval(des, scope, lidx_, -1); NetExpr*rexp = elab_and_eval(des, scope, ridx_, -1); if ((lexp == 0) || (rexp == 0)) { cerr << get_fileline() << ": internal error: There is " << "a problem evaluating indices for ``" << name_ << "''." << endl; des->errors += 1; return 0; } bool const_flag = true; verinum lval, rval; const_flag &= get_const_argument(lexp, lval); const_flag &= get_const_argument(rexp, rval); delete rexp; delete lexp; if (!const_flag) { cerr << get_fileline() << ": internal error: The indices " << "are not constant for array ``" << name_ << "''." << endl; des->errors += 1; return 0; } array_dimensions = 1; array_s0 = lval.as_long(); array_e0 = rval.as_long(); } /* If the net type is supply0 or supply1, replace it with a simple wire with a pulldown/pullup with supply strength. In other words, transform: supply0 foo; to: wire foo; pulldown #(supply0) (foo); This reduces the backend burden, and behaves exactly the same. */ NetLogic*pull = 0; if (wtype == NetNet::SUPPLY0 || wtype == NetNet::SUPPLY1) { NetLogic::TYPE pull_type = (wtype==NetNet::SUPPLY1) ? NetLogic::PULLUP : NetLogic::PULLDOWN; pull = new NetLogic(scope, scope->local_symbol(), 1, pull_type, wid); pull->set_line(*this); pull->pin(0).drive0(Link::SUPPLY); pull->pin(0).drive1(Link::SUPPLY); des->add_node(pull); wtype = NetNet::WIRE; if (debug_elaborate) { cerr << get_fileline() << ": debug: " << "Generate a SUPPLY pulldown for the " << "supply0 net." << endl; } } if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype << " ["< 0) { cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; } cerr << " in scope " << scope_path(scope) << endl; } NetNet*sig = array_dimensions > 0 ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) : new NetNet(scope, name_, wtype, msb, lsb); ivl_variable_type_t use_data_type = data_type_; if (use_data_type == IVL_VT_NO_TYPE) { use_data_type = IVL_VT_LOGIC; if (debug_elaborate) { cerr << get_fileline() << ": debug: " << "Signal " << name_ << " in scope " << scope_path(scope) << " defaults to data type " << use_data_type << endl; } } sig->data_type(use_data_type); sig->set_line(*this); sig->port_type(port_type_); sig->set_signed(get_signed()); sig->set_isint(get_isint()); if (discipline_t*dis = get_discipline()) { sig->set_discipline(dis); } if (pull) connect(sig->pin(0), pull->pin(0)); for (unsigned idx = 0 ; idx < nattrib ; idx += 1) sig->attribute(attrib_list[idx].key, attrib_list[idx].val); return sig; }