diff --git a/PExpr.h b/PExpr.h index f4f8145a7..a3d9288f3 100644 --- a/PExpr.h +++ b/PExpr.h @@ -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, diff --git a/elab_net.cc b/elab_net.cc index dd7af4fd0..ba0dcb00e 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -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="<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) { @@ -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="< (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; } @@ -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(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(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); @@ -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(tmp_ex); assert(tmp); @@ -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; @@ -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;