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.
This commit is contained in:
Stephen Williams 2012-05-09 19:35:11 -07:00
parent 580c44c015
commit dfe7beec31
18 changed files with 218 additions and 148 deletions

View File

@ -27,8 +27,8 @@
list<Module::named_expr_t> 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;

View File

@ -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<PGenerate*> generate_schemes;
/* Nested modules are placed here, and are not elaborated
unless they are instantiated, implicitly or explicitly. */
std::map<perm_string,Module*> nested_modules;
list<PSpecPath*> specify_paths;
// The mod_name() is the name of the module type.

View File

@ -260,7 +260,7 @@ const char* PGBuiltin::gate_name() const
}
PGModule::PGModule(perm_string type, perm_string name, list<PExpr*>*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<PExpr*>*pins)
PGModule::PGModule(perm_string type, perm_string name,
named<PExpr*>*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()
{
}

View File

@ -201,6 +201,9 @@ class PGModule : public PGate {
explicit PGModule(perm_string type, perm_string name,
named<PExpr*>*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<PExpr*>*overrides_;
named<PExpr*>*pins_;

View File

@ -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

View File

@ -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_

View File

@ -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<perm_string,Module*>::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());

View File

@ -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)) {

View File

@ -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<perm_string,Module*>::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<perm_string,Module*>::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<perm_string,Module*>::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;

View File

@ -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];
}

View File

@ -724,7 +724,7 @@ extern std::ostream&operator << (std::ostream&out, const std::list<netrange_t>&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*);

View File

@ -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;

68
parse.y
View File

@ -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 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 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;
}
/* Very similar to the rule above, but this takes a list of
net_decl_assigns, which are <name> = <expr> 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;

View File

@ -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;
}

189
pform.cc
View File

@ -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<perm_string,Module*> pform_modules;
/*
*/
map<perm_string,PUdp*> 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 list<Module*>pform_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<perm_string,PExpr*>&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<<":"<<lineno << ": error: "
<< "`default_nettype directives must appear" << endl;
cerr << file<<":"<<lineno << ": : "
<< "outside module definitions. The containing" << endl;
cerr << file<<":"<<lineno << ": : "
<< "module " << pform_cur_module->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<named_pexpr_t>*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<Module::port_t*>*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<Module::port_t*>*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<Module::port_t*>*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<perm_string,Module*>&use_module_map = (pform_cur_module.size() == 0)
? pform_modules
: pform_cur_module.front()->nested_modules;
map<perm_string,Module*>::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<perm_string>*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<pform_range_t>*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;
}

View File

@ -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

View File

@ -1249,6 +1249,11 @@ void Module::dump(ostream&out) const
out << ")" << endl;
}
for (map<perm_string,Module*>::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);

View File

@ -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();