diff --git a/Module.cc b/Module.cc index 596d902102..ec92e9172a 100644 --- a/Module.cc +++ b/Module.cc @@ -54,16 +54,6 @@ void Module::add_function(perm_string name, PFunction *func) funcs_[name] = func; } -PWire* Module::add_wire(PWire*wire) -{ - PWire*&ep = wires_[wire->path()]; - if (ep) return ep; - - assert(ep == 0); - ep = wire; - return wire; -} - void Module::add_behavior(PProcess*b) { behaviors_.push_back(b); @@ -111,15 +101,6 @@ unsigned Module::find_port(const char*name) const } -PWire* Module::get_wire(const pform_name_t&name) const -{ - map::const_iterator obj = wires_.find(name); - if (obj == wires_.end()) - return 0; - else - return (*obj).second; -} - PGate* Module::get_gate(perm_string name) { for (list::iterator cur = gates_.begin() diff --git a/Module.h b/Module.h index 61757b4b73..22ad3ff2f3 100644 --- a/Module.h +++ b/Module.h @@ -1,7 +1,7 @@ #ifndef __Module_H #define __Module_H /* - * Copyright (c) 1998-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -18,9 +18,7 @@ * 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: Module.h,v 1.43 2007/05/24 04:07:11 steve Exp $" -#endif + # include # include @@ -133,12 +131,6 @@ class Module : public PScope, public LineInfo { perm_string mod_name() const { return pscope_name(); } void add_gate(PGate*gate); - - // The add_wire method adds a wire by name, but only if the - // wire name doesn't already exist. Either way, the result is - // the existing wire or the pointer passed in. - PWire* add_wire(PWire*wire); - void add_behavior(PProcess*behave); void add_task(perm_string name, PTask*def); void add_function(perm_string name, PFunction*def); @@ -147,9 +139,6 @@ class Module : public PScope, public LineInfo { const svector& get_port(unsigned idx) const; unsigned find_port(const char*name) const; - // Find a wire by name. This is used for connecting gates to - // existing wires, etc. - PWire* get_wire(const pform_name_t&name) const; PGate* get_gate(perm_string name); const list& get_gates() const; @@ -164,7 +153,6 @@ class Module : public PScope, public LineInfo { bool elaborate_sig(Design*, NetScope*scope) const; private: - map wires_; list gates_; list behaviors_; map tasks_; @@ -178,26 +166,4 @@ class Module : public PScope, public LineInfo { Module& operator= (const Module&); }; - -/* - * $Log: Module.h,v $ - * Revision 1.43 2007/05/24 04:07:11 steve - * Rework the heirarchical identifier parse syntax and pform - * to handle more general combinations of heirarch and bit selects. - * - * Revision 1.42 2007/04/19 02:52:53 steve - * Add support for -v flag in command file. - * - * Revision 1.41 2006/09/23 04:57:19 steve - * Basic support for specify timing. - * - * Revision 1.40 2006/04/10 00:37:42 steve - * Add support for generate loops w/ wires and gates. - * - * Revision 1.39 2006/03/30 01:49:07 steve - * Fix instance arrays indexed by overridden parameters. - * - * Revision 1.38 2005/07/11 16:56:50 steve - * Remove NetVariable and ivl_variable_t structures. - */ #endif diff --git a/PGenerate.cc b/PGenerate.cc index aa9b597fe6..03fcfb286f 100644 --- a/PGenerate.cc +++ b/PGenerate.cc @@ -33,19 +33,9 @@ PGenerate::~PGenerate() { } -PWire* PGenerate::add_wire(PWire*wire) +PWire* PGenerate::get_wire(perm_string name) const { - PWire*&ep = wires[wire->path()]; - if (ep) return ep; - - assert(ep == 0); - ep = wire; - return wire; -} - -PWire* PGenerate::get_wire(const pform_name_t&name) const -{ - map::const_iterator obj = wires.find(name); + map::const_iterator obj = wires.find(name); if (obj == wires.end()) return 0; else diff --git a/PGenerate.h b/PGenerate.h index b29c60b25d..842e0c49a8 100644 --- a/PGenerate.h +++ b/PGenerate.h @@ -71,9 +71,8 @@ class PGenerate : public LineInfo { PExpr*loop_test; PExpr*loop_step; - mapwires; - PWire* add_wire(PWire*); - PWire* get_wire(const pform_name_t&name) const; + mapwires; + PWire* get_wire(perm_string name) const; list gates; void add_gate(PGate*); diff --git a/PScope.cc b/PScope.cc index 541d52d43a..addd4ea4fd 100644 --- a/PScope.cc +++ b/PScope.cc @@ -27,3 +27,12 @@ PScope::PScope(perm_string n, PScope*p) PScope::~PScope() { } + +PWire* PScope::wires_find(perm_string name) +{ + map::const_iterator cur = wires.find(name); + if (cur == wires.end()) + return 0; + else + return (*cur).second; +} diff --git a/PScope.h b/PScope.h index 39c445e912..054be2874e 100644 --- a/PScope.h +++ b/PScope.h @@ -24,6 +24,10 @@ # include class PEvent; +class PWire; + +class Design; +class NetScope; /* * The PScope class is a base representation of an object that @@ -50,9 +54,18 @@ class PScope { perm_string pscope_name() const { return name_; } PScope* pscope_parent() { return parent_; } + // Nets an variables (wires) in the scope + mapwires; + PWire* wires_find(perm_string name); + // Named events in the scope. mapevents; + protected: + void dump_wires_(ostream&out, unsigned indent) const; + + bool elaborate_sig_wires_(Design*des, NetScope*scope) const; + private: perm_string name_; PScope*parent_; diff --git a/PWire.cc b/PWire.cc index d26aa10af6..ec4161c2f4 100644 --- a/PWire.cc +++ b/PWire.cc @@ -22,11 +22,11 @@ # include "PExpr.h" # include -PWire::PWire(const pform_name_t&n, +PWire::PWire(perm_string n, NetNet::Type t, NetNet::PortType pt, ivl_variable_type_t dt) -: hname_(n), type_(t), port_type_(pt), data_type_(dt), +: name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), port_msb_(0), port_lsb_(0), port_set_(false), net_msb_(0), net_lsb_(0), net_set_(false), error_cnt_(0), @@ -44,9 +44,9 @@ NetNet::Type PWire::get_wire_type() const return type_; } -const pform_name_t& PWire::path() const +perm_string PWire::basename() const { - return hname_; + return name_; } bool PWire::set_wire_type(NetNet::Type t) @@ -153,7 +153,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) switch (type) { case SR_PORT: if (port_set_) { - cerr << get_fileline() << ": error: Port ``" << hname_ + cerr << get_fileline() << ": error: Port ``" << name_ << "'' has already been declared a port." << endl; error_cnt_ += 1; } else { @@ -165,7 +165,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) case SR_NET: if (net_set_) { - cerr << get_fileline() << ": error: Net ``" << hname_ + cerr << get_fileline() << ": error: Net ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } else { @@ -178,12 +178,12 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) case SR_BOTH: if (port_set_ || net_set_) { if (port_set_) { - cerr << get_fileline() << ": error: Port ``" << hname_ + cerr << get_fileline() << ": error: Port ``" << name_ << "'' has already been declared a port." << endl; error_cnt_ += 1; } if (net_set_) { - cerr << get_fileline() << ": error: Net ``" << hname_ + cerr << get_fileline() << ": error: Net ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } @@ -202,7 +202,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type) void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) { if (lidx_ != 0 || ridx_ != 0) { - cerr << get_fileline() << ": error: Array ``" << hname_ + cerr << get_fileline() << ": error: Array ``" << name_ << "'' has already been declared." << endl; error_cnt_ += 1; } else { diff --git a/PWire.h b/PWire.h index 3cf02908d3..2efa9c72b9 100644 --- a/PWire.h +++ b/PWire.h @@ -56,13 +56,13 @@ enum PWSRType {SR_PORT, SR_NET, SR_BOTH}; class PWire : public LineInfo { public: - PWire(const pform_name_t&hname, + PWire(perm_string name, NetNet::Type t, NetNet::PortType pt, ivl_variable_type_t dt); // Return a hierarchical name. - const pform_name_t&path() const; + perm_string basename() const; NetNet::Type get_wire_type() const; bool set_wire_type(NetNet::Type); @@ -90,7 +90,7 @@ class PWire : public LineInfo { NetNet* elaborate_sig(Design*, NetScope*scope) const; private: - pform_name_t hname_; + perm_string name_; NetNet::Type type_; NetNet::PortType port_type_; ivl_variable_type_t data_type_; diff --git a/Statement.h b/Statement.h index 09567b4183..aedaf17fce 100644 --- a/Statement.h +++ b/Statement.h @@ -84,6 +84,7 @@ class Statement : public LineInfo { virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; }; /* @@ -166,6 +167,7 @@ class PBlock : public PScope, public Statement { virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; private: const BL_TYPE bl_type_; @@ -217,6 +219,7 @@ class PCase : public Statement { virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; private: @@ -252,6 +255,7 @@ class PCondit : public Statement { virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; private: @@ -286,6 +290,7 @@ class PDelayStatement : public Statement { virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; private: PExpr*delay_; @@ -333,6 +338,7 @@ class PEventStatement : public Statement { virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; // This method is used to elaborate, but attach a previously // elaborated statement to the event. @@ -366,6 +372,7 @@ class PForever : public Statement { virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; private: @@ -381,6 +388,7 @@ class PForStatement : public Statement { virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; virtual void dump(ostream&out, unsigned ind) const; private: diff --git a/design_dump.cc b/design_dump.cc index 03821c0447..da4b2253b3 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -309,8 +309,14 @@ void NetPow::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "LPM_POW (NetPow): " << name() << " scope=" << scope_path(scope()) - << " delay=(" << *rise_time() << "," << *fall_time() << "," - << *decay_time() << ")" << endl; + << " delay=("; + if (rise_time()) + o << *rise_time() << "," << *fall_time() << "," + << *decay_time(); + else + o << "0,0,0"; + + o << ")" << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } @@ -980,7 +986,10 @@ void NetScope::dump(ostream&o) const o << " MISSING FUNCTION DEFINITION" << endl; break; case TASK: - task_def()->dump(o, 4); + if (task_def()) + task_def()->dump(o, 4); + else + o << " MISSING TASK DEFINITION" << endl; break; default: break; diff --git a/elab_sig.cc b/elab_sig.cc index ab484bfa05..3119e976cb 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -28,46 +28,58 @@ # 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" -/* - * This local function checks if a named signal is connected to a - * port. It looks in the array of ports passed, for NetEIdent objects - * within the port_t that have a matching name. - */ -static bool signal_is_in_port(const svector&ports, - NetNet*sig) +void Statement::elaborate_sig(Design*des, NetScope*scope) const { - perm_string name = sig->name(); +} - for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) { +bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const +{ + bool flag = true; - Module::port_t*pp = ports[idx]; - // Skip internally unconnected ports. - if (pp == 0) - continue; + for (map::const_iterator wt = wires.begin() + ; wt != wires.end() ; wt ++ ) { - // This port has an internal connection. In this case, - // the port has 0 or more NetEIdent objects concatenated - // together that form the port. + PWire*cur = (*wt).second; + NetNet*sig = cur->elaborate_sig(des, scope); - // Note that module ports should not have any hierarchy - // in their names: they are in the root of the module - // scope by definition. - for (unsigned cc = 0 ; cc < pp->expr.count() ; cc += 1) { - perm_string pname = peek_tail_name(pp->expr[cc]->path()); - assert(pp->expr[cc]); - if (pname == name) - return true; + /* 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 false; + return flag; } bool Module::elaborate_sig(Design*des, NetScope*scope) const @@ -81,14 +93,26 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const if (pp == 0) continue; - map::const_iterator wt; + // 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()); - wt = wires_.find(port_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()) { + if (wt == wires.end()) { cerr << get_fileline() << ": error: " - << "Port " << pp->expr[cc]->path() << " (" + << "Port " << port_path << " (" << (idx+1) << ") of module " << mod_name() << " is not declared within module." << endl; des->errors += 1; @@ -106,58 +130,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const } } - for (map::const_iterator wt = wires_.begin() - ; wt != wires_.end() ; wt ++ ) { - - PWire*cur = (*wt).second; - NetNet*sig = cur->elaborate_sig(des, scope); - - // If this wire is a signal of the module (as opposed to - // a port of a function) and is a port, then check that - // the module knows about it. We know that the signal is - // the name of a signal within a subscope of a module - // (a task, a function, etc.) if the name for the PWire - // has hierarchy. - - if (sig && (sig->scope() == scope) - && (cur->get_port_type() != NetNet::NOT_A_PORT)) { - - if (! signal_is_in_port(ports, sig)) { - - cerr << cur->get_fileline() << ": error: Signal " - << sig->name() << " has a declared direction " - << "but is not a port." << endl; - des->errors += 1; - } - } - - - /* If the signal is an input and is also declared as a - reg, then report an error. */ - - if (sig && (sig->scope() == scope) - && (sig->port_type() == NetNet::PINPUT) - && (sig->type() == NetNet::REG)) { - - cerr << cur->get_fileline() << ": error: " - << cur->path() << " in module " - << scope->module_name() - << " declared as input and as a reg type." << endl; - des->errors += 1; - } - - if (sig && (sig->scope() == scope) - && (sig->port_type() == NetNet::PINOUT) - && (sig->type() == NetNet::REG)) { - - cerr << cur->get_fileline() << ": error: " - << cur->path() << " in module " - << scope->module_name() - << " declared as inout and as a reg type." << 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 @@ -216,6 +189,18 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const (*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; } @@ -276,7 +261,7 @@ 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; + typedef map::const_iterator wires_it_t; for (wires_it_t wt = wires.begin() ; wt != wires.end() ; wt ++ ) { @@ -284,7 +269,7 @@ bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const if (debug_elaborate) cerr << get_fileline() << ": debug: Elaborate PWire " - << cur->path() << " in scope " << scope_path(scope) << endl; + << cur->basename() << " in scope " << scope_path(scope) << endl; cur->elaborate_sig(des, scope); } @@ -316,6 +301,8 @@ 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. */ @@ -416,19 +403,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const name. We know by design that the port name is given as two components: .. */ - pform_name_t path = (*ports_)[idx]->path(); - ivl_assert(*this, path.size() == 2); - - perm_string pname = peek_tail_name(path); - perm_string ppath = peek_head_name(path); - - if (ppath != scope->basename()) { - cerr << get_fileline() << ": internal error: function " - << "port " << (*ports_)[idx]->path() - << " has wrong name for function " - << scope_path(scope) << "." << endl; - des->errors += 1; - } + perm_string pname = (*ports_)[idx]->basename(); NetNet*tmp = scope->find_signal(pname); if (tmp == 0) { @@ -449,6 +424,10 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const assert(def); scope->set_func_def(def); + + // Look for further signals in the sub-statement + if (statement_) + statement_->elaborate_sig(des, scope); } /* @@ -464,24 +443,12 @@ 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) { - /* 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: .. */ - - pform_name_t path = (*ports_)[idx]->path(); - ivl_assert(*this, path.size() == 2); - - perm_string scope_name = peek_head_name(path); - perm_string port_name = peek_tail_name(path); - - /* check that the current scope really does have the - name of the first component of the task port name. Do - this by looking up the task scope in the parent of - the current scope. */ - ivl_assert(*this, scope->basename() == scope_name); + 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 @@ -493,6 +460,7 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const << "Could not find port " << port_name << " in scope " << scope_path(scope) << endl; scope->dump(cerr); + des->errors += 1; } ports[idx] = tmp; @@ -500,6 +468,82 @@ void PTask::elaborate_sig(Design*des, NetScope*scope) const 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 @@ -516,27 +560,6 @@ bool PGate::elaborate_sig(Design*des, NetScope*scope) const */ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const { - - /* The parser may produce hierarchical names for wires. I here - follow the scopes down to the base where I actually want to - elaborate the NetNet object. */ - { pform_name_t tmp_path = hname_; - tmp_path.pop_back(); - while (! tmp_path.empty()) { - name_component_t cur = tmp_path.front(); - tmp_path.pop_front(); - - scope = scope->child( hname_t(cur.name) ); - - if (scope == 0) { - cerr << get_fileline() << ": internal error: " - << "Bad scope component for name " - << hname_ << endl; - assert(scope); - } - } - } - NetNet::Type wtype = type_; if (wtype == NetNet::IMPLICIT) wtype = NetNet::WIRE; @@ -619,12 +642,12 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (port_msb_ == 0) { if (!gn_io_range_error_flag) { cerr << get_fileline() - << ": warning: Scalar port ``" << hname_ + << ": warning: Scalar port ``" << name_ << "'' has a vectored net declaration [" << nmsb << ":" << nlsb << "]." << endl; } else { cerr << get_fileline() - << ": error: Scalar port ``" << hname_ + << ": error: Scalar port ``" << name_ << "'' has a vectored net declaration [" << nmsb << ":" << nlsb << "]." << endl; des->errors += 1; @@ -636,7 +659,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (net_msb_ == 0) { cerr << port_msb_->get_fileline() << ": error: Vectored port ``" - << hname_ << "'' [" << pmsb << ":" << plsb + << name_ << "'' [" << pmsb << ":" << plsb << "] has a scalar net declaration at " << get_fileline() << "." << endl; des->errors += 1; @@ -647,7 +670,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (port_msb_ != 0 && net_msb_ != 0) { cerr << port_msb_->get_fileline() << ": error: Vectored port ``" - << hname_ << "'' [" << pmsb << ":" << plsb + << name_ << "'' [" << pmsb << ":" << plsb << "] has a net declaration [" << nmsb << ":" << nlsb << "] at " << net_msb_->get_fileline() << " that does not match." << endl; @@ -687,7 +710,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if ((lexp == 0) || (rexp == 0)) { cerr << get_fileline() << ": internal error: There is " << "a problem evaluating indices for ``" - << hname_ << "''." << endl; + << name_ << "''." << endl; des->errors += 1; return 0; } @@ -698,7 +721,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if ((lcon == 0) || (rcon == 0)) { cerr << get_fileline() << ": internal error: The indices " << "are not constant for array ``" - << hname_ << "''." << endl; + << name_ << "''." << endl; des->errors += 1; return 0; } @@ -748,24 +771,23 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } } - perm_string name = peek_tail_name(hname_); 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); + ? 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 + << "Signal " << name_ << " in scope " << scope_path(scope) << " defaults to data type " << use_data_type << endl; } diff --git a/elaborate.cc b/elaborate.cc index 45438b9fb2..f5b3b44f8f 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2914,7 +2914,7 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const NetNet*sig = des->find_signal(scope, id1->path()); if (sig == 0) { cerr << id1->get_fileline() << ": register ``" << id1->path() - << "'' unknown in this context." << endl; + << "'' unknown in " << scope_path(scope) << "." << endl; des->errors += 1; return 0; } diff --git a/net_scope.cc b/net_scope.cc index 82ce8a2a39..ec13a553ca 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -295,10 +295,10 @@ void NetScope::rem_event(NetEvent*ev) } -NetEvent* NetScope::find_event(const char*name) +NetEvent* NetScope::find_event(perm_string name) { for (NetEvent*cur = events_; cur ; cur = cur->snext_) - if (strcmp(cur->name(), name) == 0) + if (cur->name() == name) return cur; return 0; @@ -337,7 +337,7 @@ void NetScope::rem_signal(NetNet*net) * is assumed to be the base name of the signal, so no sub-scopes are * searched. */ -NetNet* NetScope::find_signal(const char*key) +NetNet* NetScope::find_signal(perm_string key) { if (signals_ == 0) return 0; diff --git a/netlist.h b/netlist.h index c069e3942a..9d386387cd 100644 --- a/netlist.h +++ b/netlist.h @@ -3272,7 +3272,7 @@ class NetScope : public Attrib { void add_event(NetEvent*); void rem_event(NetEvent*); - NetEvent*find_event(const char*name); + NetEvent*find_event(perm_string name); /* These methods manage signals. The add_ and rem_signal @@ -3282,7 +3282,7 @@ class NetScope : public Attrib { void add_signal(NetNet*); void rem_signal(NetNet*); - NetNet* find_signal(const char*name); + NetNet* find_signal(perm_string name); /* The parent and child() methods allow users of NetScope objects to locate nearby scopes. */ diff --git a/parse.y b/parse.y index 4b5461c99b..5ed7af2d06 100644 --- a/parse.y +++ b/parse.y @@ -26,6 +26,7 @@ # include "pform.h" # include "Statement.h" # include "PSpec.h" +# include # include # include @@ -49,7 +50,7 @@ static struct { task/function that is currently in progress. */ static PTask* current_task = 0; static PFunction* current_function = 0; -static PBlock* current_block = 0; +static stack current_block_stack; /* Later version of bison (including 1.35) will not compile in stack extension if the output is compiled with C++ and either the YYSTYPE @@ -197,7 +198,8 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where) %type udp_input_list udp_sequ_entry udp_comb_entry %type udp_input_declaration_list %type udp_entry_list udp_comb_entry_list udp_sequ_entry_list -%type udp_body udp_port_list +%type udp_body +%type udp_port_list %type udp_port_decl udp_port_decls %type udp_initial udp_init_opt %type udp_initial_expr_opt @@ -1411,28 +1413,18 @@ list_of_port_declarations { svector*tmp = new svector(1); (*tmp)[0] = $1; - /* - * Uncommenting this makes lopd always fully specified. - * Some wanted an implicit net to not be fully defined. - * - * pform_set_net_range($1[0].name); - */ $$ = tmp; } | list_of_port_declarations ',' port_declaration { svector*tmp = new svector(*$1, $3); delete $1; - /* - * Same as above. - * - * pform_set_net_range($3[0].name); - */ $$ = tmp; } | list_of_port_declarations ',' IDENTIFIER { Module::port_t*ptmp; - ptmp = pform_module_port_reference($3, @3.text, + perm_string name = lex_strings.make($3); + ptmp = pform_module_port_reference(name, @3.text, @3.first_line); svector*tmp = new svector(*$1, ptmp); @@ -1440,17 +1432,13 @@ list_of_port_declarations /* Get the port declaration details, the port type and what not, from context data stored by the last port_declaration rule. */ - pform_module_define_port(@3, $3, + pform_module_define_port(@3, name, port_declaration_context.port_type, port_declaration_context.port_net_type, port_declaration_context.sign_flag, port_declaration_context.range, 0); delete $1; - /* - * Same as above. - * - * pform_set_net_range($3); - */ + delete $3; $$ = tmp; } | list_of_port_declarations ',' @@ -1466,88 +1454,93 @@ list_of_port_declarations ; port_declaration - : attribute_list_opt - K_input net_type_opt signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - ptmp = pform_module_port_reference($6, @2.text, - @2.first_line); - pform_module_define_port(@2, $6, NetNet::PINPUT, - $3, $4, $5, $1); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.sign_flag = $4; - port_declaration_context.range = $5; - delete $1; - delete $6; - $$ = ptmp; - } - | attribute_list_opt - K_inout net_type_opt signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - ptmp = pform_module_port_reference($6, @2.text, - @2.first_line); - pform_module_define_port(@2, $6, NetNet::PINOUT, - $3, $4, $5, $1); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.sign_flag = $4; - port_declaration_context.range = $5; - delete $1; - delete $6; - $$ = ptmp; - } - | attribute_list_opt - K_output net_type_opt signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - ptmp = pform_module_port_reference($6, @2.text, - @2.first_line); - pform_module_define_port(@2, $6, NetNet::POUTPUT, - $3, $4, $5, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.sign_flag = $4; - port_declaration_context.range = $5; - delete $1; - delete $6; - $$ = ptmp; - } - | attribute_list_opt - K_output var_type signed_opt range_opt IDENTIFIER - { Module::port_t*ptmp; - ptmp = pform_module_port_reference($6, @2.text, - @2.first_line); - pform_module_define_port(@2, $6, NetNet::POUTPUT, - $3, $4, $5, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.sign_flag = $4; - port_declaration_context.range = $5; - delete $1; - delete $6; - $$ = ptmp; - } - | attribute_list_opt - K_output var_type signed_opt range_opt IDENTIFIER '=' expression - { Module::port_t*ptmp; - ptmp = pform_module_port_reference($6, @2.text, - @2.first_line); - pform_module_define_port(@2, $6, NetNet::POUTPUT, - $3, $4, $5, $1); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.port_net_type = $3; - port_declaration_context.sign_flag = $4; - port_declaration_context.range = $5; - - if (! pform_expression_is_constant($8)) - yyerror(@8, "error: register declaration assignment" - " value must be a constant expression."); - pform_make_reginit(@6, $6, $8); - - delete $1; - delete $6; - $$ = ptmp; - } - ; + : attribute_list_opt + K_input net_type_opt signed_opt range_opt IDENTIFIER + { Module::port_t*ptmp; + perm_string name = lex_strings.make($6); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::PINPUT, + $3, $4, $5, $1); + port_declaration_context.port_type = NetNet::PINPUT; + port_declaration_context.port_net_type = $3; + port_declaration_context.sign_flag = $4; + port_declaration_context.range = $5; + delete $1; + delete $6; + $$ = ptmp; + } + | attribute_list_opt + K_inout net_type_opt signed_opt range_opt IDENTIFIER + { Module::port_t*ptmp; + perm_string name = lex_strings.make($6); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::PINOUT, + $3, $4, $5, $1); + port_declaration_context.port_type = NetNet::PINOUT; + port_declaration_context.port_net_type = $3; + port_declaration_context.sign_flag = $4; + port_declaration_context.range = $5; + delete $1; + delete $6; + $$ = ptmp; + } + | attribute_list_opt + K_output net_type_opt signed_opt range_opt IDENTIFIER + { Module::port_t*ptmp; + perm_string name = lex_strings.make($6); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::POUTPUT, + $3, $4, $5, $1); + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.port_net_type = $3; + port_declaration_context.sign_flag = $4; + port_declaration_context.range = $5; + delete $1; + delete $6; + $$ = ptmp; + } + | attribute_list_opt + K_output var_type signed_opt range_opt IDENTIFIER + { Module::port_t*ptmp; + perm_string name = lex_strings.make($6); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::POUTPUT, + $3, $4, $5, $1); + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.port_net_type = $3; + port_declaration_context.sign_flag = $4; + port_declaration_context.range = $5; + delete $1; + delete $6; + $$ = ptmp; + } + | attribute_list_opt + K_output var_type signed_opt range_opt IDENTIFIER '=' expression + { Module::port_t*ptmp; + perm_string name = lex_strings.make($6); + ptmp = pform_module_port_reference(name, @2.text, + @2.first_line); + pform_module_define_port(@2, name, NetNet::POUTPUT, + $3, $4, $5, $1); + port_declaration_context.port_type = NetNet::POUTPUT; + port_declaration_context.port_net_type = $3; + port_declaration_context.sign_flag = $4; + port_declaration_context.range = $5; + + if (! pform_expression_is_constant($8)) + yyerror(@8, "error: register declaration assignment" + " value must be a constant expression."); + pform_make_reginit(@6, name, $8); + + delete $1; + delete $6; + $$ = ptmp; + } + ; @@ -1849,7 +1842,8 @@ module_item extension. */ | K_task IDENTIFIER ';' - { current_task = pform_push_task_scope($2); + { assert(current_task == 0); + current_task = pform_push_task_scope($2); FILE_NAME(current_task, @1); } task_item_list_opt @@ -1863,7 +1857,8 @@ module_item } | K_task IDENTIFIER - { current_task = pform_push_task_scope($2); + { assert(current_task == 0); + current_task = pform_push_task_scope($2); FILE_NAME(current_task, @1); } '(' task_port_decl_list ')' ';' @@ -1883,7 +1878,9 @@ module_item instead of the module. */ | K_function function_range_or_type_opt IDENTIFIER ';' - { current_function = pform_push_function_scope($3); } + { assert(current_function == 0); + current_function = pform_push_function_scope($3); + } function_item_list statement K_endfunction { current_function->set_ports($6); @@ -2037,14 +2034,15 @@ generate_block_opt : generate_block | ';' ; side effect, and all I pass up is the name of the l-value. */ net_decl_assign - : IDENTIFIER '=' expression - { net_decl_assign_t*tmp = new net_decl_assign_t; - tmp->next = tmp; - tmp->name = $1; - tmp->expr = $3; - $$ = tmp; - } - ; + : IDENTIFIER '=' expression + { net_decl_assign_t*tmp = new net_decl_assign_t; + tmp->next = tmp; + tmp->name = lex_strings.make($1); + tmp->expr = $3; + delete $1; + $$ = tmp; + } + ; net_decl_assigns : net_decl_assigns ',' net_decl_assign @@ -2320,7 +2318,8 @@ port_reference : IDENTIFIER { Module::port_t*ptmp; - ptmp = pform_module_port_reference($1, @1.text, @1.first_line); + perm_string name = lex_strings.make($1); + ptmp = pform_module_port_reference(name, @1.text, @1.first_line); delete $1; $$ = ptmp; } @@ -2530,32 +2529,33 @@ function_range_or_type_opt handle it. The register variable list simply packs them together so that bit ranges can be assigned. */ register_variable - : IDENTIFIER dimensions_opt - { pform_makewire(@1, $1, NetNet::REG, - NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); - if ($2 != 0) { - index_component_t index; - if ($2->size() > 1) { - yyerror(@2, "sorry: only 1 dimensional arrays " - "are currently supported."); - } - index = $2->front(); - pform_set_reg_idx($1, index.msb, index.lsb); - delete $2; - } - $$ = $1; - } - | IDENTIFIER '=' expression - { pform_makewire(@1, $1, NetNet::REG, - NetNet::NOT_A_PORT, - IVL_VT_NO_TYPE, 0); - if (! pform_expression_is_constant($3)) - yyerror(@3, "error: register declaration assignment" - " value must be a constant expression."); - pform_make_reginit(@1, $1, $3); - $$ = $1; - } - ; + : IDENTIFIER dimensions_opt + { perm_string ident_name = lex_strings.make($1); + pform_makewire(@1, ident_name, NetNet::REG, + NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); + if ($2 != 0) { + index_component_t index; + if ($2->size() > 1) { + yyerror(@2, "sorry: only 1 dimensional arrays " + "are currently supported."); + } + index = $2->front(); + pform_set_reg_idx(ident_name, index.msb, index.lsb); + delete $2; + } + $$ = $1; + } + | IDENTIFIER '=' expression + { perm_string ident_name = lex_strings.make($1); + pform_makewire(@1, ident_name, NetNet::REG, + NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); + if (! pform_expression_is_constant($3)) + yyerror(@3, "error: register declaration assignment" + " value must be a constant expression."); + pform_make_reginit(@1, ident_name, $3); + $$ = $1; + } + ; register_variable_list : register_variable @@ -2574,16 +2574,18 @@ register_variable_list real_variable : IDENTIFIER dimensions_opt - { pform_makewire(@1, $1, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); + { perm_string name = lex_strings.make($1); + pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); if ($2 != 0) { - yyerror(@2, "sorry: real variables do not currently support arrays."); - delete $2; + yyerror(@2, "sorry: real variables do not currently support arrays."); + delete $2; } $$ = $1; } | IDENTIFIER '=' expression - { pform_makewire(@1, $1, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - pform_make_reginit(@1, $1, $3); + { perm_string name = lex_strings.make($1); + pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); + pform_make_reginit(@1, name, $3); $$ = $1; } ; @@ -2604,22 +2606,24 @@ real_variable_list ; net_variable - : IDENTIFIER dimensions_opt - { pform_makewire(@1, $1, NetNet::IMPLICIT, - NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); - if ($2 != 0) { - index_component_t index; - if ($2->size() > 1) { - yyerror(@2, "sorry: only 1 dimensional arrays " - "are currently supported."); - } - index = $2->front(); - pform_set_reg_idx($1, index.msb, index.lsb); - delete $2; - } - $$ = $1; - } - ; + : IDENTIFIER dimensions_opt + { perm_string name = lex_strings.make($1); + pform_makewire(@1, name, NetNet::IMPLICIT, + NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); + if ($2 != 0) { + index_component_t index; + if ($2->size() > 1) { + yyerror(@2, "sorry: only 1 dimensional arrays " + "are currently supported."); + } + index = $2->front(); + pform_set_reg_idx(name, index.msb, index.lsb); + delete $2; + } + $$ = $1; + } + ; + net_variable_list : net_variable { list*tmp = new list; @@ -2970,16 +2974,20 @@ statement $$ = tmp; } | K_begin ':' IDENTIFIER - { current_block = pform_push_block_scope($3, PBlock::BL_SEQ); - FILE_NAME(current_block, @1); + { PBlock*tmp = pform_push_block_scope($3, PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + current_block_stack.push(tmp); } block_item_decls_opt statement_list K_end { pform_pop_scope(); - current_block->set_statement(*$6); + assert(! current_block_stack.empty()); + PBlock*tmp = current_block_stack.top(); + current_block_stack.pop(); + tmp->set_statement(*$6); delete $3; delete $6; - $$ = current_block; + $$ = tmp; } | K_begin K_end { PBlock*tmp = new PBlock(PBlock::BL_SEQ); @@ -3000,16 +3008,20 @@ statement code generator can do the right thing. */ | K_fork ':' IDENTIFIER - { current_block = pform_push_block_scope($3, PBlock::BL_PAR); - FILE_NAME(current_block, @1); + { PBlock*tmp = pform_push_block_scope($3, PBlock::BL_PAR); + FILE_NAME(tmp, @1); + current_block_stack.push(tmp); } block_item_decls_opt statement_list K_join { pform_pop_scope(); - current_block->set_statement(*$6); + assert(! current_block_stack.empty()); + PBlock*tmp = current_block_stack.top(); + current_block_stack.pop(); + tmp->set_statement(*$6); delete $3; delete $6; - $$ = current_block; + $$ = tmp; } | K_fork K_join { PBlock*tmp = new PBlock(PBlock::BL_PAR); @@ -3672,35 +3684,32 @@ udp_output_sym makes for these ports are scoped within the UDP, so there is no hierarchy involved. */ udp_port_decl - : K_input list_of_identifiers ';' - { $$ = pform_make_udp_input_ports($2); } - | K_output IDENTIFIER ';' - { pform_name_t pname; - pname.push_back(name_component_t(lex_strings.make($2))); - PWire*pp = new PWire(pname, NetNet::IMPLICIT, NetNet::POUTPUT, IVL_VT_LOGIC); - svector*tmp = new svector(1); - (*tmp)[0] = pp; - $$ = tmp; - delete $2; - } - | K_reg IDENTIFIER ';' - { pform_name_t pname; - pname.push_back(name_component_t(lex_strings.make($2))); - PWire*pp = new PWire(pname, NetNet::REG, NetNet::PIMPLICIT, IVL_VT_LOGIC); - svector*tmp = new svector(1); - (*tmp)[0] = pp; - $$ = tmp; - delete $2; - } - | K_reg K_output IDENTIFIER ';' - { pform_name_t pname; - pname.push_back(name_component_t(lex_strings.make($3))); - PWire*pp = new PWire(pname, NetNet::REG, NetNet::POUTPUT, IVL_VT_LOGIC); - svector*tmp = new svector(1); - (*tmp)[0] = pp; - $$ = tmp; - delete $3; - } + : K_input list_of_identifiers ';' + { $$ = pform_make_udp_input_ports($2); } + | K_output IDENTIFIER ';' + { perm_string pname = lex_strings.make($2); + PWire*pp = new PWire(pname, NetNet::IMPLICIT, NetNet::POUTPUT, IVL_VT_LOGIC); + svector*tmp = new svector(1); + (*tmp)[0] = pp; + $$ = tmp; + delete $2; + } + | K_reg IDENTIFIER ';' + { perm_string pname = lex_strings.make($2); + PWire*pp = new PWire(pname, NetNet::REG, NetNet::PIMPLICIT, IVL_VT_LOGIC); + svector*tmp = new svector(1); + (*tmp)[0] = pp; + $$ = tmp; + delete $2; + } + | K_reg K_output IDENTIFIER ';' + { perm_string pname = lex_strings.make($3); + PWire*pp = new PWire(pname, NetNet::REG, NetNet::POUTPUT, IVL_VT_LOGIC); + svector*tmp = new svector(1); + (*tmp)[0] = pp; + $$ = tmp; + delete $3; + } ; udp_port_decls @@ -3715,19 +3724,19 @@ udp_port_decls ; udp_port_list - : IDENTIFIER - { list*tmp = new list; - tmp->push_back($1); - delete $1; - $$ = tmp; - } - | udp_port_list ',' IDENTIFIER - { list*tmp = $1; - tmp->push_back($3); - delete $3; - $$ = tmp; - } - ; + : IDENTIFIER + { list*tmp = new list; + tmp->push_back(lex_strings.make($1)); + delete $1; + $$ = tmp; + } + | udp_port_list ',' IDENTIFIER + { list*tmp = $1; + tmp->push_back(lex_strings.make($3)); + delete $3; + $$ = tmp; + } + ; udp_reg_opt: K_reg { $$ = true; } | { $$ = false; }; diff --git a/pform.cc b/pform.cc index 1fabe8a424..a5dd5375c6 100644 --- a/pform.cc +++ b/pform.cc @@ -89,44 +89,21 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where) } /* - * The scope stack and the following functions handle the processing - * of scope. As I enter a scope, the push function is called, and as I - * leave a scope the pop function is called. Entering tasks, functions - * and named blocks causes scope to be pushed and popped. The module - * name is not included in this scope stack. + * The lexical_scope keeps track of the current lexical scope that is + * being parsed. The lexical scope may stack, so the current scope may + * have a parent, that is restored when the current scope ends. * - * The hier_name function, therefore, converts the name to the scoped - * name within the module currently in progress. It never includes an - * instance name. - * - * The scope stack does not include any scope created by a generate - * scheme. + * Items that have scoped names are put in the lexical_scope object. */ - -static pform_name_t scope_stack; static PScope* lexical_scope = 0; -void pform_push_scope(char*name) -{ - scope_stack.push_back(name_component_t(lex_strings.make(name))); -} - void pform_pop_scope() { - scope_stack.pop_back(); lexical_scope = lexical_scope->pscope_parent(); } -static pform_name_t hier_name(const char*tail) -{ - pform_name_t name = scope_stack; - name.push_back(name_component_t(lex_strings.make(tail))); - return name; -} - PTask* pform_push_task_scope(char*name) { - pform_push_scope(name); perm_string task_name = lex_strings.make(name); PTask*task = new PTask(task_name, pform_cur_module); @@ -139,7 +116,6 @@ PTask* pform_push_task_scope(char*name) PFunction* pform_push_function_scope(char*name) { - pform_push_scope(name); perm_string func_name = lex_strings.make(name); PFunction*func = new PFunction(func_name, lexical_scope); @@ -152,14 +128,16 @@ PFunction* pform_push_function_scope(char*name) PBlock* pform_push_block_scope(char*name, PBlock::BL_TYPE bt) { - pform_push_scope(name); perm_string block_name = lex_strings.make(name); PBlock*block = new PBlock(block_name, lexical_scope, bt); + // Make this the current lexical scope + lexical_scope = block; + return block; } -static PWire*get_wire_in_module(const pform_name_t&name) +static PWire*get_wire_in_scope(perm_string name) { /* Note that if we are processing a generate, then the scope depth will be empty because generate schemes @@ -168,7 +146,7 @@ static PWire*get_wire_in_module(const pform_name_t&name) if (pform_cur_generate) return pform_cur_generate->get_wire(name); - return pform_cur_module->get_wire(name); + return lexical_scope->wires_find(name); } void pform_set_default_nettype(NetNet::Type type, @@ -297,6 +275,9 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno, FILE_NAME(pform_cur_module, file, lineno); pform_cur_module->library_flag = pform_library_flag; + ivl_assert(*pform_cur_module, lexical_scope == 0); + lexical_scope = pform_cur_module; + /* The generate scheme numbering starts with *1*, not zero. That's just the way it is, thanks to the standard. */ scope_generate_counter = 1; @@ -323,14 +304,14 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno, * reference. This is a name without a .X(...), so the internal name * should be generated to be the same as the X. */ -Module::port_t* pform_module_port_reference(char*name, +Module::port_t* pform_module_port_reference(perm_string name, const char*file, unsigned lineno) { Module::port_t*ptmp = new Module::port_t; - PEIdent*tmp = new PEIdent(lex_strings.make(name)); + PEIdent*tmp = new PEIdent(name); FILE_NAME(tmp, file, lineno); - ptmp->name = lex_strings.make(name); + ptmp->name = name; ptmp->expr = svector(1); ptmp->expr[0] = tmp; @@ -372,6 +353,13 @@ void pform_endmodule(const char*name) pform_cur_module = 0; return; } + + // The current lexical scope should be this module by now, and + // this module should not have a parent lexical scope. + ivl_assert(*pform_cur_module, lexical_scope == pform_cur_module); + lexical_scope = pform_cur_module->pscope_parent(); + ivl_assert(*pform_cur_module, lexical_scope == 0); + pform_modules[mod_name] = pform_cur_module; pform_cur_module = 0; } @@ -583,6 +571,11 @@ PExpr* pform_select_mtm_expr(PExpr*min, PExpr*typ, PExpr*max) return res; } +template <> inline svector::svector(unsigned size) +: nitems_(size), items_(new perm_string[size]) +{ +} + static void process_udp_table(PUdp*udp, list*table, const char*file, unsigned lineno) { @@ -650,7 +643,7 @@ static void process_udp_table(PUdp*udp, list*table, udp->toutput = output; } -void pform_make_udp(perm_string name, list*parms, +void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init_expr, const char*file, unsigned lineno) @@ -662,11 +655,10 @@ void pform_make_udp(perm_string name, list*parms, off with the parameters in the list. If the port is already in the map, merge the port type. I will rebuild a list of parameters for the PUdp object. */ - map defs; + map defs; for (unsigned idx = 0 ; idx < decl->count() ; idx += 1) { - pform_name_t pname = (*decl)[idx]->path(); - string port_name = peek_tail_name(pname).str(); + perm_string port_name = (*decl)[idx]->basename(); if (PWire*cur = defs[port_name]) { bool rc = true; @@ -692,8 +684,8 @@ void pform_make_udp(perm_string name, list*parms, UDP declaration, and the defs map maps that name to a PWire* created by an input or output declaration. */ svector pins (parms->size()); - svector pin_names (parms->size()); - { list::iterator cur; + svector pin_names (parms->size()); + { list::iterator cur; unsigned idx; for (cur = parms->begin(), idx = 0 ; cur != parms->end() @@ -827,7 +819,7 @@ void pform_make_udp(perm_string name, list*parms, // Make the port list for the UDP for (unsigned idx = 0 ; idx < pins.count() ; idx += 1) - udp->ports[idx] = peek_tail_name(pins[idx]->path()); + udp->ports[idx] = pins[idx]->basename(); process_udp_table(udp, table, file, lineno); udp->initial = init; @@ -852,10 +844,9 @@ void pform_make_udp(perm_string name, bool synchronous_flag, svector pins(parms->size() + 1); /* Make the PWire for the output port. */ - pins[0] = new PWire(hier_name(out_name), + pins[0] = new PWire(out_name, synchronous_flag? NetNet::REG : NetNet::WIRE, - NetNet::POUTPUT, - IVL_VT_LOGIC); + NetNet::POUTPUT, IVL_VT_LOGIC); FILE_NAME(pins[0], file, lineno); /* Make the PWire objects for the input ports. */ @@ -865,10 +856,8 @@ void pform_make_udp(perm_string name, bool synchronous_flag, ; cur != parms->end() ; idx += 1, cur++) { assert(idx < pins.count()); - pins[idx] = new PWire(hier_name(*cur), - NetNet::WIRE, - NetNet::PINPUT, - IVL_VT_LOGIC); + pins[idx] = new PWire(*cur, NetNet::WIRE, + NetNet::PINPUT, IVL_VT_LOGIC); FILE_NAME(pins[idx], file, lineno); } assert(idx == pins.count()); @@ -909,7 +898,7 @@ void pform_make_udp(perm_string name, bool synchronous_flag, // Make the port list for the UDP for (unsigned idx = 0 ; idx < pins.count() ; idx += 1) - udp->ports[idx] = peek_tail_name(pins[idx]->path()); + udp->ports[idx] = pins[idx]->basename(); assert(udp); assert(table); @@ -924,39 +913,18 @@ void pform_make_udp(perm_string name, bool synchronous_flag, delete init_expr; } -/* - * This function is used to set the net range for a port that uses - * the new (1364-2001) list_of_port_declarations, but omitted a - * register/wire/etc. that would have triggered it to be set elsewhere. - */ -/* - * Since implicitly defined list of port declarations are no longer - * considered fully defined we no longer need this routine to force - * them to be fully defined. - * -void pform_set_net_range(const char* name) -{ - PWire*cur = get_wire_in_module(hier_name(name)); - if (cur == 0) { - VLerror("error: name is not a valid net."); - return; - } - cur->set_net_range(); -} -*/ - /* * This function attaches a range to a given name. The function is * only called by the parser within the scope of the net declaration, * and the name that I receive only has the tail component. */ -static void pform_set_net_range(const char* name, +static void pform_set_net_range(perm_string name, const svector*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt) { - PWire*cur = get_wire_in_module(hier_name(name)); + PWire*cur = get_wire_in_scope(name); if (cur == 0) { VLerror("error: name is not a valid net."); return; @@ -1271,17 +1239,16 @@ void pform_make_pgassign_list(svector*alist, * BTF-B14. */ void pform_make_reginit(const struct vlltype&li, - const char*name, PExpr*expr) + perm_string name, PExpr*expr) { - const pform_name_t sname = hier_name(name); - PWire*cur = pform_cur_module->get_wire(sname); + PWire*cur = lexical_scope->wires_find(name); if (cur == 0) { VLerror(li, "internal error: reginit to non-register?"); delete expr; return; } - PEIdent*lval = new PEIdent(sname); + PEIdent*lval = new PEIdent(name); FILE_NAME(lval, li); PAssign*ass = new PAssign(lval, expr); FILE_NAME(ass, li); @@ -1302,18 +1269,17 @@ void pform_make_reginit(const struct vlltype&li, * as is done for the old method. */ void pform_module_define_port(const struct vlltype&li, - const char*nm, + perm_string name, NetNet::PortType port_type, NetNet::Type type, bool signed_flag, svector*range, svector*attr) { - pform_name_t name = hier_name(nm); - PWire*cur = pform_cur_module->get_wire(name); + PWire*cur = lexical_scope->wires_find(name); if (cur) { ostringstream msg; - msg << nm << " definition conflicts with " + msg << name << " definition conflicts with " << "definition at " << cur->get_fileline() << "."; VLerror(msg.str().c_str()); @@ -1344,7 +1310,7 @@ void pform_module_define_port(const struct vlltype&li, cur->attributes[tmp->name] = tmp->parm; } } - pform_cur_module->add_wire(cur); + lexical_scope->wires[name] = cur; } /* @@ -1372,14 +1338,12 @@ void pform_module_define_port(const struct vlltype&li, * the variable/net. Other forms of pform_makewire ultimately call * this one to create the wire and stash it. */ -void pform_makewire(const vlltype&li, const char*nm, +void pform_makewire(const vlltype&li, perm_string name, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t dt, svector*attr) { - pform_name_t name = hier_name(nm); - - PWire*cur = get_wire_in_module(name); + PWire*cur = get_wire_in_scope(name); // If this is not implicit ("implicit" meaning we don't know // what the type is yet) then set the type now. @@ -1387,7 +1351,7 @@ void pform_makewire(const vlltype&li, const char*nm, bool rc = cur->set_wire_type(type); if (rc == false) { ostringstream msg; - msg << nm << " definition conflicts with " + msg << name << " definition conflicts with " << "definition at " << cur->get_fileline() << "."; VLerror(msg.str().c_str()); @@ -1431,9 +1395,9 @@ void pform_makewire(const vlltype&li, const char*nm, if (new_wire_flag) { if (pform_cur_generate) - pform_cur_generate->add_wire(cur); + pform_cur_generate->wires[name] = cur; else - pform_cur_module->add_wire(cur); + lexical_scope->wires[name] = cur; } } @@ -1493,32 +1457,28 @@ void pform_makewire(const vlltype&li, SR_NET); } - perm_string first_name = lex_strings.make(first->name); - pform_name_t name = hier_name(first_name); - PWire*cur = get_wire_in_module(name); + PWire*cur = get_wire_in_scope(first->name); if (cur != 0) { - PEIdent*lval = new PEIdent(first_name); + PEIdent*lval = new PEIdent(first->name); FILE_NAME(lval, li.text, li.first_line); PGAssign*ass = pform_make_pgassign(lval, first->expr, delay, str); FILE_NAME(ass, li.text, li.first_line); } - free(first->name); delete first; first = next; } } -void pform_set_port_type(perm_string nm, NetNet::PortType pt, +void pform_set_port_type(perm_string name, NetNet::PortType pt, const char*file, unsigned lineno) { - pform_name_t name = hier_name(nm); - PWire*cur = pform_cur_module->get_wire(name); + PWire*cur = lexical_scope->wires_find(name); if (cur == 0) { cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); FILE_NAME(cur, file, lineno); - pform_cur_module->add_wire(cur); + lexical_scope->wires[name] = cur; } switch (cur->get_port_type()) { @@ -1529,14 +1489,14 @@ void pform_set_port_type(perm_string nm, NetNet::PortType pt, case NetNet::NOT_A_PORT: cerr << file << ":" << lineno << ": error: " - << "port " << nm << " is not in the port list." + << "port " << name << " is not in the port list." << endl; error_count += 1; break; default: cerr << file << ":" << lineno << ": error: " - << "port " << nm << " already has a port declaration." + << "port " << name << " already has a port declaration." << endl; error_count += 1; break; @@ -1596,18 +1556,17 @@ svector*pform_make_task_ports(NetNet::PortType pt, for (list::iterator cur = names->begin() ; cur != names->end() ; cur ++ ) { - perm_string txt = *cur; - pform_name_t name = hier_name(txt); + perm_string name = *cur; /* Look for a preexisting wire. If it exists, set the port direction. If not, create it. */ - PWire*curw = pform_cur_module->get_wire(name); + PWire*curw = lexical_scope->wires_find(name); if (curw) { curw->set_port_type(pt); } else { curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype); FILE_NAME(curw, file, lineno); - pform_cur_module->add_wire(curw); + lexical_scope->wires[name] = curw; } curw->set_signed(signed_flag); @@ -1630,9 +1589,7 @@ svector*pform_make_task_ports(NetNet::PortType pt, void pform_set_attrib(perm_string name, perm_string key, char*value) { - pform_name_t path = hier_name(name); - - if (PWire*cur = pform_cur_module->get_wire(path)) { + if (PWire*cur = lexical_scope->wires_find(name)) { cur->attributes[key] = new PEString(value); } else if (PGate*cur = pform_cur_module->get_gate(name)) { @@ -1666,13 +1623,13 @@ void pform_set_type_attrib(perm_string name, const string&key, * This function attaches a memory index range to an existing * register. (The named wire must be a register. */ -void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r) +void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r) { PWire*cur = 0; if (pform_cur_generate) { - cur = pform_cur_generate->get_wire(hier_name(name)); + cur = pform_cur_generate->get_wire(name); } else { - cur = pform_cur_module->get_wire(hier_name(name)); + cur = lexical_scope->wires_find(name); } if (cur == 0) { VLerror("internal error: name is not a valid memory for index."); @@ -1819,16 +1776,15 @@ void pform_set_port_type(const struct vlltype&li, delete range; } -static void pform_set_reg_integer(const char*nm) +static void pform_set_reg_integer(perm_string name) { - pform_name_t name = hier_name(nm); - PWire*cur = pform_cur_module->get_wire(name); + PWire*cur = lexical_scope->wires_find(name); if (cur == 0) { cur = new PWire(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); cur->set_signed(true); - pform_cur_module->add_wire(cur); + lexical_scope->wires[name] = cur; } else { bool rc = cur->set_wire_type(NetNet::INTEGER); assert(rc); @@ -1854,13 +1810,12 @@ void pform_set_reg_integer(list*names) delete names; } -static void pform_set_reg_time(const char*nm) +static void pform_set_reg_time(perm_string name) { - pform_name_t name = hier_name(nm); - PWire*cur = pform_cur_module->get_wire(name); + PWire*cur = lexical_scope->wires_find(name); if (cur == 0) { cur = new PWire(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); - pform_cur_module->add_wire(cur); + lexical_scope->wires[name] = cur; } else { bool rc = cur->set_wire_type(NetNet::REG); assert(rc); @@ -1894,9 +1849,7 @@ svector* pform_make_udp_input_ports(list*names) ; cur != names->end() ; cur ++ ) { perm_string txt = *cur; - pform_name_t tmp; - tmp.push_back(name_component_t(txt)); - PWire*pp = new PWire(tmp, + PWire*pp = new PWire(txt, NetNet::IMPLICIT, NetNet::PINPUT, IVL_VT_LOGIC); diff --git a/pform.h b/pform.h index 45738a57f7..af08b4e871 100644 --- a/pform.h +++ b/pform.h @@ -95,7 +95,7 @@ struct parmvalue_t { struct str_pair_t { PGate::strength_t str0, str1; }; struct net_decl_assign_t { - char*name; + perm_string name; PExpr*expr; struct net_decl_assign_t*next; }; @@ -138,19 +138,19 @@ extern void pform_module_set_ports(svector*); port_definition_list. In this case, we have everything needed to define the port, all in one place. */ extern void pform_module_define_port(const struct vlltype&li, - const char*name, + perm_string name, NetNet::PortType, NetNet::Type type, bool signed_flag, svector*range, svector*attr); -extern Module::port_t* pform_module_port_reference(char*name, +extern Module::port_t* pform_module_port_reference(perm_string name, const char*file, unsigned lineno); extern void pform_endmodule(const char*); -extern void pform_make_udp(perm_string name, list*parms, +extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init, const char*file, unsigned lineno); @@ -201,7 +201,7 @@ extern void pform_endgenerate(); * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. */ -extern void pform_makewire(const struct vlltype&li, const char*name, +extern void pform_makewire(const struct vlltype&li, perm_string name, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t, @@ -229,7 +229,7 @@ extern void pform_makewire(const struct vlltype&li, ivl_variable_type_t); extern void pform_make_reginit(const struct vlltype&li, - const char*name, PExpr*expr); + perm_string name, PExpr*expr); /* Look up the names of the wires, and set the port type, i.e. input, output or inout. If the wire does not exist, create @@ -242,13 +242,12 @@ extern void pform_set_port_type(const struct vlltype&li, extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, const char*file, unsigned lineno); -extern void pform_set_net_range(const char* name); extern void pform_set_net_range(list*names, svector*, bool signed_flag, ivl_variable_type_t, PWSRType rt = SR_NET); -extern void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r); +extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); diff --git a/pform_dump.cc b/pform_dump.cc index f025b2c060..c0d6430f75 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -296,7 +296,7 @@ void PWire::dump(ostream&out, unsigned ind) const } } - out << " " << hname_; + out << " " << name_; // If the wire has indices, dump them. if (lidx_ || ridx_) { @@ -508,6 +508,9 @@ void PBlock::dump(ostream&out, unsigned ind) const out << " : " << pscope_name(); out << endl; + if (pscope_name() != 0) + dump_wires_(out, ind+2); + for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) { if (list_[idx]) list_[idx]->dump(out, ind+2); @@ -703,9 +706,11 @@ void PFunction::dump(ostream&out, unsigned ind) const for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { out << setw(ind) << ""; out << "input "; - out << (*ports_)[idx]->path() << ";" << endl; + out << (*ports_)[idx]->basename() << ";" << endl; } + dump_wires_(out, ind); + if (statement_) statement_->dump(out, ind); else @@ -743,9 +748,11 @@ void PTask::dump(ostream&out, unsigned ind) const assert(0); break; } - out << (*ports_)[idx]->path() << ";" << endl; + out << (*ports_)[idx]->basename() << ";" << endl; } + dump_wires_(out, ind); + if (statement_) statement_->dump(out, ind); else @@ -870,7 +877,7 @@ void PGenerate::dump(ostream&out, unsigned indent) const out << endl; - for (map::const_iterator idx = wires.begin() + for (map::const_iterator idx = wires.begin() ; idx != wires.end() ; idx++) { (*idx).second->dump(out, indent+2); @@ -894,6 +901,16 @@ void PGenerate::dump(ostream&out, unsigned indent) const out << setw(indent) << "" << "endgenerate" << endl; } +void PScope::dump_wires_(ostream&out, unsigned indent) const +{ + // Iterate through and display all the wires. + for (map::const_iterator wire = wires.begin() + ; wire != wires.end() ; wire ++ ) { + + (*wire).second->dump(out, indent); + } +} + void Module::dump(ostream&out) const { if (attributes.begin() != attributes.end()) { @@ -995,12 +1012,7 @@ void Module::dump(ostream&out) const } // Iterate through and display all the wires. - for (map::const_iterator wire = wires_.begin() - ; wire != wires_.end() - ; wire ++ ) { - - (*wire).second->dump(out); - } + dump_wires_(out, 4); // Dump the task definitions. typedef map::const_iterator task_iter_t;