Reword how we enforce program block constraints

Making the scope type NESTED_MODULE was just plain wrong, because
it didn't really encapsulate the meaning of program blocks OR
nested modules. So instead create nested_module() and program_block()
flags and use those to test scope constraints.
This commit is contained in:
Stephen Williams 2012-05-13 17:48:47 -07:00
parent dfe7beec31
commit 8154ce2a4a
12 changed files with 77 additions and 37 deletions

View File

@ -1136,6 +1136,9 @@ void NetScope::dump(ostream&o) const
print_type(o); print_type(o);
if (is_auto()) o << " (automatic)"; if (is_auto()) o << " (automatic)";
if (is_cell()) o << " (cell)"; if (is_cell()) o << " (cell)";
if (nested_module()) o << " (nested)";
if (program_block()) o << " (program)";
o << endl; o << endl;
for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1) for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1)

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 NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
{ {
assert(scope->type_is_module()); ivl_assert(*this, scope->type() == NetScope::MODULE);
NetNet*sig = des->find_signal(scope, path_); NetNet*sig = des->find_signal(scope, path_);
if (sig == 0) { if (sig == 0) {
cerr << get_fileline() << ": error: no wire/reg " << path_ cerr << get_fileline() << ": error: no wire/reg " << path_

View File

@ -1225,7 +1225,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
continue; continue;
} }
if (! scn->type_is_module()) continue; if (scn->type() != NetScope::MODULE) continue;
if (strcmp(mod->mod_name(), scn->module_name()) != 0) continue; if (strcmp(mod->mod_name(), scn->module_name()) != 0) continue;
@ -1345,7 +1345,9 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
// Create the new scope as a MODULE with my name. Note // Create the new scope as a MODULE with my name. Note
// that if this is a nested module, mark it thus so that // that if this is a nested module, mark it thus so that
// scope searches will continue into the parent scope. // scope searches will continue into the parent scope.
NetScope*my_scope = new NetScope(sc, use_name, bound_type_? NetScope::NESTED_MODULE : NetScope::MODULE); NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE,
bound_type_? true : false,
mod->program_block);
my_scope->set_line(get_file(), mod->get_file(), my_scope->set_line(get_file(), mod->get_file(),
get_lineno(), mod->get_lineno()); get_lineno(), mod->get_lineno());
my_scope->set_module_name(mod->mod_name()); 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. */ reg, then report an error. */
if (sig && (sig->scope() == scope) if (sig && (sig->scope() == scope)
&& (scope->type_is_module()) && (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINPUT) && (sig->port_type() == NetNet::PINPUT)
&& (sig->type() == NetNet::REG)) { && (sig->type() == NetNet::REG)) {
@ -110,7 +110,7 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
} }
if (sig && (sig->scope() == scope) if (sig && (sig->scope() == scope)
&& (scope->type_is_module()) && (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINOUT) && (sig->port_type() == NetNet::PINOUT)
&& (sig->type() == NetNet::REG)) { && (sig->type() == NetNet::REG)) {
@ -122,7 +122,7 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const
} }
if (sig && (sig->scope() == scope) if (sig && (sig->scope() == scope)
&& scope->type_is_module() && (scope->type() == NetScope::MODULE)
&& (sig->port_type() == NetNet::PINOUT) && (sig->port_type() == NetNet::PINOUT)
&& (sig->data_type() == IVL_VT_REAL)) { && (sig->data_type() == IVL_VT_REAL)) {

View File

@ -2312,6 +2312,18 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
return cur; return cur;
} }
static bool lval_not_program_variable(const NetAssign_*lv)
{
while (lv) {
NetScope*sig_scope = lv->sig()->scope();
if (! sig_scope->program_block())
return true;
lv = lv->more;
}
return false;
}
NetProc* PAssign::elaborate(Design*des, NetScope*scope) const NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
{ {
assert(scope); assert(scope);
@ -2326,6 +2338,12 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope); NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0; if (lv == 0) return 0;
if (scope->program_block() && lval_not_program_variable(lv)) {
cerr << get_fileline() << ": error: Blocking assignments to "
<< "non-program variables are not allowed." << endl;
des->errors += 1;
}
/* If there is an internal delay expression, elaborate it. */ /* If there is an internal delay expression, elaborate it. */
NetExpr*delay = 0; NetExpr*delay = 0;
if (delay_ != 0) if (delay_ != 0)
@ -2469,6 +2487,22 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
return cur; return cur;
} }
/*
* Return true if any lvalue parts are in a program block scope.
*/
static bool lval_is_program_variable(const NetAssign_*lv)
{
while (lv) {
NetScope*sig_scope = lv->sig()->scope();
if (sig_scope->program_block())
return true;
lv = lv->more;
}
return false;
}
/* /*
* Elaborate non-blocking assignments. The statement is of the general * Elaborate non-blocking assignments. The statement is of the general
* form: * form:
@ -2505,6 +2539,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope); NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0; if (lv == 0) return 0;
if (scope->program_block() && lval_is_program_variable(lv)) {
cerr << get_fileline() << ": error: Non-blocking assignments to "
<< "program variables are not allowed." << endl;
des->errors += 1;
// This is an error, but we can let elaboration continue
// because it would necessarily trigger other errors.
}
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type()); NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv), lv->expr_type());
if (rv == 0) return 0; if (rv == 0) return 0;
@ -3256,7 +3298,6 @@ NetProc* PDisable::elaborate(Design*des, NetScope*scope) const
return 0; return 0;
case NetScope::MODULE: case NetScope::MODULE:
case NetScope::NESTED_MODULE:
cerr << get_fileline() << ": error: Cannot disable modules." << endl; cerr << get_fileline() << ": error: Cannot disable modules." << endl;
des->errors += 1; des->errors += 1;
return 0; return 0;
@ -4849,7 +4890,7 @@ Design* elaborate(list<perm_string>roots)
// Make the root scope. This makes a NetScope object and // Make the root scope. This makes a NetScope object and
// pushes it into the list of root scopes in the Design. // pushes it into the list of root scopes in the Design.
NetScope*scope = des->make_root_scope(*root); NetScope*scope = des->make_root_scope(*root, rmod->program_block);
// Collect some basic properties of this scope from the // Collect some basic properties of this scope from the
// Module definition. // Module definition.

View File

@ -101,10 +101,11 @@ uint64_t Design::scale_to_precision(uint64_t val,
return val; return val;
} }
NetScope* Design::make_root_scope(perm_string root) NetScope* Design::make_root_scope(perm_string root, bool program_block)
{ {
NetScope *root_scope_; NetScope *root_scope_;
root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE); root_scope_ = new NetScope(0, hname_t(root), NetScope::MODULE,
false, program_block);
/* This relies on the fact that the basename return value is /* This relies on the fact that the basename return value is
permallocated. */ permallocated. */
root_scope_->set_module_name(root_scope_->basename()); root_scope_->set_module_name(root_scope_->basename());

