Support SV [size] dimension for module and gate instances (issue #553).

Also output a proper error message if multiple dimensions are supplied
instead of failing an assertion.
This commit is contained in:
Martin Whitaker 2021-11-06 00:02:38 +00:00
parent dbf55da0f5
commit dcc9b59f6d
8 changed files with 100 additions and 235 deletions

View File

@ -41,7 +41,7 @@ void PGate::set_pins_(list<PExpr*>*pins)
}
PGate::PGate(perm_string name, list<PExpr*>*pins, const list<PExpr*>*del)
: name_(name), pins_(pins? pins->size() : 0)
: name_(name), pins_(pins? pins->size() : 0), ranges_(0)
{
if (pins) set_pins_(pins);
if (del) delay_.set_delays(del);
@ -50,7 +50,7 @@ PGate::PGate(perm_string name, list<PExpr*>*pins, const list<PExpr*>*del)
}
PGate::PGate(perm_string name, list<PExpr*>*pins, PExpr*del)
: name_(name), pins_(pins? pins->size() : 0)
: name_(name), pins_(pins? pins->size() : 0), ranges_(0)
{
if (pins) set_pins_(pins);
if (del) delay_.set_delay(del);
@ -59,7 +59,7 @@ PGate::PGate(perm_string name, list<PExpr*>*pins, PExpr*del)
}
PGate::PGate(perm_string name, list<PExpr*>*pins)
: name_(name), pins_(pins? pins->size() : 0)
: name_(name), pins_(pins? pins->size() : 0), ranges_(0)
{
if (pins) set_pins_(pins);
str0_ = IVL_DR_STRONG;
@ -70,6 +70,12 @@ PGate::~PGate()
{
}
void PGate::set_ranges(list<pform_range_t>*ranges)
{
assert(ranges_ == 0);
ranges_ = ranges;
}
ivl_drive_t PGate::strength0() const
{
return str0_;
@ -143,14 +149,14 @@ PGAssign::~PGAssign()
PGBuiltin::PGBuiltin(Type t, perm_string name,
list<PExpr*>*pins,
list<PExpr*>*del)
: PGate(name, pins, del), type_(t), msb_(0), lsb_(0)
: PGate(name, pins, del), type_(t)
{
}
PGBuiltin::PGBuiltin(Type t, perm_string name,
list<PExpr*>*pins,
PExpr*del)
: PGate(name, pins, del), type_(t), msb_(0), lsb_(0)
: PGate(name, pins, del), type_(t)
{
}
@ -159,15 +165,6 @@ PGBuiltin::~PGBuiltin()
{
}
void PGBuiltin::set_range(PExpr*msb, PExpr*lsb)
{
assert(msb_ == 0);
assert(lsb_ == 0);
msb_ = msb;
lsb_ = lsb;
}
const char* PGBuiltin::gate_name() const
{
switch(type_) {
@ -268,20 +265,20 @@ const char* PGBuiltin::gate_name() const
PGModule::PGModule(perm_string type, perm_string name, list<PExpr*>*pins)
: PGate(name, pins), bound_type_(0), type_(type), overrides_(0), pins_(0),
npins_(0), parms_(0), nparms_(0), msb_(0), lsb_(0)
npins_(0), parms_(0), nparms_(0)
{
}
PGModule::PGModule(perm_string type, perm_string name,
named<PExpr*>*pins, unsigned npins)
: PGate(name, 0), bound_type_(0), type_(type), overrides_(0), pins_(pins),
npins_(npins), parms_(0), nparms_(0), msb_(0), lsb_(0)
npins_(npins), parms_(0), nparms_(0)
{
}
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)
npins_(0), parms_(0), nparms_(0)
{
}
@ -303,15 +300,6 @@ void PGModule::set_parameters(named<PExpr*>*pa, unsigned npa)
nparms_ = npa;
}
void PGModule::set_range(PExpr*msb, PExpr*lsb)
{
assert(msb_ == 0);
assert(lsb_ == 0);
msb_ = msb;
lsb_ = lsb;
}
perm_string PGModule::get_type() const
{
return type_;

26
PGate.h
View File

@ -60,6 +60,9 @@ class PGate : public PNamedItem {
virtual ~PGate();
void set_ranges(std::list<pform_range_t>*ranges);
bool is_array() const { return ranges_ != 0; }
perm_string get_name() const { return name_; }
// This evaluates the delays as far as possible, but returns
@ -93,14 +96,20 @@ class PGate : public PNamedItem {
protected:
const std::vector<PExpr*>& get_pins() const { return pins_; }
unsigned calculate_array_size_(Design*, NetScope*,
long&high, long&low) const;
void dump_pins(std::ostream&out) const;
void dump_delays(std::ostream&out) const;
void dump_ranges(std::ostream&out) const;
private:
perm_string name_;
PDelays delay_;
std::vector<PExpr*>pins_;
std::list<pform_range_t>*ranges_;
ivl_drive_t str0_, str1_;
void set_pins_(std::list<PExpr*>*pins);
@ -159,16 +168,12 @@ class PGBuiltin : public PGate {
Type type() const { return type_; }
const char * gate_name() const;
void set_range(PExpr*msb, PExpr*lsb);
virtual void dump(std::ostream&out, unsigned ind =4) const;
virtual void elaborate(Design*, NetScope*scope) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const;
private:
unsigned calculate_array_count_(Design*, NetScope*,
long&high, long&low) const;
void calculate_gate_and_lval_count_(unsigned&gate_count,
unsigned&lval_count) const;
@ -179,8 +184,6 @@ class PGBuiltin : public PGate {
bool check_delay_count(Design*des) const;
Type type_;
PExpr*msb_;
PExpr*lsb_;
};
/*
@ -215,10 +218,6 @@ class PGModule : public PGate {
void set_parameters(std::list<PExpr*>*o);
void set_parameters(named<PExpr*>*pa, unsigned npa);
// Modules can be instantiated in ranges. The parser uses this
// method to pass the range to the pform.
void set_range(PExpr*msb, PExpr*lsb);
std::map<perm_string,PExpr*> attributes;
virtual void dump(std::ostream&out, unsigned ind =4) const;
@ -241,16 +240,9 @@ class PGModule : public PGate {
named<PExpr*>*parms_;
unsigned nparms_;
// Arrays of modules are give if these are set.
PExpr*msb_;
PExpr*lsb_;
friend class delayed_elaborate_scope_mod_instances;
void elaborate_mod_(Design*, Module*mod, NetScope*scope) const;
void elaborate_udp_(Design*, PUdp *udp, NetScope*scope) const;
unsigned calculate_instance_count_(Design*, NetScope*,
long&high, long&low,
perm_string name) const;
void elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const;
void elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const;
bool elaborate_sig_mod_(Design*des, NetScope*scope, Module*mod) const;

View File

@ -1413,7 +1413,7 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
return;
}
if (msb_ || lsb_) {
if (is_array()) {
// If there are expressions to evaluate in order to know
// the actual number of instances that will be
// instantiated, then we have to delay further scope
@ -1443,41 +1443,17 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const
*/
void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*sc) const
{
NetExpr*mse = msb_ ? elab_and_eval(des, sc, msb_, -1, true) : 0;
NetExpr*lse = lsb_ ? elab_and_eval(des, sc, lsb_, -1, true) : 0;
NetEConst*msb = dynamic_cast<NetEConst*> (mse);
NetEConst*lsb = dynamic_cast<NetEConst*> (lse);
assert( (msb == 0) || (lsb != 0) );
long instance_low = 0;
long instance_high = 0;
long instance_count = 1;
bool instance_array = false;
if (msb) {
instance_array = true;
instance_high = msb->value().as_long();
instance_low = lsb->value().as_long();
if (instance_high > instance_low)
instance_count = instance_high - instance_low + 1;
else
instance_count = instance_low - instance_high + 1;
delete mse;
delete lse;
}
long instance_count = calculate_array_size_(des, sc, instance_high, instance_low);
if (instance_count == 0)
return;
NetScope::scope_vec_t instances (instance_count);
if (debug_scopes) {
cerr << get_fileline() << ": debug: Create " << instance_count
<< " instances of " << get_name()
<< "." << endl;
}
struct attrib_list_t*attrib_list;
unsigned attrib_list_n = 0;
attrib_list = evaluate_attributes(attributes, attrib_list_n, des, sc);
struct attrib_list_t*attrib_list;
unsigned attrib_list_n = 0;
attrib_list = evaluate_attributes(attributes, attrib_list_n, des, sc);
// Run through the module instances, and make scopes out of
// them. Also do parameter overrides that are done on the
@ -1486,7 +1462,7 @@ void PGModule::elaborate_scope_mod_instances_(Design*des, Module*mod, NetScope*s
hname_t use_name (get_name());
if (instance_array) {
if (is_array()) {
int instance_idx;
if (instance_low < instance_high)
instance_idx = instance_low + idx;

View File

@ -63,6 +63,44 @@ void PGate::elaborate(Design*, NetScope*) const
typeid(*this).name() << endl;
}
unsigned PGate::calculate_array_size_(Design*des, NetScope*scope,
long&high, long&low) const
{
if (ranges_ && ranges_->size() > 1) {
if (gn_system_verilog()) {
cerr << get_fileline() << ": sorry: Multi-dimensional"
<< " arrays of instances are not yet supported." << endl;
} else {
cerr << get_fileline() << ": error: Multi-dimensional"
<< " arrays of instances require SystemVerilog." << endl;
}
des->errors += 1;
return 0;
}
unsigned size = 1;
high = 0;
low = 0;
if (ranges_) {
if (!evaluate_range(des, scope, this, ranges_->front(), high, low))
return 0;
if (high > low)
size = high - low + 1;
else
size = low - high + 1;
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGate: Make array "
<< "[" << high << ":" << low << "]" << " of "
<< size << " instances for " << get_name() << endl;
}
}
return size;
}
/*
* Elaborate the continuous assign. (This is *not* the procedural
* assign.) Elaborate the lvalue and rvalue, and do the assignment.
@ -234,61 +272,6 @@ void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval
assign_unpacked_with_bufz(des, scope, this, lval, rval_net);
}
unsigned PGBuiltin::calculate_array_count_(Design*des, NetScope*scope,
long&high, long&low) const
{
unsigned count = 1;
high = 0;
low = 0;
/* If the Verilog source has a range specification for the
gates, then I am expected to make more than one
gate. Figure out how many are desired. */
if (msb_) {
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1, true);
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1, true);
NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp);
NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp);
if (msb_con == 0) {
cerr << get_fileline() << ": error: Unable to evaluate "
"expression " << *msb_ << endl;
des->errors += 1;
return 0;
}
if (lsb_con == 0) {
cerr << get_fileline() << ": error: Unable to evaluate "
"expression " << *lsb_ << endl;
des->errors += 1;
return 0;
}
verinum msb = msb_con->value();
verinum lsb = lsb_con->value();
delete msb_exp;
delete lsb_exp;
if (msb.as_long() > lsb.as_long())
count = msb.as_long() - lsb.as_long() + 1;
else
count = lsb.as_long() - msb.as_long() + 1;
low = lsb.as_long();
high = msb.as_long();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGBuiltin: Make array "
<< "[" << high << ":" << low << "]" << " of "
<< count << " gates for " << get_name() << endl;
}
}
return count;
}
void PGBuiltin::calculate_gate_and_lval_count_(unsigned&gate_count,
unsigned&lval_count) const
{
@ -724,7 +707,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
the count is 1, and high==low==0. */
long low=0, high=0;
unsigned array_count = calculate_array_count_(des, scope, high, low);
unsigned array_count = calculate_array_size_(des, scope, high, low);
if (array_count == 0) return;
unsigned gate_count = 0, lval_count = 0;
@ -855,10 +838,10 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
// to be the exact width required (this will be checked
// later). But if this is a single instance, consensus
// is that we just take the LSB of the port expression.
NetExpr*tmp = elab_and_eval(des, scope, ex, msb_ ? -1 : 1);
NetExpr*tmp = elab_and_eval(des, scope, ex, is_array() ? -1 : 1);
if (tmp == 0)
continue;
if (msb_ == 0 && tmp->expr_width() != 1)
if (!is_array() && tmp->expr_width() != 1)
tmp = new NetESelect(tmp, make_const_0(1), 1,
IVL_SEL_IDX_UP);
sig = tmp->synthesize(des, scope, tmp);
@ -1989,62 +1972,6 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
}
unsigned PGModule::calculate_instance_count_(Design*des, NetScope*scope,
long&high, long&low,
perm_string name) const
{
unsigned count = 1;
high = 0;
low = 0;
/* If the Verilog source has a range specification for the UDP, then
* I am expected to make more than one gate. Figure out how many are
* desired. */
if (msb_) {
NetExpr*msb_exp = elab_and_eval(des, scope, msb_, -1, true);
NetExpr*lsb_exp = elab_and_eval(des, scope, lsb_, -1, true);
NetEConst*msb_con = dynamic_cast<NetEConst*>(msb_exp);
NetEConst*lsb_con = dynamic_cast<NetEConst*>(lsb_exp);
if (msb_con == 0) {
cerr << get_fileline() << ": error: Unable to evaluate "
"expression " << *msb_ << endl;
des->errors += 1;
return 0;
}
if (lsb_con == 0) {
cerr << get_fileline() << ": error: Unable to evaluate "
"expression " << *lsb_ << endl;
des->errors += 1;
return 0;
}
verinum msb = msb_con->value();
verinum lsb = lsb_con->value();
delete msb_exp;
delete lsb_exp;
if (msb.as_long() > lsb.as_long())
count = msb.as_long() - lsb.as_long() + 1;
else
count = lsb.as_long() - msb.as_long() + 1;
low = lsb.as_long();
high = msb.as_long();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGModule: Make range "
<< "[" << high << ":" << low << "]" << " of "
<< count << " UDPs for " << name << endl;
}
}
return count;
}
/*
* From a UDP definition in the source, make a NetUDP
* object. Elaborate the pin expressions as netlists, then connect
@ -2076,8 +2003,7 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const
}
long low = 0, high = 0;
unsigned inst_count = calculate_instance_count_(des, scope, high, low,
my_name);
unsigned inst_count = calculate_array_size_(des, scope, high, low);
if (inst_count == 0) return;
if (inst_count != 1) {

19
parse.y
View File

@ -4290,16 +4290,12 @@ gate_instance
| IDENTIFIER dimensions '(' port_conn_expression_list_with_nuls ')'
{ lgate*tmp = new lgate;
list<pform_range_t>*rng = $2;
tmp->name = $1;
tmp->parms = $4;
tmp->range = rng->front();
rng->pop_front();
assert(rng->empty());
tmp->ranges = $2;
tmp->file = @1.text;
tmp->lineno = @1.first_line;
delete[]$1;
delete rng;
$$ = tmp;
}
@ -4316,17 +4312,13 @@ gate_instance
| IDENTIFIER dimensions
{ lgate*tmp = new lgate;
list<pform_range_t>*rng = $2;
tmp->name = $1;
tmp->parms = 0;
tmp->parms_by_name = 0;
tmp->range = rng->front();
rng->pop_front();
assert(rng->empty());
tmp->ranges = $2;
tmp->file = @1.text;
tmp->lineno = @1.first_line;
delete[]$1;
delete rng;
$$ = tmp;
}
@ -4345,17 +4337,13 @@ gate_instance
| IDENTIFIER dimensions '(' port_name_list ')'
{ lgate*tmp = new lgate;
list<pform_range_t>*rng = $2;
tmp->name = $1;
tmp->parms = 0;
tmp->parms_by_name = $4;
tmp->range = rng->front();
rng->pop_front();
assert(rng->empty());
tmp->ranges = $2;
tmp->file = @1.text;
tmp->lineno = @1.first_line;
delete[]$1;
delete rng;
$$ = tmp;
}
@ -4377,6 +4365,7 @@ gate_instance
tmp->name = $1;
tmp->parms = 0;
tmp->parms_by_name = 0;
tmp->ranges = $2;
tmp->file = @1.text;
tmp->lineno = @1.first_line;
yyerror(@3, "error: Syntax error in instance port "

View File

@ -2260,8 +2260,7 @@ static void pform_makegate(PGBuiltin::Type type,
perm_string dev_name = lex_strings.make(info.name);
PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay);
if (info.range.first)
cur->set_range(info.range.first, info.range.second);
cur->set_ranges(info.ranges);
// The pform_makegates() that calls me will take care of
// deleting the attr pointer, so tell the
@ -2326,7 +2325,7 @@ static void pform_make_modgate(perm_string type,
perm_string name,
struct parmvalue_t*overrides,
list<PExpr*>*wires,
PExpr*msb, PExpr*lsb,
list<pform_range_t>*ranges,
const char*fn, unsigned ln,
std::list<named_pexpr_t>*attr)
{
@ -2337,7 +2336,7 @@ static void pform_make_modgate(perm_string type,
PGModule*cur = new PGModule(type, name, wires);
FILE_NAME(cur, fn, ln);
cur->set_range(msb,lsb);
cur->set_ranges(ranges);
if (overrides && overrides->by_name) {
unsigned cnt = overrides->by_name->size();
@ -2369,7 +2368,7 @@ static void pform_make_modgate(perm_string type,
perm_string name,
struct parmvalue_t*overrides,
list<named_pexpr_t>*bind,
PExpr*msb, PExpr*lsb,
list<pform_range_t>*ranges,
const char*fn, unsigned ln,
std::list<named_pexpr_t>*attr)
{
@ -2384,7 +2383,7 @@ static void pform_make_modgate(perm_string type,
PGModule*cur = new PGModule(type, name, pins, npins);
FILE_NAME(cur, fn, ln);
cur->set_range(msb,lsb);
cur->set_ranges(ranges);
if (overrides && overrides->by_name) {
unsigned cnt = overrides->by_name->size();
@ -2452,8 +2451,7 @@ void pform_make_modgates(const struct vlltype&loc,
if (cur.parms_by_name) {
pform_make_modgate(type, cur_name, overrides,
cur.parms_by_name,
cur.range.first, cur.range.second,
cur.parms_by_name, cur.ranges,
cur.file, cur.lineno, attr);
} else if (cur.parms) {
@ -2466,15 +2464,13 @@ void pform_make_modgates(const struct vlltype&loc,
cur.parms = new list<PExpr*>;
}
pform_make_modgate(type, cur_name, overrides,
cur.parms,
cur.range.first, cur.range.second,
cur.parms, cur.ranges,
cur.file, cur.lineno, attr);
} else {
list<PExpr*>*wires = new list<PExpr*>;
pform_make_modgate(type, cur_name, overrides,
wires,
cur.range.first, cur.range.second,
wires, cur.ranges,
cur.file, cur.lineno, attr);
}
}

View File

@ -105,14 +105,14 @@ struct net_decl_assign_t {
/* The lgate is gate instantiation information. */
struct lgate {
explicit inline lgate(int =0)
: parms(0), parms_by_name(0), file(NULL), lineno(0)
: parms(0), parms_by_name(0), ranges(0), file(NULL), lineno(0)
{ }
std::string name;
std::list<PExpr*>*parms;
std::list<named_pexpr_t>*parms_by_name;
pform_range_t range;
std::list<pform_range_t>*ranges;
const char* file;
unsigned lineno;

View File

@ -677,6 +677,17 @@ void PGate::dump_delays(ostream&out) const
delay_.dump_delays(out);
}
void PGate::dump_ranges(ostream&out) const
{
for (list<pform_range_t>::iterator cur = ranges_->begin()
; cur != ranges_->end() ; ++cur) {
out << "[";
if (cur->first) out << *(cur->first);
if (cur->second) out << ":" << *(cur->second);
out << "]";
}
}
void PGate::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << typeid(*this).name() << " ";
@ -739,11 +750,7 @@ void PGBuiltin::dump(ostream&out, unsigned ind) const
out << "(" << strength0() << "0 " << strength1() << "1) ";
dump_delays(out);
out << " " << get_name();
if (msb_) {
out << " [" << *msb_ << ":" << *lsb_ << "]";
}
dump_ranges(out);
out << "(";
dump_pins(out);
out << ");" << endl;
@ -784,16 +791,7 @@ void PGModule::dump(ostream&out, unsigned ind) const
}
out << get_name();
// If the module is arrayed, print the index expressions.
if (msb_ || lsb_) {
out << "[";
if (msb_) out << *msb_;
out << ":";
if (lsb_) out << *lsb_;
out << "]";
}
dump_ranges(out);
out << "(";
if (pins_) {
out << "." << pins_[0].name << "(";