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:
parent
dfe7beec31
commit
8154ce2a4a
|
|
@ -1136,6 +1136,9 @@ void NetScope::dump(ostream&o) const
|
|||
print_type(o);
|
||||
if (is_auto()) o << " (automatic)";
|
||||
if (is_cell()) o << " (cell)";
|
||||
if (nested_module()) o << " (nested)";
|
||||
if (program_block()) o << " (program)";
|
||||
|
||||
o << endl;
|
||||
|
||||
for (unsigned idx = 0 ; idx < attr_cnt() ; idx += 1)
|
||||
|
|
|
|||
|
|
@ -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_is_module());
|
||||
ivl_assert(*this, scope->type() == NetScope::MODULE);
|
||||
NetNet*sig = des->find_signal(scope, path_);
|
||||
if (sig == 0) {
|
||||
cerr << get_fileline() << ": error: no wire/reg " << path_
|
||||
|
|
|
|||
|
|
@ -1225,7 +1225,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
|
|||
continue;
|
||||
}
|
||||
|
||||
if (! scn->type_is_module()) continue;
|
||||
if (scn->type() != NetScope::MODULE) 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
|
||||
// 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);
|
||||
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(),
|
||||
get_lineno(), mod->get_lineno());
|
||||
my_scope->set_module_name(mod->mod_name());
|
||||
|
|
|
|||
|
|
@ -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_is_module())
|
||||
&& (scope->type() == NetScope::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_is_module())
|
||||
&& (scope->type() == NetScope::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_is_module()
|
||||
&& (scope->type() == NetScope::MODULE)
|
||||
&& (sig->port_type() == NetNet::PINOUT)
|
||||
&& (sig->data_type() == IVL_VT_REAL)) {
|
||||
|
||||
|
|
|
|||
45
elaborate.cc
45
elaborate.cc
|
|
@ -2312,6 +2312,18 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
|
|||
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
|
||||
{
|
||||
assert(scope);
|
||||
|
|
@ -2326,6 +2338,12 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
NetAssign_*lv = elaborate_lval(des, scope);
|
||||
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. */
|
||||
NetExpr*delay = 0;
|
||||
if (delay_ != 0)
|
||||
|
|
@ -2469,6 +2487,22 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
|
|||
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
|
||||
* form:
|
||||
|
|
@ -2505,6 +2539,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
|
|||
NetAssign_*lv = elaborate_lval(des, scope);
|
||||
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());
|
||||
if (rv == 0) return 0;
|
||||
|
||||
|
|
@ -3256,7 +3298,6 @@ 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;
|
||||
|
|
@ -4849,7 +4890,7 @@ Design* elaborate(list<perm_string>roots)
|
|||
|
||||
// Make the root scope. This makes a NetScope object and
|
||||
// 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
|
||||
// Module definition.
|
||||
|
|
|
|||
|
|
@ -101,10 +101,11 @@ uint64_t Design::scale_to_precision(uint64_t 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_;
|
||||
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
|
||||
permallocated. */
|
||||
root_scope_->set_module_name(root_scope_->basename());
|
||||
|
|
|
|||
17
net_scope.cc
17
net_scope.cc
|
|
@ -38,8 +38,8 @@ class PExpr;
|
|||
* in question.
|
||||
*/
|
||||
|
||||
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t)
|
||||
: type_(t), name_(n), up_(up)
|
||||
NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest, bool prog)
|
||||
: type_(t), name_(n), nested_module_(nest), program_block_(prog), up_(up)
|
||||
{
|
||||
events_ = 0;
|
||||
lcounter_ = 0;
|
||||
|
|
@ -302,9 +302,6 @@ 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";
|
||||
|
|
@ -363,31 +360,31 @@ const NetFuncDef* NetScope::func_def() const
|
|||
|
||||
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. */
|
||||
}
|
||||
|
||||
perm_string NetScope::module_name() const
|
||||
{
|
||||
assert(type_ == MODULE || type_ == NESTED_MODULE);
|
||||
assert(type_ == MODULE);
|
||||
return module_name_;
|
||||
}
|
||||
|
||||
void NetScope::add_module_port(NetNet*port)
|
||||
{
|
||||
assert(type_ == MODULE || type_ == NESTED_MODULE);
|
||||
assert(type_ == MODULE);
|
||||
ports_.push_back(port);
|
||||
}
|
||||
|
||||
unsigned NetScope::module_ports() const
|
||||
{
|
||||
assert(type_ == MODULE || type_ == NESTED_MODULE);
|
||||
assert(type_ == MODULE);
|
||||
return ports_.size();
|
||||
}
|
||||
|
||||
NetNet* NetScope::module_port(unsigned idx) const
|
||||
{
|
||||
assert(type_ == MODULE || type_ == NESTED_MODULE);
|
||||
assert(type_ == MODULE);
|
||||
assert(idx < ports_.size());
|
||||
return ports_[idx];
|
||||
}
|
||||
|
|
|
|||
16
netlist.h
16
netlist.h
|
|
@ -724,11 +724,11 @@ extern std::ostream&operator << (std::ostream&out, const std::list<netrange_t>&r
|
|||
class NetScope : public Attrib {
|
||||
|
||||
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
|
||||
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();
|
||||
|
||||
/* 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* 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;
|
||||
bool type_is_module() const { return type()==MODULE || type()==NESTED_MODULE; }
|
||||
void print_type(ostream&) const;
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
|
|
@ -989,6 +992,11 @@ class NetScope : public Attrib {
|
|||
TYPE type_;
|
||||
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 def_file_;
|
||||
unsigned lineno_;
|
||||
|
|
@ -4012,7 +4020,7 @@ class Design {
|
|||
|
||||
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();
|
||||
list<NetScope*> find_root_scopes();
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ 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;
|
||||
|
||||
|
|
|
|||
10
parse.y
10
parse.y
|
|
@ -5489,15 +5489,11 @@ statement_item /* This is roughly statement_item in the LRM */
|
|||
{ PAssignNB*tmp = new PAssignNB($1,$3);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
if (pform_in_program_block())
|
||||
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
|
||||
}
|
||||
| error K_LE expression ';'
|
||||
{ yyerror(@2, "Syntax in assignment statement l-value.");
|
||||
yyerrok;
|
||||
$$ = new PNoop;
|
||||
if (pform_in_program_block())
|
||||
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
|
||||
}
|
||||
| lpvalue '=' delay1 expression ';'
|
||||
{ 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);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
if (pform_in_program_block())
|
||||
yyerror(@2, "Non-blocking assignments not permitted in program blocks.");
|
||||
}
|
||||
| lpvalue '=' event_control expression ';'
|
||||
{ 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);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = 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 ';'
|
||||
{ PAssignNB*tmp = new PAssignNB($1,$5,$7,$8);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* 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;
|
||||
else
|
||||
scope = scope->parent();
|
||||
|
|
|
|||
Loading…
Reference in New Issue