Handle l-value part select of packed arrays.

This commit is contained in:
Stephen Williams 2012-02-10 18:48:12 -08:00
parent 3e4f8b625f
commit 4287fc4b50
5 changed files with 89 additions and 45 deletions

View File

@ -456,42 +456,47 @@ bool PEIdent::elaborate_lval_net_part_(Design*des,
ivl_assert(*this, reg);
const list<NetNet::range_t>&packed = reg->packed_dims();
ivl_assert(*this, packed.size() == 1);
const NetNet::range_t&rng = packed.back();
if (msb == rng.msb && lsb == rng.lsb) {
/* Part select covers the entire vector. Simplest case. */
} else {
/* Get the canonical offsets into the vector. */
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) {
cerr << get_fileline() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return false;
}
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if (loff < 0 || moff >= (signed)reg->vector_width()) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
}
lv->set_part(new NetEConst(verinum(loff)), wid);
// Part selects cannot select slices. So there must be enough
// prefix_indices to get all the way to the final dimension.
if (prefix_indices.size()+1 < packed.size()) {
cerr << get_fileline() << ": error: Cannot select a range "
<< "of slices from a packed array." << endl;
des->errors += 1;
return false;
}
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) {
cerr << get_fileline() << ": error: part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is reversed." << endl;
des->errors += 1;
return false;
}
// Special case: The range winds up selecting the entire
// vector. Treat this as no part select at all.
if (loff == 0 && moff == (reg->vector_width()-1)) {
return true;
}
/* If the part select extends beyond the extremes of the
variable, then report an error. Note that loff is
converted to normalized form so is relative the
variable pins. */
if (loff < 0 || moff >= (signed)reg->vector_width()) {
cerr << get_fileline() << ": warning: Part select "
<< reg->name() << "[" << msb<<":"<<lsb<<"]"
<< " is out of range." << endl;
}
lv->set_part(new NetEConst(verinum(loff)), wid);
return true;
}

View File

@ -794,12 +794,39 @@ bool NetNet::sb_is_valid(const list<long>&indices, 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)
return sb - rng.lsb;
list<range_t>::const_iterator pcur = packed_dims_.end();
-- pcur;
long acc_off;
long acc_wid = pcur->width();
if (pcur->msb >= pcur->lsb)
acc_off = sb - pcur->lsb;
else
return rng.lsb - sb;
acc_off = pcur->lsb - sb;
// The acc_off is the possition within the innermost
// dimension. If this is a multi-dimension packed array then
// we need to add in the canonical address of the current slice.
if (indices.size() >= 1) {
list<long>::const_iterator icur = indices.end();
do {
-- icur;
-- pcur;
long tmp_off;
if (pcur->msb >= pcur->lsb)
tmp_off = *icur - pcur->lsb;
else
tmp_off = pcur->lsb - *icur;
acc_off += tmp_off * acc_wid;
acc_wid *= pcur->width();
} while (icur != indices.begin());
}
return acc_off;
}
bool NetNet::sb_to_slice(const list<long>&indices, long sb, long&loff, unsigned long&lwid) const

View File

@ -653,7 +653,7 @@ class NetNet : public NetObj {
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
[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;

View File

@ -1288,11 +1288,14 @@ static void show_signal(ivl_signal_t net)
for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) {
ivl_nexus_t nex = ivl_signal_nex(net, idx);
unsigned dim;
fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] "
"<width=%u%s> <discipline=%s> ",
type, sign, port, data_type,
ivl_signal_msb(net), ivl_signal_lsb(net),
fprintf(out, " %s %s %s%s", type, sign, port, data_type);
for (dim = 0 ; dim < ivl_signal_packed_dimensions(net) ; dim += 1) {
fprintf(out, "[%d:%d]", ivl_signal_packed_msb(net,dim),
ivl_signal_packed_lsb(net,dim));
}
fprintf(out, " %s[word=%u, adr=%d] <width=%u%s> <discipline=%s> ",
ivl_signal_basename(net),
idx, ivl_signal_array_base(net)+idx,
ivl_signal_width(net),

View File

@ -425,8 +425,17 @@ const char*draw_input_from_net(ivl_nexus_t nex)
*/
static void draw_reg_in_scope(ivl_signal_t sig)
{
int msb = ivl_signal_msb(sig);
int lsb = ivl_signal_lsb(sig);
int msb;
int lsb;
if (ivl_signal_packed_dimensions(sig) > 1) {
// FIX ME: Improve this when vvp becomes aware of packed
// arrays.
msb = ivl_signal_width(sig) - 1;
lsb = 0;
} else {
msb = ivl_signal_msb(sig);
lsb = ivl_signal_lsb(sig);
}
const char*datatype_flag = ivl_signal_integer(sig) ? "/i" :
ivl_signal_signed(sig)? "/s" : "";