/* * Copyright (c) 2000-2007 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" 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; } 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); } 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); } // After all the wires are elaborated, we are free to // elaborate the ports of the tasks defined within this // module. Run through them now. 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); } // 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 PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, Module*rmod) const { bool flag = true; 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 PGenerate::elaborate_sig(Design*des, NetScope*container) const { bool flag = true; 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); } typedef list::const_iterator generate_it_t; for (generate_it_t cur = generates.begin() ; cur != generates.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: cerr << get_fileline() << ": internal error: I don't know how " << "to deal with return type of function " << scope->basename() << "." << endl; } 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); 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; } ports[idx] = tmp; } NetFuncDef*def = 0; if (ret_sig) def = new NetFuncDef(scope, ret_sig, ports); assert(def); 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); } bool PGate::elaborate_sig(Design*des, NetScope*scope) const { return true; } /* * 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; } NetEConst*lcon = dynamic_cast (lexp); NetEConst*rcon = dynamic_cast (rexp); if ((lcon == 0) || (rcon == 0)) { cerr << get_fileline() << ": internal error: The indices " << "are not constant for array ``" << name_ << "''." << endl; des->errors += 1; return 0; } verinum lval = lcon->value(); verinum rval = rcon->value(); delete lexp; delete rexp; 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 ? 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 (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; }