From dcc9b59f6de98c36495dda344685cba89aa678e8 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sat, 6 Nov 2021 00:02:38 +0000 Subject: [PATCH] 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. --- PGate.cc | 40 +++++-------- PGate.h | 26 +++------ elab_scope.cc | 40 +++---------- elaborate.cc | 158 ++++++++++++++------------------------------------ parse.y | 19 ++---- pform.cc | 20 +++---- pform.h | 4 +- pform_dump.cc | 28 +++++---- 8 files changed, 100 insertions(+), 235 deletions(-) diff --git a/PGate.cc b/PGate.cc index f5057dcd0..1f51ffa54 100644 --- a/PGate.cc +++ b/PGate.cc @@ -41,7 +41,7 @@ void PGate::set_pins_(list*pins) } PGate::PGate(perm_string name, list*pins, const list*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*pins, const list*del) } PGate::PGate(perm_string name, list*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*pins, PExpr*del) } PGate::PGate(perm_string name, list*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*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*pins, list*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*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*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*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*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_; diff --git a/PGate.h b/PGate.h index 80ec0e5cc..1e57b8f67 100644 --- a/PGate.h +++ b/PGate.h @@ -60,6 +60,9 @@ class PGate : public PNamedItem { virtual ~PGate(); + void set_ranges(std::list*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& 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::vectorpins_; + std::list*ranges_; + ivl_drive_t str0_, str1_; void set_pins_(std::list*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*o); void set_parameters(named*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 attributes; virtual void dump(std::ostream&out, unsigned ind =4) const; @@ -241,16 +240,9 @@ class PGModule : public PGate { named*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; diff --git a/elab_scope.cc b/elab_scope.cc index 765393d55..fa0e1df96 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -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 (mse); - NetEConst*lsb = dynamic_cast (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; diff --git a/elaborate.cc b/elaborate.cc index 94799923a..8fbd10dd1 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -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(msb_exp); - NetEConst*lsb_con = dynamic_cast(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(msb_exp); - NetEConst*lsb_con = dynamic_cast(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) { diff --git a/parse.y b/parse.y index 54f6f7f4c..d7c923e13 100644 --- a/parse.y +++ b/parse.y @@ -4290,16 +4290,12 @@ gate_instance | IDENTIFIER dimensions '(' port_conn_expression_list_with_nuls ')' { lgate*tmp = new lgate; - list*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*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*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 " diff --git a/pform.cc b/pform.cc index 9db23f55a..6813fe837 100644 --- a/pform.cc +++ b/pform.cc @@ -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*wires, - PExpr*msb, PExpr*lsb, + list*ranges, const char*fn, unsigned ln, std::list*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*bind, - PExpr*msb, PExpr*lsb, + list*ranges, const char*fn, unsigned ln, std::list*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; } 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*wires = new list; pform_make_modgate(type, cur_name, overrides, - wires, - cur.range.first, cur.range.second, + wires, cur.ranges, cur.file, cur.lineno, attr); } } diff --git a/pform.h b/pform.h index c7ae8e0d6..a2d2d3f8d 100644 --- a/pform.h +++ b/pform.h @@ -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*parms; std::list*parms_by_name; - pform_range_t range; + std::list*ranges; const char* file; unsigned lineno; diff --git a/pform_dump.cc b/pform_dump.cc index e19c46be1..b563e9041 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -677,6 +677,17 @@ void PGate::dump_delays(ostream&out) const delay_.dump_delays(out); } +void PGate::dump_ranges(ostream&out) const +{ + for (list::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 << "(";