/* * Copyright (c) 2000-2003 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 */ #ifdef HAVE_CVS_IDENT #ident "$Id: elab_scope.cc,v 1.35 2004/09/10 00:15:17 steve Exp $" #endif # include "config.h" # include "compiler.h" # include # include # include /* * Elaboration happens in two passes, generally. The first scans the * pform to generate the NetScope tree and attach it to the Design * object. The methods in this source file implement the elaboration * of the scopes. */ # include "Module.h" # include "PData.h" # include "PEvent.h" # include "PExpr.h" # include "PGate.h" # include "PTask.h" # include "PWire.h" # include "Statement.h" # include "netlist.h" # include "util.h" # include # include bool Module::elaborate_scope(Design*des, NetScope*scope) const { if (debug_scopes) { cerr << get_line() << ": debug: Elaborate scope " << scope->name() << "." << endl; } // Generate all the parameters that this instance of this // module introduces to the design. This loop elaborates the // parameters, but doesn't evaluate references to // parameters. This scan practically locates all the // parameters and puts them in the parameter table in the // design. // No expressions are evaluated, yet. For now, leave them in // the pform and just place a NetEParam placeholder in the // place of the elaborated expression. typedef map::const_iterator mparm_it_t; typedef map::const_iterator hparm_it_t; // This loop scans the parameters in the module, and creates // stub parameter entries in the scope for the parameter name. for (mparm_it_t cur = parameters.begin() ; cur != parameters.end() ; cur ++) { NetEParam*tmp = new NetEParam; tmp->set_line(*((*cur).second.expr)); if ((*cur).second.msb) tmp->cast_signed( (*cur).second.signed_flag ); scope->set_parameter((*cur).first, tmp, 0, 0, false); } for (mparm_it_t cur = localparams.begin() ; cur != localparams.end() ; cur ++) { NetEParam*tmp = new NetEParam; tmp->set_line(*((*cur).second.expr)); if ((*cur).second.msb) tmp->cast_signed( (*cur).second.signed_flag ); scope->set_parameter((*cur).first, tmp, 0, 0, false); } // Now scan the parameters again, this time elaborating them // for use as parameter values. This is after the previous // scan so that local parameter names can be used in the // r-value expressions. for (mparm_it_t cur = parameters.begin() ; cur != parameters.end() ; cur ++) { PExpr*ex = (*cur).second.expr; assert(ex); NetExpr*val = ex->elaborate_pexpr(des, scope); NetExpr*msb = 0; NetExpr*lsb = 0; bool signed_flag = false; /* If the parameter declaration includes msb and lsb, then use them to calculate a width for the result. Then make sure the constant expression of the parameter value is coerced to have the correct and defined width. */ if ((*cur).second.msb) { msb = (*cur).second.msb ->elaborate_pexpr(des, scope); assert(msb); lsb = (*cur).second.lsb ->elaborate_pexpr(des, scope); signed_flag = (*cur).second.signed_flag; } val->cast_signed(signed_flag); val = scope->set_parameter((*cur).first, val, msb, lsb, signed_flag); assert(val); delete val; } for (mparm_it_t cur = localparams.begin() ; cur != localparams.end() ; cur ++) { PExpr*ex = (*cur).second.expr; assert(ex); NetExpr*val = ex->elaborate_pexpr(des, scope); NetExpr*msb = 0; NetExpr*lsb = 0; bool signed_flag = false; /* If the parameter declaration includes msb and lsb, then use them to calculate a width for the result. Then make sure the constant expression of the parameter value is coerced to have the correct and defined width. */ if ((*cur).second.msb) { msb = (*cur).second.msb ->elaborate_pexpr(des, scope); assert(msb); lsb = (*cur).second.lsb ->elaborate_pexpr(des, scope); signed_flag = (*cur).second.signed_flag; } val->cast_signed(signed_flag); val = scope->set_parameter((*cur).first, val, msb, lsb, signed_flag); assert(val); delete val; } // Run through the defparams for this module, elaborate the // expressions in this context and save the result is a table // for later final override. // It is OK to elaborate the expressions of the defparam here // because Verilog requires that the expressions only use // local parameter names. It is *not* OK to do the override // here because the parameter receiving the assignment may be // in a scope not discovered by this pass. for (hparm_it_t cur = defparms.begin() ; cur != defparms.end() ; cur ++ ) { PExpr*ex = (*cur).second; assert(ex); NetExpr*val = ex->elaborate_pexpr(des, scope); if (val == 0) continue; scope->defparams[(*cur).first] = val; } // Evaluate the attributes. Evaluate them in the scope of the // module that the attribute is attached to. Is this correct? unsigned nattr; attrib_list_t*attr = evaluate_attributes(attributes, nattr, des, scope); for (unsigned idx = 0 ; idx < nattr ; idx += 1) scope->attribute(attr[idx].key, attr[idx].val); delete[]attr; // Tasks introduce new scopes, so scan the tasks in this // module. Create a scope for the task and pass that to the // elaborate_scope method of the PTask for detailed // processing. typedef map::const_iterator tasks_it_t; for (tasks_it_t cur = tasks_.begin() ; cur != tasks_.end() ; cur ++ ) { NetScope*task_scope = new NetScope(scope, (*cur).first, NetScope::TASK); (*cur).second->elaborate_scope(des, task_scope); } // Functions are very similar to tasks, at least from the // perspective of scopes. So handle them exactly the same // way. typedef map::const_iterator funcs_it_t; for (funcs_it_t cur = funcs_.begin() ; cur != funcs_.end() ; cur ++ ) { NetScope*func_scope = new NetScope(scope, (*cur).first, NetScope::FUNC); (*cur).second->elaborate_scope(des, func_scope); } // Gates include modules, which might introduce new scopes, so // scan all of them to create those scopes. typedef list::const_iterator gates_it_t; for (gates_it_t cur = gates_.begin() ; cur != gates_.end() ; cur ++ ) { (*cur) -> elaborate_scope(des, scope); } // 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_scope(des, scope); } // Scan through all the named events in this scope. We do not // need anything more then the current scope to do this // elaboration, so do it now. This allows for normal // elaboration to reference these events. for (map::const_iterator et = events.begin() ; et != events.end() ; et ++ ) { (*et).second->elaborate_scope(des, scope); } for (map::const_iterator cur = datum.begin() ; cur != datum.end() ; cur ++ ) { (*cur).second->elaborate_scope(des, scope); } return des->errors == 0; } void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const { if (get_name() == "") { cerr << get_line() << ": error: Instantiation of module " << mod->mod_name() << " requires an instance name." << endl; des->errors += 1; return; } // Missing module instance names have already been rejected. assert(get_name() != ""); // Check for duplicate scopes. Simply look up the scope I'm // about to create, and if I find it then somebody beat me to // it. if (sc->child(get_name())) { cerr << get_line() << ": error: Instance/Scope name " << get_name() << " already used in this context." << endl; des->errors += 1; return; } // check for recursive instantiation by scanning the current // scope and its parents. Look for a module instantiation of // the same module, but farther up in the scope. for (NetScope*scn = sc ; scn ; scn = scn->parent()) { if (scn->type() != NetScope::MODULE) continue; if (strcmp(mod->mod_name(), scn->module_name()) != 0) continue; cerr << get_line() << ": error: You cannot instantiate " << "module " << mod->mod_name() << " within itself." << endl; cerr << get_line() << ": : The offending instance is " << sc->name() << "." << get_name() << " within " << scn->name() << "." << endl; des->errors += 1; return; } verinum*msb = msb_ ? msb_->eval_const(des, sc) : 0; verinum*lsb = lsb_ ? lsb_->eval_const(des, sc) : 0; assert( (msb == 0) || (lsb != 0) ); long instance_low = 0; long instance_high = 0; long instance_count = 1; bool instance_array = false; if (msb) { instance_array = true; instance_high = msb->as_long(); instance_low = lsb->as_long(); if (instance_high > instance_low) instance_count = instance_high - instance_low + 1; else instance_count = instance_low - instance_high + 1; } NetScope::scope_vec_t instances (instance_count); if (debug_scopes) { cerr << get_line() << ": debug: Create " << instance_count << " instances of " << get_name() << "." << endl; } // Run through the module instances, and make scopes out of // them. Also do parameter overrides that are done on the // instantiation line. for (int idx = 0 ; idx < instance_count ; idx += 1) { perm_string use_name = get_name(); if (instance_array) { char name_buf[128]; int instance_idx = idx; if (instance_low < instance_high) instance_idx = instance_low + idx; else instance_idx = instance_low - idx; snprintf(name_buf, sizeof name_buf, "%s[%d]", get_name().str(), instance_idx); use_name = lex_strings.make(name_buf); } if (debug_scopes) { cerr << get_line() << ": debug: Module instance " << use_name << " becomes child of " << sc->name() << "." << endl; } // Create the new scope as a MODULE with my name. NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE); my_scope->set_module_name(mod->mod_name()); my_scope->default_nettype(mod->default_nettype); instances[idx] = my_scope; // Set time units and precision. my_scope->time_unit(mod->time_unit); my_scope->time_precision(mod->time_precision); des->set_precision(mod->time_precision); // This call actually arranges for the description of the // module type to process this instance and handle parameters // and sub-scopes that might occur. Parameters are also // created in that scope, as they exist. (I'll override them // later.) mod->elaborate_scope(des, my_scope); // Look for module parameter replacements. The "replace" map // maps parameter name to replacement expression that is // passed. It is built up by the ordered overrides or named // overrides. typedef map::const_iterator mparm_it_t; map replace; // Positional parameter overrides are matched to parameter // names by using the param_names list of parameter // names. This is an ordered list of names so the first name // is parameter 0, the second parameter 1, and so on. if (overrides_) { assert(parms_ == 0); list::const_iterator cur = mod->param_names.begin(); unsigned idx = 0; for (;;) { if (idx >= overrides_->count()) break; if (cur == mod->param_names.end()) break; replace[*cur] = (*overrides_)[idx]; idx += 1; cur ++; } } // Named parameter overrides carry a name with each override // so the mapping into the replace list is much easier. if (parms_) { assert(overrides_ == 0); for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) replace[parms_[idx].name] = parms_[idx].parm; } // And here we scan the replacements we collected. Elaborate // the expression in my context, then replace the sub-scope // parameter value with the new expression. for (mparm_it_t cur = replace.begin() ; cur != replace.end() ; cur ++ ) { PExpr*tmp = (*cur).second; // No expression means that the parameter is not // replaced at all. if (tmp == 0) continue; NetExpr*val = tmp->elaborate_pexpr(des, sc); bool flag = my_scope->replace_parameter((*cur).first, val); if (! flag) { cerr << val->get_line() << ": warning: parameter " << (*cur).first << " not found in " << sc->name() << "." << endl; } } } /* Stash the instance array of scopes into the parent scope. Later elaboration passes will use this vector to further elaborate the array. */ sc->instance_arrays[get_name()] = instances; } /* * Elaborate the datum within the module. This variable may be * within a subscope (i.e., a function or task) so use the components * of the name to find the precise scope where this item goes. */ void PData::elaborate_scope(Design*des, NetScope*scope) const { NetScope*sub_scope = scope; for (unsigned idx = 0 ; idx < (hname_.component_count()-1); idx += 1) { sub_scope = sub_scope->child(hname_.peek_name(idx)); if (sub_scope == 0) { cerr << get_line() << ": internal error: " << "Could not find sub-scope " << hname_.peek_name(idx) << " of " << hname_ << " in module " << scope->name() << endl; des->errors += 1; return; } } const char*basename = hname_.peek_tail_name(); NetVariable*tmp = new NetVariable(lex_strings.make(basename)); tmp->set_line(*this); sub_scope->add_variable(tmp); } /* * The isn't really able to create new scopes, but it does create the * event name in the current scope, so can be done during the * elaborate_scope scan. Note that the name_ of the PEvent object has * no hierarchy, but neither does the NetEvent, until it is stored in * the NetScope object. */ void PEvent::elaborate_scope(Design*des, NetScope*scope) const { NetEvent*ev = new NetEvent(name_); ev->set_line(*this); scope->add_event(ev); } void PFunction::elaborate_scope(Design*des, NetScope*scope) const { assert(scope->type() == NetScope::FUNC); if (statement_) statement_->elaborate_scope(des, scope); } void PTask::elaborate_scope(Design*des, NetScope*scope) const { assert(scope->type() == NetScope::TASK); if (statement_) statement_->elaborate_scope(des, scope); } /* * The base statement does not have sub-statements and does not * introduce any scope, so this is a no-op. */ void Statement::elaborate_scope(Design*, NetScope*) const { } /* * When I get a behavioral block, check to see if it has a name. If it * does, then create a new scope for the statements within it, * otherwise use the current scope. Use the selected scope to scan the * statements that I contain. */ void PBlock::elaborate_scope(Design*des, NetScope*scope) const { NetScope*my_scope = scope; if (name_ != 0) { my_scope = new NetScope(scope, name_, bl_type_==BL_PAR ? NetScope::FORK_JOIN : NetScope::BEGIN_END); } for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) list_[idx] -> elaborate_scope(des, my_scope); } /* * The case statement itself does not introduce scope, but contains * other statements that may be named blocks. So scan the case items * with the elaborate_scope method. */ void PCase::elaborate_scope(Design*des, NetScope*scope) const { assert(items_); for (unsigned idx = 0 ; idx < (*items_).count() ; idx += 1) { assert( (*items_)[idx] ); if (Statement*sp = (*items_)[idx]->stat) sp -> elaborate_scope(des, scope); } } /* * The conditional statement (if-else) does not introduce scope, but * the statements of the clauses may, so elaborate_scope the contained * statements. */ void PCondit::elaborate_scope(Design*des, NetScope*scope) const { if (if_) if_ -> elaborate_scope(des, scope); if (else_) else_ -> elaborate_scope(des, scope); } /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained * statement. */ void PDelayStatement::elaborate_scope(Design*des, NetScope*scope) const { if (statement_) statement_ -> elaborate_scope(des, scope); } /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained * statement. */ void PEventStatement::elaborate_scope(Design*des, NetScope*scope) const { if (statement_) statement_ -> elaborate_scope(des, scope); } /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained * statement. */ void PForever::elaborate_scope(Design*des, NetScope*scope) const { if (statement_) statement_ -> elaborate_scope(des, scope); } /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained * statement. */ void PForStatement::elaborate_scope(Design*des, NetScope*scope) const { if (statement_) statement_ -> elaborate_scope(des, scope); } /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained * statement. */ void PRepeat::elaborate_scope(Design*des, NetScope*scope) const { if (statement_) statement_ -> elaborate_scope(des, scope); } /* * Statements that contain a further statement but do not * intrinsically add a scope need to elaborate_scope the contained * statement. */ void PWhile::elaborate_scope(Design*des, NetScope*scope) const { if (statement_) statement_ -> elaborate_scope(des, scope); } /* * $Log: elab_scope.cc,v $ * Revision 1.35 2004/09/10 00:15:17 steve * Missing stdio.h header for warnings. * * Revision 1.34 2004/09/05 17:44:41 steve * Add support for module instance arrays. * * Revision 1.33 2004/08/26 04:02:03 steve * Add support for localparam ranges. * * Revision 1.32 2004/06/13 04:56:54 steve * Add support for the default_nettype directive. * * Revision 1.31 2004/05/25 19:21:06 steve * More identifier lists use perm_strings. * * Revision 1.30 2004/02/20 06:22:56 steve * parameter keys are per_strings. * * Revision 1.29 2004/02/19 07:06:57 steve * LPM, logic and Variables have perm_string names. * * Revision 1.28 2004/02/18 17:11:55 steve * Use perm_strings for named langiage items. * * Revision 1.27 2003/09/13 01:01:51 steve * Spelling fixes. * * Revision 1.26 2003/08/28 04:11:17 steve * Spelling patch. * * Revision 1.25 2003/06/24 01:38:02 steve * Various warnings fixed. * * Revision 1.24 2003/06/20 00:53:19 steve * Module attributes from the parser * through to elaborated form. * * Revision 1.23 2003/06/16 00:34:08 steve * Functions can have sub-scope. * * Revision 1.22 2003/06/13 19:10:46 steve * Properly manage real variables in subscopes. * * Revision 1.21 2003/05/30 02:55:32 steve * Support parameters in real expressions and * as real expressions, and fix multiply and * divide with real results. * * Revision 1.20 2003/03/06 00:28:41 steve * All NetObj objects have lex_string base names. * * Revision 1.19 2003/01/27 05:09:17 steve * Spelling fixes. * * Revision 1.18 2003/01/26 21:15:58 steve * Rework expression parsing and elaboration to * accommodate real/realtime values and expressions. * * Revision 1.17 2002/10/19 22:59:49 steve * Redo the parameter vector support to allow * parameter names in range expressions. * * Revision 1.16 2002/09/01 03:01:48 steve * Properly cast signedness of parameters with ranges. * * Revision 1.15 2002/08/19 02:39:16 steve * Support parameters with defined ranges. * * Revision 1.14 2002/08/12 01:34:59 steve * conditional ident string using autoconfig. * * Revision 1.13 2001/12/30 04:47:57 steve * Properly handle empty target in positionla parameter override. * * Revision 1.12 2001/12/03 04:47:14 steve * Parser and pform use hierarchical names as hname_t * objects instead of encoded strings. */