Skip to content

Commit

Permalink
Handle indexed part select in continuous assign.
Browse files Browse the repository at this point in the history
Non-constant indexed part select in continuous assignment generates
a select node with the correct width. In the process factor out and
share some of the part select calculations with expr part select
handling methods.

Signed-off-by: Stephen Williams <steve@icarus.com>
  • Loading branch information
steveicarus committed Jul 3, 2007
1 parent 88dea0c commit 018f1a6
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 40 deletions.
14 changes: 14 additions & 0 deletions PExpr.h
Expand Up @@ -358,6 +358,20 @@ class PEIdent : public PExpr {
Link::strength_t drive0,
Link::strength_t drive1) const;

NetNet* elaborate_net_net_(Design*des, NetScope*scope,
NetNet*sig, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
NetNet* elaborate_net_net_idx_up_(Design*des, NetScope*scope,
NetNet*sig, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const;
NetNet* elaborate_net_bitmux_(Design*des, NetScope*scope,
NetNet*sig,
const NetExpr* rise,
Expand Down
190 changes: 150 additions & 40 deletions elab_net.cc
Expand Up @@ -1709,10 +1709,74 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
drive0, drive1);
}

return elaborate_net_net_(des, scope, sig, lwidth,
rise, fall, decay, drive0, drive1);

}

NetNet* PEIdent::process_select_(Design*des, NetScope*scope,
NetNet*sig) const
{

// If there are more index items then there are array
// dimensions, then treat them as word part selects. For
// example, if this is a memory array, then array dimensions
// is 1 and
unsigned midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return sig;

unsigned part_count = midx-lidx+1;

// Maybe this is a full-width constant part select? If
// so, do nothing.
if (part_count == sig->vector_width())
return sig;

if (debug_elaborate) {
cerr << get_line() << ": debug: Elaborate part select"
<< " of word from " << sig->name() << "[base="<<lidx
<< " wid=" << part_count << "]" << endl;
}

NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count,
NetPartSelect::VP);
ps->set_line(*sig);
des->add_node(ps);

NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, part_count-1, 0);
tmp->data_type( sig->data_type() );
tmp->local_flag(true);
connect(tmp->pin(0), ps->pin(0));

return tmp;
}

NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
NetNet*sig, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const
{
const name_component_t&name_tail = path_.back();

index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;

switch (use_sel) {
case index_component_t::SEL_IDX_UP:
case index_component_t::SEL_IDX_DO:
return elaborate_net_net_idx_up_(des, scope, sig, lwidth,
rise, fall, decay, drive0, drive1);

default:
break;
}

/* Catch the case of a non-constant bit select. That should be
handled elsewhere. */
if (use_sel == index_component_t::SEL_BIT) {
Expand Down Expand Up @@ -1755,45 +1819,87 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
}



return sig;
}

NetNet* PEIdent::process_select_(Design*des, NetScope*scope,
NetNet*sig) const
NetNet* PEIdent::elaborate_net_net_idx_up_(Design*des, NetScope*scope,
NetNet*sig, unsigned lwidth,
const NetExpr* rise,
const NetExpr* fall,
const NetExpr* decay,
Link::strength_t drive0,
Link::strength_t drive1) const
{
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());

// If there are more index items then there are array
// dimensions, then treat them as word part selects. For
// example, if this is a memory array, then array dimensions
// is 1 and
unsigned midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return sig;
const index_component_t&index_tail = name_tail.index.back();
ivl_assert(*this, index_tail.lsb != 0);
ivl_assert(*this, index_tail.msb != 0);

unsigned part_count = midx-lidx+1;
NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);

// Maybe this is a full-width constant part select? If
// so, do nothing.
if (part_count == sig->vector_width())
return sig;
unsigned long wid = 0;
calculate_up_do_width_(des, scope, wid);

