From dfe7beec31aafcee19ed95ea6b7d10114e91e8a9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 9 May 2012 19:35:11 -0700 Subject: [PATCH] Allow modules (and program blocks in particular) to nest. An important advantage of program blocks is its ability to nest within a module. This winds up also allowing modules to nest, which is legal but presumably less used feature. --- Module.cc | 4 +- Module.h | 6 +- PGate.cc | 10 ++- PGate.h | 4 ++ compiler.h | 5 ++ elab_net.cc | 2 +- elab_scope.cc | 21 +++++- elab_sig.cc | 6 +- elaborate.cc | 20 +++++- net_scope.cc | 13 ++-- netlist.h | 3 +- nodangle.cc | 1 + parse.y | 68 +++++++++--------- parse_misc.cc | 2 + pform.cc | 189 +++++++++++++++++++++++++++----------------------- pform.h | 6 -- pform_dump.cc | 5 ++ t-dll.cc | 1 + 18 files changed, 218 insertions(+), 148 deletions(-) diff --git a/Module.cc b/Module.cc index 589e3e7e31..d448f6dfc6 100644 --- a/Module.cc +++ b/Module.cc @@ -27,8 +27,8 @@ list Module::user_defparms; /* n is a permallocated string. */ -Module::Module(perm_string n) -: PScopeExtra(n) +Module::Module(LexicalScope*parent, perm_string n) +: PScopeExtra(n, parent) { library_flag = false; is_cell = false; diff --git a/Module.h b/Module.h index 29da46ae18..ad6604b377 100644 --- a/Module.h +++ b/Module.h @@ -65,7 +65,7 @@ class Module : public PScopeExtra, public LineInfo { public: /* The name passed here is the module name, not the instance name. This make must be a permallocated string. */ - explicit Module(perm_string name); + explicit Module(LexicalScope*parent, perm_string name); ~Module(); /* Initially false. This is set to true if the module has been @@ -121,6 +121,10 @@ class Module : public PScopeExtra, public LineInfo { the module definition. These are used at elaboration time. */ list generate_schemes; + /* Nested modules are placed here, and are not elaborated + unless they are instantiated, implicitly or explicitly. */ + std::map nested_modules; + list specify_paths; // The mod_name() is the name of the module type. diff --git a/PGate.cc b/PGate.cc index 9ec25d33f9..05a1dc5725 100644 --- a/PGate.cc +++ b/PGate.cc @@ -260,7 +260,7 @@ const char* PGBuiltin::gate_name() const } PGModule::PGModule(perm_string type, perm_string name, list*pins) -: PGate(name, pins), overrides_(0), pins_(0), +: PGate(name, pins), bound_type_(0), overrides_(0), pins_(0), npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0) { type_ = type; @@ -268,12 +268,18 @@ PGModule::PGModule(perm_string type, perm_string name, list*pins) PGModule::PGModule(perm_string type, perm_string name, named*pins, unsigned npins) -: PGate(name, 0), overrides_(0), pins_(pins), +: PGate(name, 0), bound_type_(0), overrides_(0), pins_(pins), npins_(npins), parms_(0), nparms_(0), msb_(0), lsb_(0) { type_ = type; } +PGModule::PGModule(Module*type, perm_string name) +: PGate(name, 0), bound_type_(type), overrides_(0), pins_(0), + npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0) +{ +} + PGModule::~PGModule() { } diff --git a/PGate.h b/PGate.h index 84fb26b9d0..97e8261c9c 100644 --- a/PGate.h +++ b/PGate.h @@ -201,6 +201,9 @@ class PGModule : public PGate { explicit PGModule(perm_string type, perm_string name, named*pins, unsigned npins); + // If the module type is known by design, then use this + // constructor. + explicit PGModule(Module*type, perm_string name); ~PGModule(); @@ -223,6 +226,7 @@ class PGModule : public PGate { perm_string get_type() const; private: + Module*bound_type_; perm_string type_; list*overrides_; named*pins_; diff --git a/compiler.h b/compiler.h index 976cbc8315..8fb7b009ef 100644 --- a/compiler.h +++ b/compiler.h @@ -177,6 +177,11 @@ static inline bool gn_system_verilog(void) return false; } +static inline bool gn_modules_nest(void) +{ + return gn_system_verilog(); +} + /* The bits of these GN_KEYWORDS_* constants define non-intersecting sets of keywords. The compiler enables groups of keywords by setting lexor_keyword_mask with the OR of the bits for the keywords to be diff --git a/elab_net.cc b/elab_net.cc index 030e22544c..4d70820b7e 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -693,7 +693,7 @@ NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const */ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const { - assert(scope->type() == NetScope::MODULE); + assert(scope->type_is_module()); NetNet*sig = des->find_signal(scope, path_); if (sig == 0) { cerr << get_fileline() << ": error: no wire/reg " << path_ diff --git a/elab_scope.cc b/elab_scope.cc index 234c8c9835..eb17273ede 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -541,6 +541,19 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, elaborate_scope_funcs(des, scope, funcs); + // Look for implicit modules and implicit gates for them. + + for (map::iterator cur = nested_modules.begin() + ; cur != nested_modules.end() ; ++cur) { + // Skip modules that must be explicitly instantiated. + if (cur->second->port_count() > 0) + continue; + + PGModule*nested_gate = new PGModule(cur->second, cur->second->mod_name()); + nested_gate->set_line(*cur->second); + gates_.push_back(nested_gate); + } + // Gates include modules, which might introduce new scopes, so // scan all of them to create those scopes. @@ -1212,7 +1225,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const continue; } - if (scn->type() != NetScope::MODULE) continue; + if (! scn->type_is_module()) continue; if (strcmp(mod->mod_name(), scn->module_name()) != 0) continue; @@ -1329,8 +1342,10 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s << "." << endl; } - // Create the new scope as a MODULE with my name. - NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE); + // Create the new scope as a MODULE with my name. Note + // that if this is a nested module, mark it thus so that + // scope searches will continue into the parent scope. + NetScope*my_scope = new NetScope(sc, use_name, bound_type_? NetScope::NESTED_MODULE : NetScope::MODULE); my_scope->set_line(get_file(), mod->get_file(), get_lineno(), mod->get_lineno()); my_scope->set_module_name(mod->mod_name()); diff --git a/elab_sig.cc b/elab_sig.cc index 9f2e6b60ec..90969c2fa4 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -98,7 +98,7 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const reg, then report an error. */ if (sig && (sig->scope() == scope) - && (scope->type() == NetScope::MODULE) + && (scope->type_is_module()) && (sig->port_type() == NetNet::PINPUT) && (sig->type() == NetNet::REG)) { @@ -110,7 +110,7 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const } if (sig && (sig->scope() == scope) - && (scope->type() == NetScope::MODULE) + && (scope->type_is_module()) && (sig->port_type() == NetNet::PINOUT) && (sig->type() == NetNet::REG)) { @@ -122,7 +122,7 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const } if (sig && (sig->scope() == scope) - && (scope->type() == NetScope::MODULE) + && scope->type_is_module() && (sig->port_type() == NetNet::PINOUT) && (sig->data_type() == IVL_VT_REAL)) { diff --git a/elaborate.cc b/elaborate.cc index c684b0de1c..fa309110de 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2068,6 +2068,10 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const bool PGModule::elaborate_sig(Design*des, NetScope*scope) const { + if (bound_type_) { + return elaborate_sig_mod_(des, scope, bound_type_); + } + // Look for the module type map::const_iterator mod = pform_modules.find(type_); if (mod != pform_modules.end()) @@ -2087,6 +2091,11 @@ bool PGModule::elaborate_sig(Design*des, NetScope*scope) const void PGModule::elaborate(Design*des, NetScope*scope) const { + if (bound_type_) { + elaborate_mod_(des, bound_type_, scope); + return; + } + // Look for the module type map::const_iterator mod = pform_modules.find(type_); if (mod != pform_modules.end()) { @@ -2108,10 +2117,16 @@ void PGModule::elaborate(Design*des, NetScope*scope) const void PGModule::elaborate_scope(Design*des, NetScope*sc) const { + // If the module type is known by design, then go right to it. + if (bound_type_) { + elaborate_scope_mod_(des, bound_type_, sc); + return; + } + // Look for the module type map::const_iterator mod = pform_modules.find(type_); if (mod != pform_modules.end()) { - elaborate_scope_mod_(des, (*mod).second, sc); + elaborate_scope_mod_(des, mod->second, sc); return; } @@ -2128,7 +2143,7 @@ void PGModule::elaborate_scope(Design*des, NetScope*sc) const // Try again to find the module type mod = pform_modules.find(type_); if (mod != pform_modules.end()) { - elaborate_scope_mod_(des, (*mod).second, sc); + elaborate_scope_mod_(des, mod->second, sc); return; } @@ -3241,6 +3256,7 @@ NetProc* PDisable::elaborate(Design*des, NetScope*scope) const return 0; case NetScope::MODULE: + case NetScope::NESTED_MODULE: cerr << get_fileline() << ": error: Cannot disable modules." << endl; des->errors += 1; return 0; diff --git a/net_scope.cc b/net_scope.cc index d51ade0b4d..22a67e6fc3 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -302,6 +302,9 @@ void NetScope::print_type(ostream&stream) const case FUNC: stream << "function"; break; + case NESTED_MODULE: + stream << "nested_module <" << (module_name_ ? module_name_.str() : "") + << "> instance"; case MODULE: stream << "module <" << (module_name_ ? module_name_.str() : "") << "> instance"; @@ -360,31 +363,31 @@ const NetFuncDef* NetScope::func_def() const void NetScope::set_module_name(perm_string n) { - assert(type_ == MODULE); + assert(type_ == MODULE || type_ == NESTED_MODULE); module_name_ = n; /* NOTE: n must have been permallocated. */ } perm_string NetScope::module_name() const { - assert(type_ == MODULE); + assert(type_ == MODULE || type_ == NESTED_MODULE); return module_name_; } void NetScope::add_module_port(NetNet*port) { - assert(type_ == MODULE); + assert(type_ == MODULE || type_ == NESTED_MODULE); ports_.push_back(port); } unsigned NetScope::module_ports() const { - assert(type_ == MODULE); + assert(type_ == MODULE || type_ == NESTED_MODULE); return ports_.size(); } NetNet* NetScope::module_port(unsigned idx) const { - assert(type_ == MODULE); + assert(type_ == MODULE || type_ == NESTED_MODULE); assert(idx < ports_.size()); return ports_[idx]; } diff --git a/netlist.h b/netlist.h index 06684d8043..ddfc70e3d5 100644 --- a/netlist.h +++ b/netlist.h @@ -724,7 +724,7 @@ extern std::ostream&operator << (std::ostream&out, const std::list&r class NetScope : public Attrib { public: - enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; + enum TYPE { MODULE, NESTED_MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; /* Create a new scope, and attach it to the given parent. The name is expected to have been permallocated. */ @@ -806,6 +806,7 @@ class NetScope : public Attrib { const NetScope* child(const hname_t&name) const; TYPE type() const; + bool type_is_module() const { return type()==MODULE || type()==NESTED_MODULE; } void print_type(ostream&) const; void set_task_def(NetTaskDef*); diff --git a/nodangle.cc b/nodangle.cc index 6e01d4aba8..229d212143 100644 --- a/nodangle.cc +++ b/nodangle.cc @@ -136,6 +136,7 @@ void nodangle_f::signal(Design*, NetNet*sig) if ((sig->port_type() != NetNet::NOT_A_PORT) && ((sig->scope()->type() == NetScope::TASK) || (sig->scope()->type() == NetScope::FUNC) || + (sig->scope()->type() == NetScope::NESTED_MODULE) || (sig->scope()->type() == NetScope::MODULE))) return; diff --git a/parse.y b/parse.y index c4a21fa3d0..1850385315 100644 --- a/parse.y +++ b/parse.y @@ -3866,43 +3866,46 @@ module_parameter_port_list module_item + /* Modules can contain further sub-module definitions. */ + : module + /* This rule detects net declarations that possibly include a primitive type, an optional vector range and signed flag. This also includes an optional delay set. The values are then applied to a list of names. If the primitive type is not specified, then resort to the default type LOGIC. */ - : attribute_list_opt net_type - primitive_type_opt unsigned_signed_opt range_opt - delay3_opt - net_variable_list ';' + | attribute_list_opt net_type + primitive_type_opt unsigned_signed_opt range_opt + delay3_opt + net_variable_list ';' + + { ivl_variable_type_t dtype = $3; + if (dtype == IVL_VT_NO_TYPE) + dtype = IVL_VT_LOGIC; + pform_makewire(@2, $5, $4, $7, $2, NetNet::NOT_A_PORT, dtype, $1); + if ($6 != 0) { + yyerror(@6, "sorry: net delays not supported."); + delete $6; + } + delete $1; + } - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_makewire(@2, $5, $4, $7, $2, - NetNet::NOT_A_PORT, dtype, $1); - if ($6 != 0) { - yyerror(@6, "sorry: net delays not supported."); - delete $6; - } - delete $1; - } + | attribute_list_opt K_wreal delay3 net_variable_list ';' + { pform_makewire(@2, 0, true, $4, NetNet::WIRE, + NetNet::NOT_A_PORT, IVL_VT_REAL, $1); + if ($3 != 0) { + yyerror(@3, "sorry: net delays not supported."); + delete $3; + } + delete $1; + } - | attribute_list_opt K_wreal delay3 net_variable_list ';' - { pform_makewire(@2, 0, true, $4, NetNet::WIRE, - NetNet::NOT_A_PORT, IVL_VT_REAL, $1); - if ($3 != 0) { - yyerror(@3, "sorry: net delays not supported."); - delete $3; - } - delete $1; - } - | attribute_list_opt K_wreal net_variable_list ';' - { pform_makewire(@2, 0, true, $3, NetNet::WIRE, - NetNet::NOT_A_PORT, IVL_VT_REAL, $1); - delete $1; - } + | attribute_list_opt K_wreal net_variable_list ';' + { pform_makewire(@2, 0, true, $3, NetNet::WIRE, + NetNet::NOT_A_PORT, IVL_VT_REAL, $1); + delete $1; + } /* Very similar to the rule above, but this takes a list of net_decl_assigns, which are = assignment @@ -4248,13 +4251,6 @@ module_item module items. These rules try to catch them at a point where a reasonable error message can be produced. */ - | K_module error ';' - { yyerror(@1, "error: missing endmodule or attempt to " - "nest modules."); - pform_error_nested_modules(); - yyerrok; - } - | error ';' { yyerror(@2, "error: invalid module item."); yyerrok; diff --git a/parse_misc.cc b/parse_misc.cc index 241341564a..32f1bafc66 100644 --- a/parse_misc.cc +++ b/parse_misc.cc @@ -33,6 +33,8 @@ std::ostream& operator << (std::ostream&o, const YYLTYPE&loc) { if (loc.text) o << loc.text << ":"; + else + o << "<>:"; o << loc.first_line; return o; } diff --git a/pform.cc b/pform.cc index d8acf08ce8..726cead0d6 100644 --- a/pform.cc +++ b/pform.cc @@ -41,7 +41,13 @@ # include "ivl_assert.h" # include "ivl_alloc.h" +/* + * The pform_modules is a map of the modules that have been defined in + * the top level. This should not contain nested modules/programs. + */ map pform_modules; +/* + */ map pform_primitives; @@ -217,7 +223,7 @@ extern int VLparse(); /* This tracks the current module being processed. There can only be exactly one module currently being parsed, since Verilog does not allow nested module definitions. */ -static Module*pform_cur_module = 0; +static listpform_cur_module; bool pform_library_flag = false; @@ -307,7 +313,7 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) pform_cur_generate->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" - << pform_cur_module->mod_name() << "' (generate)." + << pform_cur_module.front()->mod_name() << "' (generate)." << endl; error_count += 1; } @@ -350,7 +356,7 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, pform_cur_generate->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" - << pform_cur_module->mod_name() << "' (generate)." + << pform_cur_module.front()->mod_name() << "' (generate)." << endl; error_count += 1; } @@ -402,16 +408,16 @@ void pform_bind_attributes(map&attributes, bool pform_in_program_block() { - if (pform_cur_module == 0) + if (pform_cur_module.size() == 0) return false; - if (pform_cur_module->program_block) + if (pform_cur_module.front()->program_block) return true; return false; } static bool pform_at_module_level() { - return (lexical_scope == pform_cur_module) + return (lexical_scope == pform_cur_module.front()) || (lexical_scope == pform_cur_generate); } @@ -488,15 +494,15 @@ void pform_set_default_nettype(NetNet::Type type, { pform_default_nettype = type; - if (pform_cur_module) { + if (pform_cur_module.size() > 0) { cerr << file<<":"<mod_name() + << "module " << pform_cur_module.back()->mod_name() << " starts on line " - << pform_cur_module->get_fileline() << "." << endl; + << pform_cur_module.back()->get_fileline() << "." << endl; error_count += 1; } } @@ -699,14 +705,14 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check) if (in_module) { if (!only_check) { - pform_cur_module->time_unit = val; + pform_cur_module.front()->time_unit = val; tu_decl_flag = true; tu_local_flag = true; } else if (!tu_decl_flag) { VLerror(yylloc, "error: repeat timeunit found and the " "initial module timeunit is missing."); return; - } else if (pform_cur_module->time_unit != val) { + } else if (pform_cur_module.front()->time_unit != val) { VLerror(yylloc, "error: repeat timeunit does not match " "the initial module timeunit " "declaration."); @@ -723,7 +729,7 @@ void pform_set_timeunit(const char*txt, bool in_module, bool only_check) int pform_get_timeunit() { - return pform_cur_module->time_unit; + return pform_cur_module.front()->time_unit; } void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) @@ -734,14 +740,14 @@ void pform_set_timeprecision(const char*txt, bool in_module, bool only_check) if (in_module) { if (!only_check) { - pform_cur_module->time_precision = val; + pform_cur_module.front()->time_precision = val; tp_decl_flag = true; tp_local_flag = true; } else if (!tp_decl_flag) { VLerror(yylloc, "error: repeat timeprecision found and the " "initial module timeprecision is missing."); return; - } else if (pform_cur_module->time_precision != val) { + } else if (pform_cur_module.front()->time_precision != val) { VLerror(yylloc, "error: repeat timeprecision does not match " "the initial module timeprecision " "declaration."); @@ -808,26 +814,32 @@ verinum* pform_verinum_with_size(verinum*siz, verinum*val, void pform_startmodule(const struct vlltype&loc, const char*name, bool program_block, list*attr) { - assert( pform_cur_module == 0 ); + if (pform_cur_module.size() > 0 && !gn_system_verilog()) { + cerr << loc << ": error: Module definition " << name + << " cannot nest into module " << pform_cur_module.front()->mod_name() << "." << endl; + error_count += 1; + } + perm_string lex_name = lex_strings.make(name); - pform_cur_module = new Module(lex_name); - pform_cur_module->program_block = program_block; + Module*cur_module = new Module(lexical_scope, lex_name); + cur_module->program_block = program_block; /* Set the local time unit/precision to the global value. */ - pform_cur_module->time_unit = pform_time_unit; - pform_cur_module->time_precision = pform_time_prec; + cur_module->time_unit = pform_time_unit; + cur_module->time_precision = pform_time_prec; tu_local_flag = tu_global_flag; tp_local_flag = tp_global_flag; /* If we have a timescale file then the time information is from * a timescale directive. */ - pform_cur_module->time_from_timescale = pform_timescale_file != 0; + cur_module->time_from_timescale = pform_timescale_file != 0; - FILE_NAME(pform_cur_module, loc); - pform_cur_module->library_flag = pform_library_flag; + FILE_NAME(cur_module, loc); + cur_module->library_flag = pform_library_flag; - ivl_assert(*pform_cur_module, lexical_scope == 0); - lexical_scope = pform_cur_module; + pform_cur_module.push_front(cur_module); + + lexical_scope = cur_module; /* The generate scheme numbering starts with *1*, not zero. That's just the way it is, thanks to the standard. */ @@ -836,13 +848,13 @@ void pform_startmodule(const struct vlltype&loc, const char*name, if (warn_timescale && pform_timescale_file && (strcmp(pform_timescale_file,loc.text) != 0)) { - cerr << pform_cur_module->get_fileline() << ": warning: " + cerr << cur_module->get_fileline() << ": warning: " << "timescale for " << name << " inherited from another file." << endl; cerr << pform_timescale_file << ":" << pform_timescale_line << ": ...: The inherited timescale is here." << endl; } - pform_bind_attributes(pform_cur_module->attributes, attr); + pform_bind_attributes(cur_module->attributes, attr); } /* @@ -852,13 +864,12 @@ void pform_startmodule(const struct vlltype&loc, const char*name, */ void pform_check_timeunit_prec() { - assert(pform_cur_module); + assert(pform_cur_module.size() > 0); if ((generation_flag & (GN_VER2005_SV | GN_VER2009)) && - (pform_cur_module->time_unit < pform_cur_module->time_precision)) { - VLerror("error: a timeprecision is missing or is too " - "large!"); - } else assert(pform_cur_module->time_unit >= - pform_cur_module->time_precision); + (pform_cur_module.front()->time_unit < pform_cur_module.front()->time_precision)) { + VLerror("error: a timeprecision is missing or is too large!"); + } else assert(pform_cur_module.front()->time_unit >= + pform_cur_module.front()->time_precision); } /* @@ -881,7 +892,7 @@ Module::port_t* pform_module_port_reference(perm_string name, void pform_module_set_ports(vector*ports) { - assert(pform_cur_module); + assert(pform_cur_module.size() > 0); /* The parser parses ``module foo()'' as having one unconnected port, but it is really a module with no @@ -892,7 +903,7 @@ void pform_module_set_ports(vector*ports) } if (ports != 0) { - pform_cur_module->ports = *ports; + pform_cur_module.front()->ports = *ports; delete ports; } } @@ -900,34 +911,44 @@ void pform_module_set_ports(vector*ports) void pform_endmodule(const char*name, bool inside_celldefine, Module::UCDriveType uc_drive_def) { - assert(pform_cur_module); - pform_cur_module->time_from_timescale = (tu_local_flag && - tp_local_flag) || - (pform_timescale_file != 0); - perm_string mod_name = pform_cur_module->mod_name(); + assert(pform_cur_module.size() > 0); + Module*cur_module = pform_cur_module.front(); + pform_cur_module.pop_front(); + + cur_module->time_from_timescale = (tu_local_flag && tp_local_flag) + || (pform_timescale_file != 0); + perm_string mod_name = cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); - pform_cur_module->is_cell = inside_celldefine; - pform_cur_module->uc_drive = uc_drive_def; + cur_module->is_cell = inside_celldefine; + cur_module->uc_drive = uc_drive_def; + + // If this is a root module, then there is no parent module + // and we try to put this newly defined module into the global + // root list of modules. Otherwise, this is a nested module + // and we put it into the parent module scope to be elaborated + // if needed. + map&use_module_map = (pform_cur_module.size() == 0) + ? pform_modules + : pform_cur_module.front()->nested_modules; map::const_iterator test = - pform_modules.find(mod_name); + use_module_map.find(mod_name); - if (test != pform_modules.end()) { + if (test != use_module_map.end()) { ostringstream msg; msg << "Module " << name << " was already declared here: " - << (*test).second->get_fileline() << endl; + << test->second->get_fileline() << endl; VLerror(msg.str().c_str()); } else { - pform_modules[mod_name] = pform_cur_module; + use_module_map[mod_name] = cur_module; } // 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); + ivl_assert(*cur_module, lexical_scope == cur_module); pform_pop_scope(); - ivl_assert(*pform_cur_module, lexical_scope == 0); + ivl_assert(*cur_module, pform_cur_module.size()>0 || lexical_scope == 0); - pform_cur_module = 0; tp_decl_flag = false; tu_decl_flag = false; tu_local_flag = false; @@ -958,7 +979,7 @@ void pform_genvars(const struct vlltype&li, list*names) if (pform_cur_generate) pform_add_genvar(li, *cur, pform_cur_generate->genvars); else - pform_add_genvar(li, *cur, pform_cur_module->genvars); + pform_add_genvar(li, *cur, pform_cur_module.front()->genvars); } delete names; @@ -1113,7 +1134,7 @@ void pform_generate_block_name(char*name) void pform_endgenerate() { assert(pform_cur_generate != 0); - assert(pform_cur_module); + assert(pform_cur_module.size() > 0); // If there is no explicit block name then generate a temporary // name. This will be replaced by the correct name later, once @@ -1137,7 +1158,7 @@ void pform_endgenerate() parent_generate->generate_schemes.push_back(pform_cur_generate); } else { assert(pform_cur_generate->scheme_type != PGenerate::GS_CASE_ITEM); - pform_cur_module->generate_schemes.push_back(pform_cur_generate); + pform_cur_module.front()->generate_schemes.push_back(pform_cur_generate); } pform_cur_generate = parent_generate; } @@ -1593,7 +1614,7 @@ static void pform_make_event(perm_string name, const char*fn, unsigned ln) FILE_NAME(&tloc, fn, ln); cerr << tloc.get_fileline() << ": error: duplicate definition " "for named event '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } @@ -1653,7 +1674,7 @@ static void pform_makegate(PGBuiltin::Type type, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); } void pform_makegates(PGBuiltin::Type type, @@ -1719,7 +1740,7 @@ static void pform_make_modgate(perm_string type, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); } static void pform_make_modgate(perm_string type, @@ -1763,7 +1784,7 @@ static void pform_make_modgate(perm_string type, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); } void pform_make_modgates(perm_string type, @@ -1833,7 +1854,7 @@ static PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval, if (pform_cur_generate) pform_cur_generate->add_gate(cur); else - pform_cur_module->add_gate(cur); + pform_cur_module.front()->add_gate(cur); return cur; } @@ -2305,7 +2326,7 @@ void pform_set_attrib(perm_string name, perm_string key, char*value) if (PWire*cur = lexical_scope->wires_find(name)) { cur->attributes[key] = new PEString(value); - } else if (PGate*curg = pform_cur_module->get_gate(name)) { + } else if (PGate*curg = pform_cur_module.front()->get_gate(name)) { curg->attributes[key] = new PEString(value); } else { @@ -2384,23 +2405,23 @@ void pform_set_parameter(const struct vlltype&loc, FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for parameter '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } if (scope->localparams.find(name) != scope->localparams.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: localparam and " - "parameter in '" << pform_cur_module->mod_name() + << "parameter in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } - if ((scope == pform_cur_module) && - (pform_cur_module->specparams.find(name) != pform_cur_module->specparams.end())) { + if ((scope == pform_cur_module.front()) && + (pform_cur_module.front()->specparams.find(name) != pform_cur_module.front()->specparams.end())) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: specparam and " - "parameter in '" << pform_cur_module->mod_name() + "parameter in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -2426,8 +2447,8 @@ void pform_set_parameter(const struct vlltype&loc, parm.signed_flag = signed_flag; parm.range = value_range; - if (scope == pform_cur_module) - pform_cur_module->param_names.push_back(name); + if (scope == pform_cur_module.front()) + pform_cur_module.front()->param_names.push_back(name); } void pform_set_localparam(const struct vlltype&loc, @@ -2442,23 +2463,23 @@ void pform_set_localparam(const struct vlltype&loc, FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for localparam '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } if (scope->parameters.find(name) != scope->parameters.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: parameter and " - "localparam in '" << pform_cur_module->mod_name() + << "localparam in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } - if ((scope == pform_cur_module) && - (pform_cur_module->specparams.find(name) != pform_cur_module->specparams.end())) { + if ((scope == pform_cur_module.front()) && + (pform_cur_module.front()->specparams.find(name) != pform_cur_module.front()->specparams.end())) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: specparam and " - "localparam in '" << pform_cur_module->mod_name() + "localparam in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -2488,23 +2509,25 @@ void pform_set_localparam(const struct vlltype&loc, void pform_set_specparam(const struct vlltype&loc, perm_string name, list*range, PExpr*expr) { - Module*scope = pform_cur_module; + assert(pform_cur_module.size() > 0); + Module*scope = pform_cur_module.front(); assert(scope == lexical_scope); // Check if the specparam name is already in the dictionary. - if (scope->specparams.find(name) != scope->specparams.end()) { + if (pform_cur_module.front()->specparams.find(name) != + pform_cur_module.front()->specparams.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: duplicate definition " "for specparam '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << pform_cur_module.front()->mod_name() << "'." << endl; error_count += 1; } if (scope->parameters.find(name) != scope->parameters.end()) { LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: parameter and " - "specparam in '" << pform_cur_module->mod_name() + "specparam in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } @@ -2512,13 +2535,14 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name, LineInfo tloc; FILE_NAME(&tloc, loc); cerr << tloc.get_fileline() << ": error: localparam and " - "specparam in '" << pform_cur_module->mod_name() + "specparam in '" << pform_cur_module.front()->mod_name() << "' have the same name '" << name << "'." << endl; error_count += 1; } assert(expr); - Module::param_expr_t&parm = scope->specparams[name]; + + Module::param_expr_t&parm = pform_cur_module.front()->specparams[name]; FILE_NAME(&parm, loc); parm.expr = expr; @@ -2542,7 +2566,7 @@ void pform_set_specparam(const struct vlltype&loc, perm_string name, void pform_set_defparam(const pform_name_t&name, PExpr*expr) { assert(expr); - pform_cur_module->defparms.push_back(make_pair(name,expr)); + pform_cur_module.front()->defparms.push_back(make_pair(name,expr)); } /* @@ -2609,7 +2633,7 @@ extern void pform_module_specify_path(PSpecPath*obj) { if (obj == 0) return; - pform_cur_module->specify_paths.push_back(obj); + pform_cur_module.front()->specify_paths.push_back(obj); } @@ -2860,8 +2884,8 @@ PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, pform_put_behavior_in_scope(pp); - ivl_assert(*st, pform_cur_module); - if (pform_cur_module->program_block && type == IVL_PR_ALWAYS) { + ivl_assert(*st, pform_cur_module.size() > 0); + if (pform_cur_module.front()->program_block && type == IVL_PR_ALWAYS) { cerr << st->get_fileline() << ": error: Always statements not allowed" << " in program blocks." << endl; error_count += 1; @@ -2908,10 +2932,3 @@ int pform_parse(const char*path, FILE*file) destroy_lexor(); return error_count; } - -void pform_error_nested_modules() -{ - assert( pform_cur_module != 0 ); - cerr << pform_cur_module->get_fileline() << ": error: original module " - "(" << pform_cur_module->mod_name() << ") defined here." << endl; -} diff --git a/pform.h b/pform.h index c3b2928711..a1892cbe9a 100644 --- a/pform.h +++ b/pform.h @@ -424,12 +424,6 @@ extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, */ extern void pform_dump(ostream&out, Module*mod); -/* - * Used to report the original module location when a nested module - * (missing endmodule) is found by the parser. - */ -extern void pform_error_nested_modules(); - /* ** pform_discipline.cc * Functions for handling the parse of natures and disciplines. These * functions are in pform_disciplines.cc diff --git a/pform_dump.cc b/pform_dump.cc index 364a26b676..12f2db915f 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1249,6 +1249,11 @@ void Module::dump(ostream&out) const out << ")" << endl; } + for (map::const_iterator cur = nested_modules.begin() + ; cur != nested_modules.end() ; ++cur) { + out << setw(4) << "" << "Nested module " << cur->first << ";" << endl; + } + dump_typedefs_(out, 4); dump_parameters_(out, 4); diff --git a/t-dll.cc b/t-dll.cc index 0bee8e88d4..ed644be400 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2297,6 +2297,7 @@ void dll_target::scope(const NetScope*net) switch (net->type()) { case NetScope::MODULE: + case NetScope::NESTED_MODULE: scop->type_ = IVL_SCT_MODULE; scop->tname_ = net->module_name(); scop->ports = net->module_ports();