/* * Copyright (c) 2000Stephen 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 */ #if !defined(WINNT) && !defined(macintosh) #ident "$Id: net_design.cc,v 1.19 2001/04/02 02:28:12 steve Exp $" #endif /* * This source file contains all the implementations of the Design * class declared in netlist.h. */ # include "netlist.h" # include "util.h" # include Design:: Design() : errors(0), root_scope_(0), nodes_(0), procs_(0), lcounter_(0) { procs_idx_ = 0; des_precision_ = 0; } Design::~Design() { } string Design::local_symbol(const string&path) { strstream res; res << "_L" << (lcounter_++) << ends; return path + "." + res.str(); } void Design::set_precision(int val) { if (val < des_precision_) des_precision_ = val; } int Design::get_precision() const { return des_precision_; } unsigned long Design::scale_to_precision(unsigned long val, const NetScope*scope) const { int units = scope->time_unit(); assert( units >= des_precision_ ); while (units > des_precision_) { units -= 1; val *= 10; } return val; } NetScope* Design::make_root_scope(const string&root) { assert(root_scope_ == 0); root_scope_ = new NetScope(0, root, NetScope::MODULE); root_scope_->set_module_name(root.c_str()); return root_scope_; } NetScope* Design::find_root_scope() { assert(root_scope_); return root_scope_; } const NetScope* Design::find_root_scope() const { assert(root_scope_); return root_scope_; } /* * This method locates a scope in the design, given its rooted * heirarchical name. Each component of the key is used to scan one * more step down the tree until the name runs out or the search * fails. */ NetScope* Design::find_scope(const string&key) const { if (key == root_scope_->name()) return root_scope_; string path = key; string root = parse_first_name(path); NetScope*cur = root_scope_; if (root != cur->name()) return 0; while (cur) { string next = parse_first_name(path); cur = cur->child(next); if (path == "") return cur; } return cur; } /* * This is a relative lookup of a scope by name. The starting point is * the scope parameter is the place within which I start looking for * the scope. If I do not find the scope within the passed scope, * start looking in parent scopes until I find it, or I run out of * parent scopes. */ NetScope* Design::find_scope(NetScope*scope, const string&name) const { assert(scope); for ( ; scope ; scope = scope->parent()) { string path = name; string key = parse_first_name(path); NetScope*cur = scope; do { cur = cur->child(key); if (cur == 0) break; key = parse_first_name(path); } while (key != ""); if (cur) return cur; } // Last chance. Look for the name starting at the root. return find_scope(name); } /* * Find a parameter from within a specified context. If the name is * not here, keep looking up until I run out of up to look at. The * method works by scanning scopes, starting with the passed scope and * working up towards the root, looking for the named parameter. The * name in this case can be hierarchical, so there is an inner loop to * follow the scopes of the name down to to key. */ const NetExpr* Design::find_parameter(const NetScope*scope, const string&name) const { for ( ; scope ; scope = scope->parent()) { string path = name; string key = parse_first_name(path); const NetScope*cur = scope; while (path != "") { cur = cur->child(key); if (cur == 0) break; key = parse_first_name(path); } if (cur == 0) continue; if (const NetExpr*res = cur->get_parameter(key)) return res; } return 0; } /* * This method runs through the scope, noticing the defparam * statements that were collected during the elaborate_scope pass and * applying them to the target parameters. The implementation actually * works by using a specialized method from the NetScope class that * does all the work for me. */ void Design::run_defparams() { root_scope_->run_defparams(this); } void NetScope::run_defparams(Design*des) { NetScope*cur = sub_; while (cur) { cur->run_defparams(des); cur = cur->sib_; } map::const_iterator pp; for (pp = defparams.begin() ; pp != defparams.end() ; pp ++ ) { NetExpr*val = (*pp).second; string path = (*pp).first; string name = parse_last_name(path); NetScope*targ_scope = des->find_scope(this, path); if (targ_scope == 0) { cerr << val->get_line() << ": warning: scope of " << path << "." << name << " not found." << endl; continue; } val = targ_scope->set_parameter(name, val); if (val == 0) { cerr << val->get_line() << ": warning: parameter " << name << " not found in " << targ_scope->name() << "." << endl; } else { delete val; } } } void Design::evaluate_parameters() { root_scope_->evaluate_parameters(this); } void NetScope::evaluate_parameters(Design*des) { NetScope*cur = sub_; while (cur) { cur->evaluate_parameters(des); cur = cur->sib_; } // Evaluate the parameter values. The parameter expressions // have already been elaborated and replaced by the scope // scanning code. Now the parameter expression can be fully // evaluated, or it cannot be evaluated at all. typedef map::iterator mparm_it_t; for (mparm_it_t cur = parameters_.begin() ; cur != parameters_.end() ; cur ++) { // Get the NetExpr for the parameter. NetExpr*expr = (*cur).second; assert(expr); // If it's already a NetEConst, then this parameter is done. if (dynamic_cast(expr)) continue; // Try to evaluate the expression. NetExpr*nexpr = expr->eval_tree(); if (nexpr == 0) { cerr << (*cur).second->get_line() << ": internal error: " "unable to evaluate parm expression: " << *expr << endl; des->errors += 1; continue; } // The evaluate worked, replace the old expression with // this constant value. assert(nexpr); delete expr; (*cur).second = nexpr; } } string Design::get_flag(const string&key) const { map::const_iterator tmp = flags_.find(key); if (tmp == flags_.end()) return ""; else return (*tmp).second; } /* * This method looks for a signal (reg, wire, whatever) starting at * the specified scope. If the name is hierarchical, it is split into * scope and name and the scope used to find the proper starting point * for the real search. * * It is the job of this function to properly implement Verilog scope * rules as signals are concerned. */ NetNet* Design::find_signal(NetScope*scope, const string&name) { assert(scope); /* If the name has a path attached to it, parse it off and use that to locate the desired starting scope. */ string path = name; string key = parse_last_name(path); if (path != "") scope = find_scope(scope, path); /* Now from the starting point, scan upwards until we find the signal or we find a module boundary. */ while (scope) { if (NetNet*net = scope->find_signal(key)) return net; if (scope->type() == NetScope::MODULE) break; scope = scope->parent(); } return 0; } NetMemory* Design::find_memory(NetScope*scope, const string&name) { assert(scope); /* If the name has a path attached to it, parse it off and use that to locate the desired scope. */ string path = name; string key = parse_last_name(path); if (path != "") scope = find_scope(scope, path); while (scope) { if (NetMemory*mem = scope->find_memory(key)) return mem; scope = scope->parent(); } return 0; } void Design::find_symbol(NetScope*scope, const string&name, NetNet*&sig, NetMemory*&mem) { sig = 0; mem = 0; /* If the name has a path attached to it, parse it off and use that to locate the desired scope. Then locate the key within that scope. */ string path = name; string key = parse_last_name(path); if (path != "") scope = find_scope(scope, path); /* If there is no path, then just search upwards for the key. */ while (scope) { if (NetNet*cur = scope->find_signal(key)) { sig = cur; return; } if (NetMemory*cur = scope->find_memory(key)) { mem = cur; return; } scope = scope->parent(); } } NetFuncDef* Design::find_function(NetScope*scope, const string&name) { assert(scope); NetScope*func = find_scope(scope, name); if (func && (func->type() == NetScope::FUNC)) return func->func_def(); return 0; } NetFuncDef* Design::find_function(const string&key) { NetScope*func = find_scope(key); if (func && (func->type() == NetScope::FUNC)) return func->func_def(); return 0; } NetScope* Design::find_task(NetScope*scope, const string&name) { NetScope*task = find_scope(scope, name); if (task && (task->type() == NetScope::TASK)) return task; return 0; } NetScope* Design::find_task(const string&key) { NetScope*task = find_scope(key); if (task && (task->type() == NetScope::TASK)) return task; return 0; } void Design::add_node(NetNode*net) { assert(net->design_ == 0); if (nodes_ == 0) { net->node_next_ = net; net->node_prev_ = net; } else { net->node_next_ = nodes_->node_next_; net->node_prev_ = nodes_; net->node_next_->node_prev_ = net; net->node_prev_->node_next_ = net; } nodes_ = net; net->design_ = this; } void Design::del_node(NetNode*net) { assert(net->design_ == this); if (nodes_ == net) nodes_ = net->node_prev_; if (nodes_ == net) { nodes_ = 0; } else { net->node_next_->node_prev_ = net->node_prev_; net->node_prev_->node_next_ = net->node_next_; } net->design_ = 0; } void Design::add_process(NetProcTop*pro) { pro->next_ = procs_; procs_ = pro; } void Design::delete_process(NetProcTop*top) { assert(top); if (procs_ == top) { procs_ = top->next_; } else { NetProcTop*cur = procs_; while (cur->next_ != top) { assert(cur->next_); cur = cur->next_; } cur->next_ = top->next_; } if (procs_idx_ == top) procs_idx_ = top->next_; delete top; } /* * $Log: net_design.cc,v $ * Revision 1.19 2001/04/02 02:28:12 steve * Generate code for task calls. * * Revision 1.18 2001/01/14 23:04:56 steve * Generalize the evaluation of floating point delays, and * get it working with delay assignment statements. * * Allow parameters to be referenced by hierarchical name. * * Revision 1.17 2000/12/16 01:45:48 steve * Detect recursive instantiations (PR#2) * * Revision 1.16 2000/09/24 17:41:13 steve * fix null pointer when elaborating undefined task. * * Revision 1.15 2000/08/26 00:54:03 steve * Get at gate information for ivl_target interface. * * Revision 1.14 2000/08/12 17:59:48 steve * Limit signal scope search at module boundaries. * * Revision 1.13 2000/07/30 18:25:43 steve * Rearrange task and function elaboration so that the * NetTaskDef and NetFuncDef functions are created during * signal enaboration, and carry these objects in the * NetScope class instead of the extra, useless map in * the Design class. * * Revision 1.12 2000/07/23 02:41:32 steve * Excessive assert. * * Revision 1.11 2000/07/22 22:09:03 steve * Parse and elaborate timescale to scopes. * * Revision 1.10 2000/07/16 04:56:08 steve * Handle some edge cases during node scans. * * Revision 1.9 2000/07/14 06:12:57 steve * Move inital value handling from NetNet to Nexus * objects. This allows better propogation of inital * values. * * Clean up constant propagation a bit to account * for regs that are not really values. * * Revision 1.8 2000/05/02 16:27:38 steve * Move signal elaboration to a seperate pass. * * Revision 1.7 2000/05/02 03:13:31 steve * Move memories to the NetScope object. * * Revision 1.6 2000/05/02 00:58:12 steve * Move signal tables to the NetScope class. * * Revision 1.5 2000/04/28 16:50:53 steve * Catch memory word parameters to tasks. * * Revision 1.4 2000/04/10 05:26:06 steve * All events now use the NetEvent class. * * Revision 1.3 2000/03/11 03:25:52 steve * Locate scopes in statements. * * Revision 1.2 2000/03/10 06:20:48 steve * Handle defparam to partial hierarchical names. * * Revision 1.1 2000/03/08 04:36:53 steve * Redesign the implementation of scopes and parameters. * I now generate the scopes and notice the parameters * in a separate pass over the pform. Once the scopes * are generated, I can process overrides and evalutate * paremeters before elaboration begins. * */