View File

@ -38,8 +38,8 @@ class PExpr;
* in question. * in question.
*/ */
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t) NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bool prog)
: type_(t), name_(n), up_(up) : type_(t), name_(n), nested_module_(nest), program_block_(prog), up_(up)
{ {
events_ = 0; events_ = 0;
lcounter_ = 0; lcounter_ = 0;
@ -302,9 +302,6 @@ void NetScope::print_type(ostream&stream) const
case FUNC: case FUNC:
stream << "function"; stream << "function";
break; break;
case NESTED_MODULE:
stream << "nested_module <" << (module_name_ ? module_name_.str() : "")
<< "> instance";
case MODULE: case MODULE:
stream << "module <" << (module_name_ ? module_name_.str() : "") stream << "module <" << (module_name_ ? module_name_.str() : "")
<< "> instance"; << "> instance";
@ -363,31 +360,31 @@ const NetFuncDef* NetScope::func_def() const
void NetScope::set_module_name(perm_string n) void NetScope::set_module_name(perm_string n)
{ {
assert(type_ == MODULE || type_ == NESTED_MODULE); assert(type_ == MODULE);
module_name_ = n; /* NOTE: n must have been permallocated. */ module_name_ = n; /* NOTE: n must have been permallocated. */
} }
perm_string NetScope::module_name() const perm_string NetScope::module_name() const
{ {
assert(type_ == MODULE || type_ == NESTED_MODULE); assert(type_ == MODULE);
return module_name_; return module_name_;
} }
void NetScope::add_module_port(NetNet*port) void NetScope::add_module_port(NetNet*port)
{ {
assert(type_ == MODULE || type_ == NESTED_MODULE); assert(type_ == MODULE);
ports_.push_back(port); ports_.push_back(port);
} }
unsigned NetScope::module_ports() const unsigned NetScope::module_ports() const
{ {
assert(type_ == MODULE || type_ == NESTED_MODULE); assert(type_ == MODULE);
return ports_.size(); return ports_.size();
} }
NetNet* NetScope::module_port(unsigned idx) const NetNet* NetScope::module_port(unsigned idx) const
{ {
assert(type_ == MODULE || type_ == NESTED_MODULE); assert(type_ == MODULE);
assert(idx < ports_.size()); assert(idx < ports_.size());
return ports_[idx]; return ports_[idx];
} }

View File

@ -724,11 +724,11 @@ extern std::ostream&operator << (std::ostream&out, const std::list<netrange_t>&r
class NetScope : public Attrib { class NetScope : public Attrib {
public: public:
enum TYPE { MODULE, NESTED_MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK };
/* Create a new scope, and attach it to the given parent. The /* Create a new scope, and attach it to the given parent. The
name is expected to have been permallocated. */ name is expected to have been permallocated. */
NetScope(NetScope*up, const hname_t&name, TYPE t); NetScope(NetScope*up, const hname_t&name, TYPE t, bool nest=false, bool prog=false);
~NetScope(); ~NetScope();
/* Rename the scope using the name generated by inserting as /* Rename the scope using the name generated by inserting as
@ -805,8 +805,11 @@ class NetScope : public Attrib {
const NetScope* parent() const { return up_; } const NetScope* parent() const { return up_; }
const NetScope* child(const hname_t&name) const; const NetScope* child(const hname_t&name) const;
// Nested modules have slightly different scope search rules.
inline bool nested_module() const { return nested_module_; }
// Program blocks have elaboration constraints.
inline bool program_block() const { return program_block_; }
TYPE type() const; TYPE type() const;
bool type_is_module() const { return type()==MODULE || type()==NESTED_MODULE; }
void print_type(ostream&) const; void print_type(ostream&) const;
void set_task_def(NetTaskDef*); void set_task_def(NetTaskDef*);
@ -989,6 +992,11 @@ class NetScope : public Attrib {
TYPE type_; TYPE type_;
hname_t name_; hname_t name_;
// True if the scope is a nested module/program block
bool nested_module_;
// True if the scope is a program block
bool program_block_;
perm_string file_; perm_string file_;
perm_string def_file_; perm_string def_file_;
unsigned lineno_; unsigned lineno_;
@ -4012,7 +4020,7 @@ class Design {
const char* get_flag(const string&key) const; const char* get_flag(const string&key) const;
NetScope* make_root_scope(perm_string name); NetScope* make_root_scope(perm_string name, bool program_block);
NetScope* find_root_scope(); NetScope* find_root_scope();
list<NetScope*> find_root_scopes(); list<NetScope*> find_root_scopes();

View File

@ -136,7 +136,6 @@ void nodangle_f::signal(Design*, NetNet*sig)
if ((sig->port_type() != NetNet::NOT_A_PORT) && if ((sig->port_type() != NetNet::NOT_A_PORT) &&
((sig->scope()->type() == NetScope::TASK) || ((sig->scope()->type() == NetScope::TASK) ||
(sig->scope()->type() == NetScope::FUNC) || (sig->scope()->type() == NetScope::FUNC) ||
(sig->scope()->type() == NetScope::NESTED_MODULE) ||
(sig->scope()->type() == NetScope::MODULE))) (sig->scope()->type() == NetScope::MODULE)))
return; return;

10
parse.y
View File

@ -5489,15 +5489,11 @@ statement_item /* This is roughly statement_item in the LRM */
{ PAssignNB*tmp = new PAssignNB($1,$3); { PAssignNB*tmp = new PAssignNB($1,$3);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
if (pform_in_program_block())
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
} }
| error K_LE expression ';' | error K_LE expression ';'
{ yyerror(@2, "Syntax in assignment statement l-value."); { yyerror(@2, "Syntax in assignment statement l-value.");
yyerrok; yyerrok;
$$ = new PNoop; $$ = new PNoop;
if (pform_in_program_block())
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
} }
| lpvalue '=' delay1 expression ';' | lpvalue '=' delay1 expression ';'
{ PExpr*del = $3->front(); $3->pop_front(); { PExpr*del = $3->front(); $3->pop_front();
@ -5512,8 +5508,6 @@ statement_item /* This is roughly statement_item in the LRM */
PAssignNB*tmp = new PAssignNB($1,del,$4); PAssignNB*tmp = new PAssignNB($1,del,$4);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
if (pform_in_program_block())
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
} }
| lpvalue '=' event_control expression ';' | lpvalue '=' event_control expression ';'
{ PAssign*tmp = new PAssign($1,0,$3,$4); { PAssign*tmp = new PAssign($1,0,$3,$4);
@ -5530,15 +5524,11 @@ statement_item /* This is roughly statement_item in the LRM */
{ PAssignNB*tmp = new PAssignNB($1,0,$3,$4); { PAssignNB*tmp = new PAssignNB($1,0,$3,$4);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
if (pform_in_program_block())
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
} }
| lpvalue K_LE K_repeat '(' expression ')' event_control expression ';' | lpvalue K_LE K_repeat '(' expression ')' event_control expression ';'
{ PAssignNB*tmp = new PAssignNB($1,$5,$7,$8); { PAssignNB*tmp = new PAssignNB($1,$5,$7,$8);
FILE_NAME(tmp, @1); FILE_NAME(tmp, @1);
$$ = tmp; $$ = tmp;
if (pform_in_program_block())
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
} }
/* The IEEE1800 standard defines dynamic_array_new assignment as a /* The IEEE1800 standard defines dynamic_array_new assignment as a

View File

@ -79,7 +79,7 @@ NetScope*symbol_search(const LineInfo*li, Design*des, NetScope*scope,
/* We can't look up if we are at the enclosing module scope /* We can't look up if we are at the enclosing module scope
* or if a hierarchical path was given. */ * or if a hierarchical path was given. */
if ((scope->type() == NetScope::MODULE) || hier_path) if ((scope->type()==NetScope::MODULE && !scope->nested_module()) || hier_path)
scope = 0; scope = 0;
else else
scope = scope->parent(); scope = scope->parent();

View File

@ -2297,7 +2297,6 @@ void dll_target::scope(const NetScope*net)
switch (net->type()) { switch (net->type()) {
case NetScope::MODULE: case NetScope::MODULE:
case NetScope::NESTED_MODULE:
scop->type_ = IVL_SCT_MODULE; scop->type_ = IVL_SCT_MODULE;
scop->tname_ = net->module_name(); scop->tname_ = net->module_name();
scop->ports = net->module_ports(); scop->ports = net->module_ports();