if (debug_elaborate) {
cerr << get_line() << ": debug: Elaborate part select"
<< " of word from " << sig->name() << "[base="<<lidx
<< " wid=" << part_count << "]" << endl;
bool down_flag = name_tail.index.back().sel==index_component_t::SEL_IDX_DO;

// Handle the special case that the base is constant as
// well. In this case it can be converted to a conventional
// part select.
if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
long lsv = base_c->value().as_long();

// convert from -: to +: form.
if (down_flag) lsv -= (wid-1);

// If the part select convers exactly the entire
// vector, then do not bother with it. Return the
// signal itself.
if (sig->sb_to_idx(lsv) == 0 && wid == sig->vector_width())
return sig;

NetPartSelect*sel = new NetPartSelect(sig, sig->sb_to_idx(lsv),
wid, NetPartSelect::VP);
sel->set_line(*this);
des->add_node(sel);

NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, wid);
tmp->set_line(*this);
tmp->data_type(sig->data_type());
connect(tmp->pin(0), sel->pin(0));

delete base;
return tmp;
}

NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count,
NetPartSelect::VP);
ps->set_line(*sig);
des->add_node(ps);
if (sig->msb() > sig->lsb()) {
long offset = sig->lsb();
if (down_flag)
offset += (wid-1);
if (offset != 0)
base = make_add_expr(base, 0-offset);
} else {
long vwid = sig->lsb() - sig->msb() + 1;
long offset = sig->msb();
if (down_flag)
offset += (wid-1);
base = make_sub_expr(vwid-offset-wid, base);
}

NetPartSelect*sel = new NetPartSelect(sig, base->synthesize(des), wid);
sel->set_line(*this);
des->add_node(sel);

NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, part_count-1, 0);
tmp->data_type( sig->data_type() );
tmp->local_flag(true);
connect(tmp->pin(0), ps->pin(0));
NetNet::WIRE, wid);
tmp->set_line(*this);
tmp->data_type(sig->data_type());
connect(tmp->pin(0), sel->pin(0));

delete base;
return tmp;
}

Expand Down Expand Up @@ -2136,18 +2242,17 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
case index_component_t::SEL_IDX_UP: {
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
assert(tmp);
ivl_assert(*this, tmp);

long midx_val = tmp->value().as_long();
midx = sig->sb_to_idx(midx_val);
delete tmp_ex;

tmp_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
tmp = dynamic_cast<NetEConst*>(tmp_ex);
assert(tmp);

long wid = tmp->value().as_long();
delete tmp_ex;
/* The width (a constant) is calculated here. */
unsigned long wid = 0;
bool flag = calculate_up_do_width_(des, scope, wid);
if (! flag)
return false;

if (index_tail.sel == index_component_t::SEL_IDX_UP)
lidx = sig->sb_to_idx(midx_val+wid-1);
Expand All @@ -2165,6 +2270,9 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,

case index_component_t::SEL_PART: {

long msb, lsb;
bool flag = calculate_parts_(des, scope, msb, lsb);
#if 0
NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
assert(tmp);
Expand All @@ -2185,15 +2293,17 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
long lidx_val = tmp->value().as_long();
lidx = sig->sb_to_idx(lidx_val);
delete tmp_ex;

#endif
lidx = sig->sb_to_idx(lsb);
midx = sig->sb_to_idx(msb);
/* Detect reversed indices of a part select. */
if (lidx > midx) {
cerr << get_line() << ": error: Part select "
<< sig->name() << "[" << midx_val << ":"
<< lidx_val << "] indices reversed." << endl;
<< sig->name() << "[" << msb << ":"
<< lsb << "] indices reversed." << endl;
cerr << get_line() << ": : Did you mean "
<< sig->name() << "[" << lidx_val << ":"
<< midx_val << "]?" << endl;
<< sig->name() << "[" << lsb << ":"
<< msb << "]?" << endl;
unsigned tmp = midx;
midx = lidx;
lidx = tmp;
Expand All @@ -2203,8 +2313,8 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
/* Detect a part select out of range. */
if (midx >= sig->vector_width()) {
cerr << get_line() << ": error: Part select "
<< sig->name() << "[" << midx_val << ":"
<< midx_val << "] out of range." << endl;
<< sig->name() << "[" << msb << ":"
<< lsb << "] out of range." << endl;
midx = sig->vector_width() - 1;
lidx = 0;
des->errors += 1;
Expand Down

0 comments on commit 018f1a6

Please sign in to comment.