From b31124983a5efb27f2b2bd1a8c8b4560078880e6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 6 Jun 2008 22:05:17 -0700 Subject: [PATCH] Allow part selects to fall off the ends of the selected identifier Part selects to signals are allowed to be off the ends of the signal itself. The bits that are beyond the vector return X. This may mean creating constant X bits on one or both ends of the result. --- elab_expr.cc | 97 +++++++++++++++++++++++++++++++++++++--------------- netmisc.cc | 7 ++++ netmisc.h | 5 +++ 3 files changed, 81 insertions(+), 28 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index d452b31e4..9cc1acf1b 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1370,8 +1370,7 @@ NetExpr* PEIdent::elaborate_expr_net_word_(Design*des, NetScope*scope, // Special case: The index is out of range, so the value // of this expression is a 'bx vector the width of a word. if (!net->array_index_is_valid(addr)) { - verinum xxx (verinum::Vx, net->vector_width()); - NetEConst*resx = new NetEConst(xxx); + NetEConst*resx = make_const_x(net->vector_width()); resx->set_line(*this); delete word_index; return resx; @@ -1437,16 +1436,7 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, negative values. However, the width that they represent is unsigned. Remember that any order is possible, i.e., [1:0], [-4:6], etc. */ - unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv)); - if (wid > net->vector_width()) { - cerr << get_fileline() << ": error: part select [" - << msv << ":" << lsv << "] out of range." << endl; - des->errors += 1; - //delete lsn; - //delete msn; - return net; - } - ivl_assert(*this, wid <= net->vector_width()); + unsigned long wid = 1 + labs(msv-lsv); if (net->sig()->sb_to_idx(msv) < net->sig()->sb_to_idx(lsv)) { cerr << get_fileline() << ": error: part select [" @@ -1457,27 +1447,79 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, return net; } - - if (net->sig()->sb_to_idx(msv) >= (signed) net->vector_width()) { - cerr << get_fileline() << ": error: part select [" - << msv << ":" << lsv << "] out of range." << endl; - des->errors += 1; - //delete lsn; - //delete msn; - return net; - } + long sb_lsb = net->sig()->sb_to_idx(lsv); + long sb_msb = net->sig()->sb_to_idx(msv); // 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 && wid == net->vector_width()) + if (sb_lsb == 0 && wid == net->vector_width()) return net; - NetExpr*ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv))); - NetESelect*ss = new NetESelect(net, ex, wid); - ss->set_line(*this); + // If the part select covers NONE of the vector, then return a + // constant X. - return ss; + if ((sb_lsb >= (signed) net->vector_width()) || (sb_msb < 0)) { + NetEConst*tmp = make_const_x(wid); + tmp->set_line(*this); + return tmp; + } + + // If the part select is entirely within the vector, then make + // a simple part select. + if (sb_lsb >= 0 && sb_msb < (signed)net->vector_width()) { + NetExpr*ex = new NetEConst(verinum(sb_lsb)); + NetESelect*ss = new NetESelect(net, ex, wid); + ss->set_line(*this); + return ss; + } + + // Now the hard stuff. The part select is falling off at least + // one end. We're going to need a NetEConcat to mix the + // selection with overrun. + + NetEConst*bot = 0; + if (sb_lsb < 0) { + bot = make_const_x( 0-sb_lsb ); + bot->set_line(*this); + sb_lsb = 0; + } + NetEConst*top = 0; + if (sb_msb >= (signed)net->vector_width()) { + top = make_const_x( 1+sb_msb-net->vector_width() ); + top->set_line(*this); + sb_msb = net->vector_width()-1; + } + + unsigned concat_count = 1; + if (bot) concat_count += 1; + if (top) concat_count += 1; + + NetEConcat*concat = new NetEConcat(concat_count); + concat->set_line(*this); + + if (bot) { + concat_count -= 1; + concat->set(concat_count, bot); + } + if (sb_lsb == 0 && sb_msb+1 == (signed)net->vector_width()) { + concat_count -= 1; + concat->set(concat_count, net); + } else { + NetExpr*ex = new NetEConst(verinum(sb_lsb)); + ex->set_line(*this); + NetESelect*ss = new NetESelect(net, ex, 1+sb_msb-sb_lsb); + ss->set_line(*this); + concat_count -= 1; + concat->set(concat_count, ss); + } + if (top) { + concat_count -= 1; + concat->set(concat_count, top); + } + ivl_assert(*this, concat_count==0); + + return concat; } /* @@ -1618,8 +1660,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, /* The bit select is out of range of the vector. This is legal, but returns a constant 1'bx value. */ - verinum x (verinum::Vx); - NetEConst*tmp = new NetEConst(x); + NetEConst*tmp = make_const_x(1); tmp->set_line(*this); cerr << get_fileline() << ": warning: Bit select [" diff --git a/netmisc.cc b/netmisc.cc index ac69d6885..39787d621 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -123,6 +123,13 @@ NetExpr* make_sub_expr(long val, NetExpr*expr) return res; } +NetEConst* make_const_x(unsigned long wid) +{ + verinum xxx (verinum::Vx, wid); + NetEConst*resx = new NetEConst(xxx); + return resx; +} + NetExpr* condition_reduce(NetExpr*expr) { if (expr->expr_width() == 1) diff --git a/netmisc.h b/netmisc.h index 439e86422..e82c3ef20 100644 --- a/netmisc.h +++ b/netmisc.h @@ -102,6 +102,11 @@ extern NetNet*add_to_net(Design*des, NetNet*sig, long val); extern NetExpr*make_add_expr(NetExpr*expr, long val); extern NetExpr*make_sub_expr(long val, NetExpr*expr); +/* + * Make a NetEConst object that contains only X bits. + */ +extern NetEConst*make_const_x(unsigned long wid); + /* * In some cases the lval is accessible as a pointer to the head of * a list of NetAssign_ objects. This function returns the width of