From 3f2fa29482e8ff35faffa547960cdeded038576a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 13 Feb 2008 19:59:05 -0800 Subject: [PATCH 1/3] Factor compile-time scopes into PScope class Modules, functions and tasks are named scopes so derive them all from the PScope base class. These items all take scoped items, so the eventual plan is to move these items into PScope. --- Makefile.in | 2 +- Module.cc | 2 +- Module.h | 12 +++------ PFunction.cc | 32 ++--------------------- PScope.cc | 29 +++++++++++++++++++++ PScope.h | 50 ++++++++++++++++++++++++++++++++++++ PTask.cc | 9 +++---- PTask.h | 71 ++++----------------------------------------------- elab_sig.cc | 4 +-- parse.y | 58 ++++++++++++++++++++--------------------- pform_dump.cc | 4 +-- 11 files changed, 128 insertions(+), 145 deletions(-) create mode 100644 PScope.cc create mode 100644 PScope.h diff --git a/Makefile.in b/Makefile.in index 9326070cf..28668c04d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -111,7 +111,7 @@ parse.o parse_misc.o pform.o pform_dump.o pform_types.o \ set_width.o symbol_search.o sync.o sys_funcs.o \ verinum.o verireal.o target.o targets.o \ Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \ -PExpr.o PGate.o PGenerate.o PSpec.o \ +PExpr.o PGate.o PGenerate.o PScope.o PSpec.o \ PTask.o PUdp.o PFunction.o PWire.o Statement.o StringHeap.o \ $(FF) $(TT) diff --git a/Module.cc b/Module.cc index ffe2c2e11..74f36f678 100644 --- a/Module.cc +++ b/Module.cc @@ -29,7 +29,7 @@ /* n is a permallocated string. */ Module::Module(perm_string n) -: name_(n) +: PScope(n) { library_flag = false; default_nettype = NetNet::NONE; diff --git a/Module.h b/Module.h index 28be4fc11..61757b4b7 100644 --- a/Module.h +++ b/Module.h @@ -28,10 +28,10 @@ # include "StringHeap.h" # include "HName.h" # include "named.h" +# include "PScope.h" # include "LineInfo.h" # include "netlist.h" # include "pform_types.h" -class PEvent; class PExpr; class PEIdent; class PGate; @@ -50,7 +50,7 @@ class NetScope; * therefore the handle for grasping the described circuit. */ -class Module : public LineInfo { +class Module : public PScope, public LineInfo { /* The module ports are in general a vector of port_t objects. Each port has a name and an ordered list of @@ -113,9 +113,6 @@ class Module : public LineInfo { named array of PEident pointers. */ svector ports; - /* Keep a table of named events declared in the module. */ - mapevents; - map attributes; /* These are the timescale for this module. The default is @@ -132,7 +129,8 @@ class Module : public LineInfo { list specify_paths; - perm_string mod_name() const { return name_; } + // The mod_name() is the name of the module type. + perm_string mod_name() const { return pscope_name(); } void add_gate(PGate*gate); @@ -166,8 +164,6 @@ class Module : public LineInfo { bool elaborate_sig(Design*, NetScope*scope) const; private: - perm_string name_; - map wires_; list gates_; list behaviors_; diff --git a/PFunction.cc b/PFunction.cc index ebf035b6e..f8f5e6027 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-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 @@ -16,16 +16,13 @@ * 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: PFunction.cc,v 1.7 2004/05/31 23:34:36 steve Exp $" -#endif # include "config.h" #include "PTask.h" PFunction::PFunction(perm_string name) -: name_(name), ports_(0), statement_(0) +: PScope(name), ports_(0), statement_(0) { return_type_.type = PTF_NONE; } @@ -51,28 +48,3 @@ void PFunction::set_return(PTaskFuncArg t) { return_type_ = t; } - -/* - * $Log: PFunction.cc,v $ - * Revision 1.7 2004/05/31 23:34:36 steve - * Rewire/generalize parsing an elaboration of - * function return values to allow for better - * speed and more type support. - * - * Revision 1.6 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.5 2001/07/25 03:10:48 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.4 2001/01/13 22:20:08 steve - * Parse parameters within nested scopes. - * - * Revision 1.3 2000/02/23 02:56:53 steve - * Macintosh compilers do not support ident. - * - * Revision 1.2 1999/08/25 22:22:41 steve - * elaborate some aspects of functions. - * - */ diff --git a/PScope.cc b/PScope.cc new file mode 100644 index 000000000..3c1b1da4a --- /dev/null +++ b/PScope.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "PScope.h" + +PScope::PScope(perm_string n) +: name_(n) +{ +} + +PScope::~PScope() +{ +} diff --git a/PScope.h b/PScope.h new file mode 100644 index 000000000..5125f4bba --- /dev/null +++ b/PScope.h @@ -0,0 +1,50 @@ +#ifndef __PScope_H +#define __PScope_H +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "StringHeap.h" +# include + +class PEvent; + +/* + * The PScope class is a base representation of an object that + * represents some sort of compile-time scope. For example, a module, + * a function/task, a named block is derived from a PScope. + * + * NOTE: This is note the same concept as the "scope" of an elaborated + * hierarchy. That is represented by NetScope objects after elaboration. + */ +class PScope { + + public: + PScope(perm_string name); + ~PScope(); + + perm_string pscope_name() const { return name_; } + + // Named events in the scope. + mapevents; + + private: + perm_string name_; +}; + +#endif diff --git a/PTask.cc b/PTask.cc index bd725bbb7..9155cb0b2 100644 --- a/PTask.cc +++ b/PTask.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-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 @@ -16,16 +16,13 @@ * 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: PTask.cc,v 1.7 2002/08/12 01:34:58 steve Exp $" -#endif # include "config.h" # include "PTask.h" -PTask::PTask() -: ports_(0), statement_(0) +PTask::PTask(perm_string name) +: PScope(name), ports_(0), statement_(0) { } diff --git a/PTask.h b/PTask.h index 596cdc59d..9c296a78d 100644 --- a/PTask.h +++ b/PTask.h @@ -1,7 +1,7 @@ #ifndef __PTask_H #define __PTask_H /* - * Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-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,11 +18,9 @@ * 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: PTask.h,v 1.14 2007/03/06 05:22:49 steve Exp $" -#endif # include "LineInfo.h" +# include "PScope.h" # include "svector.h" # include "StringHeap.h" # include @@ -50,10 +48,10 @@ struct PTaskFuncArg { /* * The PTask holds the parsed definitions of a task. */ -class PTask : public LineInfo { +class PTask : public PScope, public LineInfo { public: - explicit PTask(); + explicit PTask(perm_string name); ~PTask(); void set_ports(svector*p); @@ -89,7 +87,7 @@ class PTask : public LineInfo { * * The output value is not elaborated until elaborate_sig. */ -class PFunction : public LineInfo { +class PFunction : public PScope, public LineInfo { public: explicit PFunction(perm_string name); @@ -110,68 +108,9 @@ class PFunction : public LineInfo { void dump(ostream&, unsigned) const; private: - perm_string name_; PTaskFuncArg return_type_; svector *ports_; Statement *statement_; }; -/* - * $Log: PTask.h,v $ - * Revision 1.14 2007/03/06 05:22:49 steve - * Support signed function return values. - * - * Revision 1.13 2004/05/31 23:34:36 steve - * Rewire/generalize parsing an elaboration of - * function return values to allow for better - * speed and more type support. - * - * Revision 1.12 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.11 2001/11/22 06:20:59 steve - * Use NetScope instead of string for scope path. - * - * Revision 1.10 2001/01/13 22:20:08 steve - * Parse parameters within nested scopes. - * - * Revision 1.9 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.8 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. - * - * Revision 1.7 2000/02/23 02:56:53 steve - * Macintosh compilers do not support ident. - * - * Revision 1.6 1999/09/30 21:28:34 steve - * Handle mutual reference of tasks by elaborating - * task definitions in two passes, like functions. - * - * Revision 1.5 1999/09/01 20:46:19 steve - * Handle recursive functions and arbitrary function - * references to other functions, properly pass - * function parameters and save function results. - * - * Revision 1.4 1999/08/25 22:22:41 steve - * elaborate some aspects of functions. - * - * Revision 1.3 1999/07/31 19:14:47 steve - * Add functions up to elaboration (Ed Carter) - * - * Revision 1.2 1999/07/24 02:11:19 steve - * Elaborate task input ports. - * - * Revision 1.1 1999/07/03 02:12:51 steve - * Elaborate user defined tasks. - * - */ #endif diff --git a/elab_sig.cc b/elab_sig.cc index 7ea9be5df..ab484bfa0 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -89,7 +89,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const if (wt == wires_.end()) { cerr << get_fileline() << ": error: " << "Port " << pp->expr[cc]->path() << " (" - << (idx+1) << ") of module " << name_ + << (idx+1) << ") of module " << mod_name() << " is not declared within module." << endl; des->errors += 1; continue; @@ -98,7 +98,7 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const if ((*wt).second->get_port_type() == NetNet::NOT_A_PORT) { cerr << get_fileline() << ": error: " << "Port " << pp->expr[cc]->path() << " (" - << (idx+1) << ") of module " << name_ + << (idx+1) << ") of module " << mod_name() << " has no direction declaration." << endl; des->errors += 1; diff --git a/parse.y b/parse.y index 818372c7c..96c9a8111 100644 --- a/parse.y +++ b/parse.y @@ -1842,36 +1842,36 @@ module_item statements in the task body. But we continue to accept it as an extension. */ - | K_task IDENTIFIER ';' - { pform_push_scope($2); } - task_item_list_opt - statement_or_null - K_endtask - { PTask*tmp = new PTask; - perm_string tmp2 = lex_strings.make($2); - FILE_NAME(tmp, @1); - tmp->set_ports($5); - tmp->set_statement($6); - pform_set_task(tmp2, tmp); - pform_pop_scope(); - delete $2; - } + | K_task IDENTIFIER ';' + { pform_push_scope($2); } + task_item_list_opt + statement_or_null + K_endtask + { perm_string task_name = lex_strings.make($2); + PTask*tmp = new PTask(task_name); + FILE_NAME(tmp, @1); + tmp->set_ports($5); + tmp->set_statement($6); + pform_set_task(task_name, tmp); + pform_pop_scope(); + delete $2; + } - | K_task IDENTIFIER - { pform_push_scope($2); } - '(' task_port_decl_list ')' ';' - task_item_list_opt - statement_or_null - K_endtask - { PTask*tmp = new PTask; - perm_string tmp2 = lex_strings.make($2); - FILE_NAME(tmp, @1); - tmp->set_ports($5); - tmp->set_statement($9); - pform_set_task(tmp2, tmp); - pform_pop_scope(); - delete $2; - } + | K_task IDENTIFIER + { pform_push_scope($2); } + '(' task_port_decl_list ')' ';' + task_item_list_opt + statement_or_null + K_endtask + { perm_string task_name = lex_strings.make($2); + PTask*tmp = new PTask(task_name); + FILE_NAME(tmp, @1); + tmp->set_ports($5); + tmp->set_statement($9); + pform_set_task(task_name, tmp); + pform_pop_scope(); + delete $2; + } /* The function declaration rule matches the function declaration header, then pushes the function scope. This causes the diff --git a/pform_dump.cc b/pform_dump.cc index addc8932c..cee72d81d 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -697,7 +697,7 @@ void PFunction::dump(ostream&out, unsigned ind) const out << "] "; } - out << name_ << ";" << endl; + out << pscope_name() << ";" << endl; if (ports_) for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { @@ -911,7 +911,7 @@ void Module::dump(ostream&out) const out << " *) "; } - out << "module " << name_ << ";" << endl; + out << "module " << mod_name() << ";" << endl; for (unsigned idx = 0 ; idx < ports.count() ; idx += 1) { port_t*cur = ports[idx]; From b0e4a6884a3308e5f960670a0ea7b1a26dd19dd1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 15 Feb 2008 21:20:24 -0800 Subject: [PATCH 2/3] Objects of lexical scope use PScope base class. All the pform objects that represent lexical scope now are derived from the PScope class, and are kept in a lexical_scope table so that the scope can be managed. --- Module.cc | 2 +- PFunction.cc | 4 +- PScope.cc | 4 +- PScope.h | 19 ++++-- PTask.cc | 4 +- PTask.h | 4 +- Statement.cc | 16 ++--- Statement.h | 10 +-- elab_scope.cc | 4 +- elaborate.cc | 8 +-- parse.y | 167 +++++++++++++++++++++++++------------------------- pform.cc | 49 +++++++++++---- pform.h | 7 ++- pform_dump.cc | 4 +- 14 files changed, 173 insertions(+), 129 deletions(-) diff --git a/Module.cc b/Module.cc index 74f36f678..596d90210 100644 --- a/Module.cc +++ b/Module.cc @@ -29,7 +29,7 @@ /* n is a permallocated string. */ Module::Module(perm_string n) -: PScope(n) +: PScope(n, 0) { library_flag = false; default_nettype = NetNet::NONE; diff --git a/PFunction.cc b/PFunction.cc index f8f5e6027..fb26c434b 100644 --- a/PFunction.cc +++ b/PFunction.cc @@ -21,8 +21,8 @@ #include "PTask.h" -PFunction::PFunction(perm_string name) -: PScope(name), ports_(0), statement_(0) +PFunction::PFunction(perm_string name, PScope*parent) +: PScope(name, parent), ports_(0), statement_(0) { return_type_.type = PTF_NONE; } diff --git a/PScope.cc b/PScope.cc index 3c1b1da4a..541d52d43 100644 --- a/PScope.cc +++ b/PScope.cc @@ -19,8 +19,8 @@ # include "PScope.h" -PScope::PScope(perm_string n) -: name_(n) +PScope::PScope(perm_string n, PScope*p) + : name_(n), parent_(p) { } diff --git a/PScope.h b/PScope.h index 5125f4bba..39c445e91 100644 --- a/PScope.h +++ b/PScope.h @@ -20,14 +20,15 @@ */ # include "StringHeap.h" +# include "pform_types.h" # include class PEvent; /* * The PScope class is a base representation of an object that - * represents some sort of compile-time scope. For example, a module, - * a function/task, a named block is derived from a PScope. + * represents lexical scope. For example, a module, a function/task, a + * named block is derived from a PScope. * * NOTE: This is note the same concept as the "scope" of an elaborated * hierarchy. That is represented by NetScope objects after elaboration. @@ -35,16 +36,26 @@ class PEvent; class PScope { public: - PScope(perm_string name); - ~PScope(); + // When created, a scope has a name and a parent. The name is + // the name of the definition. For example, if this is a + // module declaration, the name is the name after the "module" + // keyword, and if this is a task scope, the name is the task + // name. The parent is the lexical parent of this scope. Since + // modules do not nest in Verilog, the parent must be nil for + // modules. Scopes for tasks and functions point to their + // containing module. + PScope(perm_string name, PScope*parent); + virtual ~PScope(); perm_string pscope_name() const { return name_; } + PScope* pscope_parent() { return parent_; } // Named events in the scope. mapevents; private: perm_string name_; + PScope*parent_; }; #endif diff --git a/PTask.cc b/PTask.cc index 9155cb0b2..b829e03f2 100644 --- a/PTask.cc +++ b/PTask.cc @@ -21,8 +21,8 @@ # include "PTask.h" -PTask::PTask(perm_string name) -: PScope(name), ports_(0), statement_(0) +PTask::PTask(perm_string name, PScope*parent) +: PScope(name, parent), ports_(0), statement_(0) { } diff --git a/PTask.h b/PTask.h index 9c296a78d..4d9c24e9c 100644 --- a/PTask.h +++ b/PTask.h @@ -51,7 +51,7 @@ struct PTaskFuncArg { class PTask : public PScope, public LineInfo { public: - explicit PTask(perm_string name); + explicit PTask(perm_string name, PScope*parent); ~PTask(); void set_ports(svector*p); @@ -90,7 +90,7 @@ class PTask : public PScope, public LineInfo { class PFunction : public PScope, public LineInfo { public: - explicit PFunction(perm_string name); + explicit PFunction(perm_string name, PScope*parent); ~PFunction(); void set_ports(svector*p); diff --git a/Statement.cc b/Statement.cc index f6f14fa65..1ab66ec35 100644 --- a/Statement.cc +++ b/Statement.cc @@ -86,18 +86,13 @@ PAssignNB::~PAssignNB() { } -PBlock::PBlock(perm_string n, BL_TYPE t, const svector&st) -: name_(n), bl_type_(t), list_(st) -{ -} - -PBlock::PBlock(BL_TYPE t, const svector&st) -: bl_type_(t), list_(st) +PBlock::PBlock(perm_string n, PScope*parent, BL_TYPE t) +: PScope(n, parent), bl_type_(t) { } PBlock::PBlock(BL_TYPE t) -: bl_type_(t) +: PScope(perm_string(),0), bl_type_(t) { } @@ -107,6 +102,11 @@ PBlock::~PBlock() delete list_[idx]; } +void PBlock::set_statement(const svector&st) +{ + list_ = st; +} + PCallTask::PCallTask(const pform_name_t&n, const svector&p) : path_(n), parms_(p) { diff --git a/Statement.h b/Statement.h index 21864a831..09567b418 100644 --- a/Statement.h +++ b/Statement.h @@ -27,6 +27,7 @@ # include "StringHeap.h" # include "PDelays.h" # include "PExpr.h" +# include "PScope.h" # include "HName.h" # include "LineInfo.h" class PExpr; @@ -147,25 +148,26 @@ class PAssignNB : public PAssign_ { * statements before constructing this object, so it knows a priori * what is contained. */ -class PBlock : public Statement { +class PBlock : public PScope, public Statement { public: enum BL_TYPE { BL_SEQ, BL_PAR }; - explicit PBlock(perm_string n, BL_TYPE t, const svector&st); - explicit PBlock(BL_TYPE t, const svector&st); + // If the block has a name, it is a scope and also has a parent. + explicit PBlock(perm_string n, PScope*parent, BL_TYPE t); + // If it doesn't have a name, it's not a scope explicit PBlock(BL_TYPE t); ~PBlock(); BL_TYPE bl_type() const { return bl_type_; } + void set_statement(const svector&st); 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; private: - perm_string name_; const BL_TYPE bl_type_; svectorlist_; }; diff --git a/elab_scope.cc b/elab_scope.cc index c954da025..280781335 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -794,8 +794,8 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const { NetScope*my_scope = scope; - if (name_ != 0) { - hname_t use_name(name_); + if (pscope_name() != 0) { + hname_t use_name(pscope_name()); if (scope->child(use_name)) { cerr << get_fileline() << ": error: block/scope name " << use_name << " already used in this context." diff --git a/elaborate.cc b/elaborate.cc index 50481b044..45438b9fb 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1846,12 +1846,12 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const : NetBlock::SEQU; NetScope*nscope = 0; - if (name_.str() != 0) { - nscope = scope->child(hname_t(name_)); + if (pscope_name() != 0) { + nscope = scope->child(hname_t(pscope_name())); if (nscope == 0) { cerr << get_fileline() << ": internal error: " "unable to find block scope " << scope_path(scope) - << "<" << name_ << ">" << endl; + << "<" << pscope_name() << ">" << endl; des->errors += 1; return 0; } @@ -1869,7 +1869,7 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const // statement. There is no need to keep the block node. Also, // don't elide named blocks, because they might be referenced // elsewhere. - if ((list_.count() == 1) && (name_.str() == 0)) { + if ((list_.count() == 1) && (pscope_name() == 0)) { assert(list_[0]); NetProc*tmp = list_[0]->elaborate(des, nscope); return tmp; diff --git a/parse.y b/parse.y index 96c9a8111..4b5461c99 100644 --- a/parse.y +++ b/parse.y @@ -45,6 +45,12 @@ static struct { svector* range; } port_declaration_context; +/* The task and function rules need to briefly hold the pointer to the + task/function that is currently in progress. */ +static PTask* current_task = 0; +static PFunction* current_function = 0; +static PBlock* current_block = 0; + /* Later version of bison (including 1.35) will not compile in stack extension if the output is compiled with C++ and either the YYSTYPE or YYLTYPE are provided by the source code. However, I can get the @@ -1843,33 +1849,31 @@ module_item extension. */ | K_task IDENTIFIER ';' - { pform_push_scope($2); } + { current_task = pform_push_task_scope($2); + FILE_NAME(current_task, @1); + } task_item_list_opt statement_or_null K_endtask - { perm_string task_name = lex_strings.make($2); - PTask*tmp = new PTask(task_name); - FILE_NAME(tmp, @1); - tmp->set_ports($5); - tmp->set_statement($6); - pform_set_task(task_name, tmp); + { current_task->set_ports($5); + current_task->set_statement($6); pform_pop_scope(); + current_task = 0; delete $2; } | K_task IDENTIFIER - { pform_push_scope($2); } + { current_task = pform_push_task_scope($2); + FILE_NAME(current_task, @1); + } '(' task_port_decl_list ')' ';' task_item_list_opt statement_or_null K_endtask - { perm_string task_name = lex_strings.make($2); - PTask*tmp = new PTask(task_name); - FILE_NAME(tmp, @1); - tmp->set_ports($5); - tmp->set_statement($9); - pform_set_task(task_name, tmp); + { current_task->set_ports($5); + current_task->set_statement($9); pform_pop_scope(); + current_task = 0; delete $2; } @@ -1878,20 +1882,17 @@ module_item definitions in the func_body to take on the scope of the function instead of the module. */ - | K_function function_range_or_type_opt IDENTIFIER ';' - { pform_push_scope($3); } - function_item_list statement - K_endfunction - { perm_string name = lex_strings.make($3); - PFunction *tmp = new PFunction(name); - FILE_NAME(tmp, @1); - tmp->set_ports($6); - tmp->set_statement($7); - tmp->set_return($2); - pform_set_function(name, tmp); - pform_pop_scope(); - delete $3; - } + | K_function function_range_or_type_opt IDENTIFIER ';' + { current_function = pform_push_function_scope($3); } + function_item_list statement + K_endfunction + { current_function->set_ports($6); + current_function->set_statement($7); + current_function->set_return($2); + pform_pop_scope(); + current_function = 0; + delete $3; + } /* A generate region can contain further module items. Actually, it is supposed to be limited to certain kinds of module items, but @@ -2961,65 +2962,66 @@ statement name. These are handled by pushing the scope name then matching the declarations. The scope is popped at the end of the block. */ - | K_begin statement_list K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ, *$2); - FILE_NAME(tmp, @1); - delete $2; - $$ = tmp; - } - | K_begin ':' IDENTIFIER - { pform_push_scope($3); } - block_item_decls_opt - statement_list K_end - { pform_pop_scope(); - PBlock*tmp = new PBlock(lex_strings.make($3), - PBlock::BL_SEQ, *$6); - FILE_NAME(tmp, @1); - delete $3; - delete $6; - $$ = tmp; - } - | K_begin K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_begin ':' IDENTIFIER K_end - { PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_begin error K_end - { yyerrok; } + | K_begin statement_list K_end + { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + tmp->set_statement(*$2); + delete $2; + $$ = tmp; + } + | K_begin ':' IDENTIFIER + { current_block = pform_push_block_scope($3, PBlock::BL_SEQ); + FILE_NAME(current_block, @1); + } + block_item_decls_opt + statement_list K_end + { pform_pop_scope(); + current_block->set_statement(*$6); + delete $3; + delete $6; + $$ = current_block; + } + | K_begin K_end + { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_begin ':' IDENTIFIER K_end + { PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_begin error K_end + { yyerrok; } /* fork-join blocks are very similar to begin-end blocks. In fact, from the parser's perspective there is no real difference. All we need to do is remember that this is a parallel block so that the code generator can do the right thing. */ - | K_fork ':' IDENTIFIER - { pform_push_scope($3); } - block_item_decls_opt - statement_list K_join - { pform_pop_scope(); - PBlock*tmp = new PBlock(lex_strings.make($3), - PBlock::BL_PAR, *$6); - FILE_NAME(tmp, @1); - delete $3; - delete $6; - $$ = tmp; - } - | K_fork K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_fork ':' IDENTIFIER K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR); - FILE_NAME(tmp, @1); - delete $3; - $$ = tmp; - } + | K_fork ':' IDENTIFIER + { current_block = pform_push_block_scope($3, PBlock::BL_PAR); + FILE_NAME(current_block, @1); + } + block_item_decls_opt + statement_list K_join + { pform_pop_scope(); + current_block->set_statement(*$6); + delete $3; + delete $6; + $$ = current_block; + } + | K_fork K_join + { PBlock*tmp = new PBlock(PBlock::BL_PAR); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_fork ':' IDENTIFIER K_join + { PBlock*tmp = new PBlock(PBlock::BL_PAR); + FILE_NAME(tmp, @1); + delete $3; + $$ = tmp; + } | K_disable hierarchy_identifier ';' { PDisable*tmp = new PDisable(*$2); @@ -3039,8 +3041,9 @@ statement $$ = tmp; } | K_fork statement_list K_join - { PBlock*tmp = new PBlock(PBlock::BL_PAR, *$2); + { PBlock*tmp = new PBlock(PBlock::BL_PAR); FILE_NAME(tmp, @1); + tmp->set_statement(*$2); delete $2; $$ = tmp; } diff --git a/pform.cc b/pform.cc index 425a2162e..1fabe8a42 100644 --- a/pform.cc +++ b/pform.cc @@ -38,6 +38,7 @@ # include "ivl_assert.h" + map pform_modules; map pform_primitives; @@ -103,6 +104,7 @@ static inline void FILE_NAME(LineInfo*tmp, const struct vlltype&where) */ static pform_name_t scope_stack; +static PScope* lexical_scope = 0; void pform_push_scope(char*name) { @@ -112,6 +114,7 @@ void pform_push_scope(char*name) void pform_pop_scope() { scope_stack.pop_back(); + lexical_scope = lexical_scope->pscope_parent(); } static pform_name_t hier_name(const char*tail) @@ -121,6 +124,41 @@ static pform_name_t hier_name(const char*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); + + // Add the task to the current module + pform_cur_module->add_task(task->pscope_name(), task); + // Make this the current lexical scope + lexical_scope = task; + return task; +} + +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); + + // Add the task to the current module + pform_cur_module->add_function(func->pscope_name(), func); + // Make this the current lexical scope + lexical_scope = func; + return func; +} + +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); + + return block; +} + static PWire*get_wire_in_module(const pform_name_t&name) { /* Note that if we are processing a generate, then the @@ -1590,17 +1628,6 @@ svector*pform_make_task_ports(NetNet::PortType pt, return res; } -void pform_set_task(perm_string name, PTask*task) -{ - pform_cur_module->add_task(name, task); -} - - -void pform_set_function(perm_string name, PFunction*func) -{ - pform_cur_module->add_function(name, func); -} - void pform_set_attrib(perm_string name, perm_string key, char*value) { pform_name_t path = hier_name(name); diff --git a/pform.h b/pform.h index 5dc556f30..45738a57f 100644 --- a/pform.h +++ b/pform.h @@ -167,9 +167,12 @@ extern void pform_make_udp(perm_string name, * name string onto the scope hierarchy. The pop pulls it off and * deletes it. Thus, the string pushed must be allocated. */ -extern void pform_push_scope(char*name); extern void pform_pop_scope(); +extern PTask*pform_push_task_scope(char*name); +extern PFunction*pform_push_function_scope(char*name); +extern PBlock*pform_push_block_scope(char*name, PBlock::BL_TYPE tt); + extern verinum* pform_verinum_with_size(verinum*s, verinum*val, const char*file, unsigned loneno); @@ -248,8 +251,6 @@ extern void pform_set_net_range(list*names, extern void pform_set_reg_idx(const char*name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); -extern void pform_set_task(perm_string name, PTask*); -extern void pform_set_function(perm_string name, PFunction*); /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to diff --git a/pform_dump.cc b/pform_dump.cc index cee72d81d..f025b2c06 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -504,8 +504,8 @@ void PAssignNB::dump(ostream&out, unsigned ind) const void PBlock::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "begin"; - if (name_ != 0) - out << " : " << name_; + if (pscope_name() != 0) + out << " : " << pscope_name(); out << endl; for (unsigned idx = 0 ; idx < list_.count() ; idx += 1) { From 8e704cbf93add654826a604ec97e34e8c8a756fd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 24 Feb 2008 19:40:54 -0800 Subject: [PATCH 3/3] Rework handling of lexical scope Move the storage of wires (signals) out of the Module class into the PScope base class, and instead of putting the PWires all into the Module object, distribute them into the various lexical scopes (derived from PScope) so that the wire names do not need to carry scope information. This required some rewiring of elaboration of signals, and rewriting of lexical scope handling. --- Module.cc | 19 --- Module.h | 38 +---- PGenerate.cc | 14 +- PGenerate.h | 5 +- PScope.cc | 9 ++ PScope.h | 13 ++ PWire.cc | 18 +-- PWire.h | 6 +- Statement.h | 8 + design_dump.cc | 15 +- elab_sig.cc | 308 ++++++++++++++++++----------------- elaborate.cc | 2 +- net_scope.cc | 6 +- netlist.h | 4 +- parse.y | 427 +++++++++++++++++++++++++------------------------ pform.cc | 193 +++++++++------------- pform.h | 15 +- pform_dump.cc | 32 ++-- 18 files changed, 551 insertions(+), 581 deletions(-) diff --git a/Module.cc b/Module.cc index 596d90210..ec92e9172 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 61757b4b7..22ad3ff2f 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 aa9b597fe..03fcfb286 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 b29c60b25..842e0c49a 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 541d52d43..addd4ea4f 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 39c445e91..054be2874 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 d26aa10af..ec4161c2f 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 3cf02908d..2efa9c72b 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 09567b418..aedaf17fc 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 03821c044..da4b2253b 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 ab484bfa0..3119e976c 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; + } - if (wt == wires_.end()) { + wt = wires.find(peek_tail_name(port_path)); + + 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 45438b9fb..f5b3b44f8 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 82ce8a2a3..ec13a553c 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 c069e3942..9d386387c 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 4b5461c99..5ed7af2d0 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; + : 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, $6, $8); + 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; - } - ; + 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 1fabe8a42..a5dd5375c 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 45738a57f..af08b4e87 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 f025b2c06..c0d6430f7 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;