Skip to content
Browse files

Get packed signals working through to simulation in some situations.

When dynamic indexing of early dimensions is not needed, we can get
pretty far with getting packed arrays to work.
  • Loading branch information...
1 parent e5c4902 commit 3e4f8b625f4c323d4e72abedb39a45be7625345a @steveicarus committed Feb 10, 2012
Showing with 366 additions and 77 deletions.
  1. +12 −0 PExpr.h
  2. +1 −1 design_dump.cc
  3. +67 −19 elab_expr.cc
  4. +57 −16 elab_lval.cc
  5. +10 −6 elab_net.cc
  6. +0 −6 elab_sig.cc
  7. +21 −8 ivl_target.h
  8. +54 −2 netlist.cc
  9. +25 −5 netlist.h
  10. +76 −0 netmisc.cc
  11. +5 −0 netmisc.h
  12. +27 −3 t-dll-api.cc
  13. +8 −7 t-dll.cc
  14. +3 −4 t-dll.h
View
12 PExpr.h
@@ -343,6 +343,18 @@ class PEIdent : public PExpr {
bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const;
+ // Evaluate the prefix indices. All but the final index in a
+ // chain of indices must be a single value and must evaluate
+ // to constants at compile time. For example:
+ // [x] - OK
+ // [1][2][x] - OK
+ // [1][x:y] - OK
+ // [2:0][x] - BAD
+ // [y][x] - BAD
+ // Leave the last index for special handling.
+ bool calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
+ std::list<long>&prefix_indices) const;
+
private:
NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const;
bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const;
View
2 design_dump.cc
@@ -1518,7 +1518,7 @@ void NetESignal::dump(ostream&o) const
o << "+";
o << name();
if (word_) o << "[word=" << *word_ << "]";
- o << "[" << msi()<<":"<<lsi() << "]";
+ o << sig()->packed_dims();
}
void NetETernary::dump(ostream&o) const
View
86 elab_expr.cc
@@ -1854,6 +1854,17 @@ NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const
return tmp;
}
+bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net,
+ list<long>&prefix_indices) const
+{
+ list<index_component_t> index;
+ index = path_.back().index;
+ for (size_t idx = 0 ; idx < net->array_dimensions() ; idx += 1)
+ index.pop_front();
+
+ return evaluate_index_prefix(des, scope, prefix_indices, index);
+}
+
/*
* Given that the msb_ and lsb_ are part select expressions, this
* function calculates their values. Note that this method does *not*
@@ -3101,6 +3112,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
unsigned expr_wid) const
{
+ list<long> prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
long msv, lsv;
bool parts_defined_flag;
bool flag = calculate_parts_(des, scope, msv, lsv, parts_defined_flag);
@@ -3133,9 +3148,8 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
tmp->set_line(*this);
return tmp;
}
-
- long sb_lsb = net->sig()->sb_to_idx(lsv);
- long sb_msb = net->sig()->sb_to_idx(msv);
+ long sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv);
+ long sb_msb = net->sig()->sb_to_idx(prefix_indices, msv);
if (sb_msb < sb_lsb) {
cerr << get_fileline() << ": error: part select " << net->name();
@@ -3207,6 +3221,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
+ list<long>prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
unsigned long wid = 0;
@@ -3224,7 +3242,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
- if (net->sig()->sb_to_idx(lsv) == 0 &&
+ if (net->sig()->sb_to_idx(prefix_indices, lsv) == 0 &&
wid == net->vector_width()) {
delete base;
net->cast_signed(false);
@@ -3237,10 +3255,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope,
}
// Otherwise, make a part select that covers the right
// range.
- ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
- offset));
+ ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset));
if (warn_ob_select) {
- long rel_base = net->sig()->sb_to_idx(lsv) + offset;
+ long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
@@ -3296,6 +3313,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
+ list<long>prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
NetExpr*base = calculate_up_do_base_(des, scope, need_const);
unsigned long wid = 0;
@@ -3312,7 +3333,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
// If the part select covers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
- if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) &&
+ if (net->sig()->sb_to_idx(prefix_indices,lsv) == (signed) (wid-1) &&
wid == net->vector_width()) {
delete base;
net->cast_signed(false);
@@ -3325,10 +3346,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope,
}
// Otherwise, make a part select that covers the right
// range.
- ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) +
- offset));
+ ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset));
if (warn_ob_select) {
- long rel_base = net->sig()->sb_to_idx(lsv) + offset;
+ long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset;
if (rel_base < 0) {
cerr << get_fileline() << ": warning: "
<< net->name();
@@ -3381,19 +3401,23 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetESignal*net, NetScope*,
bool need_const) const
{
+ list<long>prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
- NetExpr*ex = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
+ NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const);
// If the bit select is constant, then treat it similar
// to the part select, so that I save the effort of
// making a mux part in the netlist.
- if (NetEConst*msc = dynamic_cast<NetEConst*> (ex)) {
+ if (NetEConst*msc = dynamic_cast<NetEConst*> (mux)) {
// Special case: The bit select expression is constant
// x/z. The result of the expression is 1'bx.
@@ -3414,12 +3438,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
- delete ex;
+ delete mux;
return tmp;
}
long msv = msc->value().as_long();
- long idx = net->sig()->sb_to_idx(msv);
+ long idx = net->sig()->sb_to_idx(prefix_indices,msv);
if (idx >= (long)net->vector_width() || idx < 0) {
/* The bit select is out of range of the
@@ -3444,7 +3468,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
NetEConst*tmp = make_const_x(1);
tmp->set_line(*this);
- delete ex;
+ delete mux;
return tmp;
}
@@ -3464,16 +3488,36 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope,
return res;
}
+ const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
+ if (prefix_indices.size()+2 <= sig_packed.size()) {
+ // Special case: this is a slice of a multi-dimensional
+ // packed array. For example:
+ // reg [3:0][7:0] x;
+ // x[2] = ...
+ // This shows up as the prefix_indices being too short
+ // for the packed dimensions of the vector. What we do
+ // here is convert to a "slice" of the vector.
+ unsigned long lwid;
+ mux = normalize_variable_slice_base(prefix_indices, mux,
+ net->sig(), lwid);
+ mux->set_line(*net);
+
+ // Make a PART select with the canonical index
+ NetESelect*res = new NetESelect(net, mux, lwid);
+ res->set_line(*net);
+
+ return res;
+ }
+
// Non-constant bit select? punt and make a subsignal
// device to mux the bit in the net. This is a fairly
// complicated task because we need to generate
// expressions to convert calculated bit select
// values to canonical values that are used internally.
- const list<NetNet::range_t>& sig_packed = net->sig()->packed_dims();
assert(sig_packed.size() == 1);
- ex = normalize_variable_base(ex, sig_packed, 1, true);
+ mux = normalize_variable_base(mux, sig_packed, 1, true);
- NetESelect*ss = new NetESelect(net, ex, 1);
+ NetESelect*ss = new NetESelect(net, mux, 1);
ss->set_line(*this);
return ss;
}
@@ -3506,6 +3550,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope,
return 0;
}
+ list<long> prefix_indices;
+ bool rc = evaluate_index_prefix(des, scope, prefix_indices, path_.back().index);
+ ivl_assert(*this, rc);
+
// If this is a part select of a signal, then make a new
// temporary signal that is connected to just the
// selected bits. The lsb_ and msb_ expressions are from
View
73 elab_lval.cc
@@ -183,24 +183,34 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
ivl_assert(*this, reg);
-
+ // We are processing the tail of a string of names. For
+ // example, the verilog may be "a.b.c", so we are processing
+ // "c" at this point.
const name_component_t&name_tail = path_.back();
+ // Use the last index to determine what kind of select
+ // (bit/part/etc) we are processing. For example, the verilog
+ // may be "a.b.c[1][2][<index>]". All but the last index must
+ // be simple expressions, only the <index> may be a part
+ // select etc., so look at it to determine how we will be
+ // proceeding.
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
- // This is the special case that the l-value is an entire
- // memory. This is, in fact, an error.
- if (reg->array_dimensions() > 0 && name_tail.index.empty()) {
+ // Special case: The l-value is an entire memory, or array
+ // slice. This is, in fact, an error in l-values. Detect the
+ // situation by noting if the index count is less then the
+ // array dimensions (unpacked).
+ if (reg->array_dimensions() > name_tail.index.size()) {
cerr << get_fileline() << ": error: Cannot assign to array "
<< path_ << ". Did you forget a word index?" << endl;
des->errors += 1;
return 0;
}
/* Get the signal referenced by the identifier, and make sure
- it is a register. Wires are not allows in this context,
+ it is a register. Wires are not allowed in this context,
unless this is the l-value of a force. */
if ((reg->type() != NetNet::REG) && !is_force) {
cerr << get_fileline() << ": error: " << path_ <<
@@ -347,7 +357,13 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
+ list<long>prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
const name_component_t&name_tail = path_.back();
+ ivl_assert(*this, !name_tail.index.empty());
+
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
@@ -365,26 +381,43 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
mux = 0;
}
- // For now, we only understand 1-dim packed arrays.
- const list<NetNet::range_t>&packed = reg->packed_dims();
- ivl_assert(*this, packed.size() == 1);
- const NetNet::range_t rng = packed.back();
- if (mux) {
+ if (prefix_indices.size()+2 <= reg->packed_dims().size()) {
+ // Special case: this is a slice of a multi-dimensional
+ // packed array. For example:
+ // reg [3:0][7:0] x;
+ // x[2] = ...
+ // This shows up as the prefix_indices being too short
+ // for the packed dimensions of the vector. What we do
+ // here is convert to a "slice" of the vector.
+ if (mux == 0) {
+ long loff;
+ unsigned long lwid;
+ bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid);
+ ivl_assert(*this, rcl);
+
+ lv->set_part(new NetEConst(verinum(loff)), lwid);
+ } else {
+ unsigned long lwid;
+ mux = normalize_variable_slice_base(prefix_indices, mux,
+ reg, lwid);
+ lv->set_part(mux, lwid);
+ }
+
+ } else if (mux) {
// Non-constant bit mux. Correct the mux for the range
// of the vector, then set the l-value part select
// expression.
mux = normalize_variable_base(mux, reg->packed_dims(), 1, true);
-
lv->set_part(mux, 1);
- } else if (lsb == rng.msb && lsb == rng.lsb) {
+ } else if (reg->vector_width() == 1 && reg->sb_is_valid(prefix_indices,lsb)) {
// Constant bit mux that happens to select the only bit
// of the l-value. Don't bother with any select at all.
} else {
// Constant bit select that does something useful.
- long loff = reg->sb_to_idx(lsb);
+ long loff = reg->sb_to_idx(prefix_indices,lsb);
if (loff < 0 || loff >= (long)reg->vector_width()) {
cerr << get_fileline() << ": error: bit select "
@@ -404,6 +437,10 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
NetScope*scope,
NetAssign_*lv) const
{
+ list<long> prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
// The range expressions of a part select must be
// constant. The calculate_parts_ function calculates the
// values into msb and lsb.
@@ -429,8 +466,8 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
} else {
/* Get the canonical offsets into the vector. */
- long loff = reg->sb_to_idx(lsb);
- long moff = reg->sb_to_idx(msb);
+ long loff = reg->sb_to_idx(prefix_indices,lsb);
+ long moff = reg->sb_to_idx(prefix_indices,msb);
long wid = moff - loff + 1;
if (moff < loff) {
@@ -463,6 +500,10 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
NetAssign_*lv,
index_component_t::ctype_t use_sel) const
{
+ list<long>prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
+ ivl_assert(*this, rc);
+
const name_component_t&name_tail = path_.back();;
ivl_assert(*this, !name_tail.index.empty());
@@ -509,7 +550,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
offset = -wid + 1;
}
delete base;
- long rel_base = reg->sb_to_idx(lsv) + offset;
+ long rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset;
/* If we cover the entire lvalue just skip the select. */
if (rel_base == 0 && wid == reg->vector_width()) return true;
base = new NetEConst(verinum(rel_base));
View
16 elab_net.cc
@@ -200,6 +200,10 @@ bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
long&midx, long&lidx) const
{
+ list<long> prefix_indices;
+ bool rc = calculate_packed_indices_(des, scope, sig, prefix_indices);
+ ivl_assert(*this, rc);
+
const name_component_t&name_tail = path_.back();
// Only treat as part/bit selects any index that is beyond the
// word selects for an array. This is not an array, then
@@ -258,13 +262,13 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
long midx_val = tmp->value().as_long();
- midx = sig->sb_to_idx(midx_val);
+ midx = sig->sb_to_idx(prefix_indices, midx_val);
delete tmp_ex;
if (index_tail.sel == index_component_t::SEL_IDX_UP)
- lidx = sig->sb_to_idx(midx_val+wid-1);
+ lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1);
else
- lidx = sig->sb_to_idx(midx_val-wid+1);
+ lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1);
if (midx < lidx) {
long tmpx = midx;
@@ -313,8 +317,8 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
/* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag);
ivl_assert(*this, part_defined_flag);
- long lidx_tmp = sig->sb_to_idx(lsb);
- long midx_tmp = sig->sb_to_idx(msb);
+ long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb);
+ long midx_tmp = sig->sb_to_idx(prefix_indices, msb);
/* Detect reversed indices of a part select. */
if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
@@ -370,7 +374,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
}
assert(mval);
- midx = sig->sb_to_idx(mval->as_long());
+ midx = sig->sb_to_idx(prefix_indices, mval->as_long());
if (midx >= (long)sig->vector_width()) {
cerr << get_fileline() << ": error: Index " << sig->name()
<< "[" << mval->as_long() << "] is out of range."
View
6 elab_sig.cc
@@ -1149,12 +1149,6 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
cerr << " in scope " << scope_path(scope) << endl;
}
- if (packed_dimensions.size() > 1) {
- cerr << get_fileline() << ": sorry: Multi-dimension "
- << "packed arrays not supported." << endl;
- des->errors += 1;
- }
-
sig = array_dimensions > 0
? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0)
: new NetNet(scope, name_, wtype, packed_dimensions);
View
29 ivl_target.h
@@ -1785,13 +1785,23 @@ extern int ivl_scope_time_units(ivl_scope_t net);
* If the signal has been declared with a domain (Verilog-AMS) then
* this function will return a non-nil ivl_discipline_t.
*
- * ivl_signal_msb
- * ivl_signal_lsb
+ * ivl_signal_msb (deprecated)
+ * ivl_signal_lsb (deprecated)
+ * ivl_signal_packed_dimensions
+ * ivl_signal_packed_msb
+ * ivl_signal_packed_lsb
* ivl_signal_width
- * These functions return the left and right indices, respectively,
- * of the signal. If the signal is a scalar, both return 0. However,
- * it doesn't mean that the signal is a scalar if both return 0, one
- * can have a vector with 0 as both indices.
+ * These functions return the msb and lsb packed indices. The
+ * packed dimensions are declared differently from array
+ * dimensions, like so:
+ * reg [4:1][7:0] sig...
+ * which has two packed dimensions. The [4:1] dimension is the
+ * first, and so forth. If the signal is a scalar, it has 0
+ * dimension.
+ *
+ * The ivl_signal_msb/ivl_signal_lsb functions are deprecated
+ * versions that only work with variables that have less then two
+ * dimensions. They will return msb==lsb==0 for scalars.
*
* ivl_signal_port
* If the signal is a port to a module, this function returns the
@@ -1859,8 +1869,11 @@ extern unsigned ivl_signal_array_count(ivl_signal_t net);
extern unsigned ivl_signal_array_addr_swapped(ivl_signal_t net);
extern unsigned ivl_signal_dimensions(ivl_signal_t net);
extern ivl_discipline_t ivl_signal_discipline(ivl_signal_t net);
-extern int ivl_signal_msb(ivl_signal_t net);
-extern int ivl_signal_lsb(ivl_signal_t net);
+extern unsigned ivl_signal_packed_dimensions(ivl_signal_t net);
+extern int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim);
+extern int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim);
+extern int ivl_signal_msb(ivl_signal_t net) __attribute__((deprecated));
+extern int ivl_signal_lsb(ivl_signal_t net) __attribute__((deprecated));
extern unsigned ivl_signal_width(ivl_signal_t net);
extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net);
extern int ivl_signal_signed(ivl_signal_t net);
View
56 netlist.cc
@@ -780,8 +780,9 @@ unsigned long NetNet::vector_width(const list<NetNet::range_t>&packed)
return wid;
}
-bool NetNet::sb_is_valid(long sb) const
+bool NetNet::sb_is_valid(const list<long>&indices, long sb) const
{
+ ivl_assert(*this, indices.size()+1 == packed_dims_.size());
assert(packed_dims_.size() == 1);
const range_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
@@ -790,8 +791,9 @@ bool NetNet::sb_is_valid(long sb) const
return (sb <= rng.lsb) && (sb >= rng.msb);
}
-long NetNet::sb_to_idx(long sb) const
+long NetNet::sb_to_idx(const list<long>&indices, long sb) const
{
+ ivl_assert(*this, indices.size()+1 == packed_dims_.size());
assert(packed_dims_.size() == 1);
const range_t&rng = packed_dims_.back();
if (rng.msb >= rng.lsb)
@@ -800,6 +802,56 @@ long NetNet::sb_to_idx(long sb) const
return rng.lsb - sb;
}
+bool NetNet::sb_to_slice(const list<long>&indices, long sb, long&loff, unsigned long&lwid) const
+{
+ ivl_assert(*this, indices.size() < packed_dims_.size());
+
+ size_t acc_wid = 1;
+ list<range_t>::const_iterator pcur = packed_dims_.end();
+ for (size_t idx = indices.size()+1 ; idx < packed_dims_.size() ; idx += 1) {
+ -- pcur;
+ acc_wid *= pcur->width();
+ }
+
+ lwid = acc_wid;
+
+ -- pcur;
+ if (sb < pcur->msb && sb < pcur->lsb)
+ return false;
+ if (sb > pcur->msb && sb > pcur->lsb)
+ return false;
+
+ long acc_off = 0;
+ if (pcur->msb >= pcur->lsb)
+ acc_off += (sb - pcur->lsb) * acc_wid;
+ else
+ acc_off += (sb - pcur->msb) * acc_wid;
+
+ if (indices.size() == 0) {
+ loff = acc_off;
+ return true;
+ }
+
+ lwid *= pcur->width();
+
+ list<long>::const_iterator icur = indices.end();
+ do {
+ -- pcur;
+ -- icur;
+ acc_wid *= pcur->width();
+ if (pcur->msb >= pcur->lsb)
+ acc_off += (*icur - pcur->lsb) * acc_wid;
+ else
+ acc_off += (*icur - pcur->msb) * acc_wid;
+
+ } while (icur != indices.begin());
+
+ loff = acc_off;
+
+ return true;
+}
+
+
unsigned NetNet::array_dimensions() const
{
return dimensions_;
View
30 netlist.h
@@ -550,7 +550,7 @@ class NetDelaySrc : public NetObj {
*
* NetNet objects are located by searching NetScope objects.
*
- * The pin of a NetNet object are PASSIVE: they do not drive
+ * The pins of a NetNet object are PASSIVE: they do not drive
* anything and they are not a data sink, per se. The pins follow the
* values on the nexus.
*/
@@ -573,6 +573,9 @@ class NetNet : public NetObj {
long msb;
long lsb;
+
+ inline unsigned long width()const
+ { if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; }
};
public:
@@ -639,15 +642,30 @@ class NetNet : public NetObj {
static unsigned long vector_width(const std::list<NetNet::range_t>&);
unsigned long vector_width() const { return vector_width(packed_dims_); }
+ /* Given a prefix of indices, figure out how wide the
+ resulting slice would be. This is a generalization of the
+ vector_width(), where the depth would be 0. */
+ unsigned long slice_width(size_t depth) const;
+
/* This method converts a signed index (the type that might be
- found in the Verilog source) to a pin number. It accounts
- for variation in the definition of the reg/wire/whatever. */
- long sb_to_idx(long sb) const;
+ found in the Verilog source) to canonical. It accounts
+ for variation in the definition of the
+ reg/wire/whatever. Note that a canonical index of a
+ multi-dimensioned packed array is a single dimension. For
+ example, "reg [4:1][3:0]..." has the canonical dimension
+ [15:0] and the sb_to_idx) method will convert [2][2] to
+ the canonical index [6]. */
+ long sb_to_idx(const std::list<long>&prefix, long sb) const;
+
+ /* This method converts a partial packed indices list and a
+ tail index, and generates a canonical slice offset and
+ width. */
+ bool sb_to_slice(const std::list<long>&prefix, long sb, long&off, unsigned long&wid) const;
/* This method checks that the signed index is valid for this
signal. If it is, the above sb_to_idx can be used to get
the pin# from the index. */
- bool sb_is_valid(long sb) const;
+ bool sb_is_valid(const std::list<long>&prefix, long sb) const;
/* This method returns 0 for scalars and vectors, and greater
for arrays. The value is the number of array
@@ -2348,6 +2366,8 @@ class NetAssign_ {
ivl_select_type_t select_type() const;
void set_word(NetExpr*);
+ // Set a part select expression for the l-value vector. Note
+ // that the expression calculates a CANONICAL bit address.
void set_part(NetExpr* loff, unsigned wid,
ivl_select_type_t = IVL_SEL_OTHER);
View
76 netmisc.cc
@@ -198,6 +198,21 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr)
return res;
}
+static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val)
+{
+ verinum val_v (val, expr->expr_width());
+ val_v.has_sign(true);
+
+ NetEConst*val_c = new NetEConst(val_v);
+ val_c->set_line(*expr);
+
+ NetEBMult*res = new NetEBMult('*', expr, val_c, expr->expr_width(),
+ expr->has_sign());
+ res->set_line(*expr);
+
+ return res;
+}
+
/*
* This routine is used to calculate the number of bits needed to
* contain the given number.
@@ -310,6 +325,31 @@ NetExpr *normalize_variable_base(NetExpr *base,
return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up);
}
+NetExpr *normalize_variable_slice_base(const list<long>&indices, NetExpr*base,
+ const NetNet*reg, unsigned long&lwid)
+{
+ const list<NetNet::range_t>&packed_dims = reg->packed_dims();
+ ivl_assert(*base, indices.size() < packed_dims.size());
+
+ list<NetNet::range_t>::const_iterator pcur = packed_dims.end();
+ for (size_t idx = indices.size() ; idx < packed_dims.size(); idx += 1) {
+ -- pcur;
+ }
+
+ long sb;
+ if (pcur->msb >= pcur->lsb)
+ sb = pcur->lsb;
+ else
+ sb = pcur->msb;
+
+ long loff;
+ reg->sb_to_slice(indices, sb, loff, lwid);
+
+ base = make_mult_expr(base, lwid);
+ base = make_add_expr(base, loff);
+ return base;
+}
+
/*
* This routine generates the normalization expression needed for a variable
* array word select.
@@ -858,3 +898,39 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig)
delete ps_obj;
}
}
+
+/*
+ * Evaluate the prefix indices. All but the final index in a
+ * chain of indices must be a single value and must evaluate
+ * to constants at compile time. For example:
+ * [x] - OK
+ * [1][2][x] - OK
+ * [1][x:y] - OK
+ * [2:0][x] - BAD
+ * [y][x] - BAD
+ * Leave the last index for special handling.
+ */
+bool evaluate_index_prefix(Design*des, NetScope*scope,
+ list<long>&prefix_indices,
+ const list<index_component_t>&indices)
+{
+ list<index_component_t>::const_iterator icur = indices.begin();
+ for (size_t idx = 0 ; (idx+1) < indices.size() ; idx += 1, ++icur) {
+ assert(icur != indices.end());
+ assert(icur->sel == index_component_t::SEL_BIT);
+ NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, true);
+ ivl_assert(*icur->msb, texpr);
+ long tmp;
+ if (!eval_as_long(tmp, texpr)) {
+ cerr << icur->msb->get_fileline() << ": error: "
+ "Array index expressions must be constant." << endl;
+ des->errors += 1;
+ return 0;
+ }
+
+ prefix_indices .push_back(tmp);
+ delete texpr;
+ }
+
+ return true;
+}
View
5 netmisc.h
@@ -103,6 +103,8 @@ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb,
extern NetExpr*normalize_variable_base(NetExpr *base,
const list<NetNet::range_t>&dims,
unsigned long wid, bool is_up);
+extern NetExpr*normalize_variable_slice_base(const list<long>&indices, NetExpr *base,
+ const NetNet*reg, unsigned long&lwid);
extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset,
unsigned count);
@@ -238,4 +240,7 @@ extern uint64_t get_scaled_time_from_real(Design*des,
extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig);
+extern bool evaluate_index_prefix(Design*des, NetScope*scope,
+ list<long>&prefix_indices,
+ const list<index_component_t>&indices);
#endif
View
30 t-dll-api.cc
@@ -2147,15 +2147,39 @@ extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word)
}
}
+extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net)
+{
+ return net->packed_dims.size();
+}
+
+extern "C" int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim)
+{
+ assert(dim < net->packed_dims.size());
+ return net->packed_dims[dim].msb;
+}
+
+extern "C" int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim)
+{
+ assert(dim < net->packed_dims.size());
+ return net->packed_dims[dim].lsb;
+}
+
extern "C" int ivl_signal_msb(ivl_signal_t net)
{
- assert(net->lsb_dist == 1 || net->lsb_dist == -1);
- return net->lsb_index + net->lsb_dist * (net->width_ - 1);
+ if (net->packed_dims.size() == 0)
+ return 0;
+
+ assert(net->packed_dims.size() == 1);
+ return net->packed_dims[0].msb;
}
extern "C" int ivl_signal_lsb(ivl_signal_t net)
{
- return net->lsb_index;
+ if (net->packed_dims.size() == 0)
+ return 0;
+
+ assert(net->packed_dims.size() == 1);
+ return net->packed_dims[0].lsb;
}
extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net)
View
15 t-dll.cc
@@ -2399,16 +2399,17 @@ void dll_target::signal(const NetNet*net)
/* Save the primitive properties of the signal in the
ivl_signal_t object. */
- // FIX ME: This is a temporary workaround until the ivl_target
- // API gets a way to represent multiple packed dimensions.
- const list<NetNet::range_t>&packed = net->packed_dims();
- ivl_assert(*net, packed.size() <= 1);
- const NetNet::range_t rng = packed.empty()? NetNet::range_t(0,0) : packed.back();
+ { size_t idx = 0;
+ list<NetNet::range_t>::const_iterator cur;
+ obj->packed_dims.resize(net->packed_dims().size());
+ for (cur = net->packed_dims().begin(), idx = 0
+ ; cur != net->packed_dims().end() ; ++cur, idx += 1) {
+ obj->packed_dims[idx] = *cur;
+ }
+ }
obj->width_ = net->vector_width();
obj->signed_= net->get_signed()? 1 : 0;
- obj->lsb_index = rng.lsb;
- obj->lsb_dist = rng.msb >= rng.lsb ? 1 : -1;
obj->isint_ = false;
obj->local_ = net->local_flag()? 1 : 0;
obj->forced_net_ = (net->type() != NetNet::REG) &&
View
7 t-dll.h
@@ -688,10 +688,9 @@ struct ivl_signal_s {
unsigned array_dimensions_ : 1;
unsigned array_addr_swapped : 1;
- /* These encode the run-time index for the least significant
- bit, and the distance to the second bit. */
- signed lsb_index;
- signed lsb_dist;
+ /* These encode the declared packed dimensions for the
+ signal, in case they are needed by the run-time */
+ std::vector<NetNet::range_t> packed_dims;
perm_string name_;
ivl_scope_t scope_;

0 comments on commit 3e4f8b6

Please sign in to comment.
Something went wrong with that request. Please try again.