Allow canonical part select of net vectors to be larger then the vector
The part select of a vector is converted by the compiler during elaboration to a 0-based canonical address. But since it is legal to address bits below the LSB, the canonical address can be negative. So make the part select base for selecting from signals work with signed arithmetic and make the code generator generate negative indices when needed.
This commit is contained in:
parent
4af4c8cca9
commit
392b162024
59
elab_expr.cc
59
elab_expr.cc
|
|
@ -1580,61 +1580,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope,
|
|||
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;
|
||||
NetExpr*ex = new NetEConst(verinum(sb_lsb));
|
||||
NetESelect*ss = new NetESelect(net, ex, wid);
|
||||
ss->set_line(*this);
|
||||
return ss;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -75,9 +75,9 @@ int number_is_immediate(ivl_expr_t ex, unsigned lim_wid)
|
|||
return 1;
|
||||
}
|
||||
|
||||
unsigned long get_number_immediate(ivl_expr_t ex)
|
||||
long get_number_immediate(ivl_expr_t ex)
|
||||
{
|
||||
unsigned long imm = 0;
|
||||
long imm = 0;
|
||||
unsigned idx;
|
||||
|
||||
switch (ivl_expr_type(ex)) {
|
||||
|
|
@ -93,11 +93,13 @@ unsigned long get_number_immediate(ivl_expr_t ex)
|
|||
break;
|
||||
case '1':
|
||||
assert(idx < 8*sizeof(imm));
|
||||
imm |= 1UL << idx;
|
||||
imm |= 1L << idx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
if (ivl_expr_signed(ex) && bits[nbits-1]=='1' && nbits < 8*sizeof(imm))
|
||||
imm |= -1L << nbits;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -112,30 +114,18 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
|||
{
|
||||
switch (ivl_expr_type(expr)) {
|
||||
|
||||
case IVL_EX_NUMBER: {
|
||||
unsigned value = 0;
|
||||
unsigned idx, nbits = ivl_expr_width(expr);
|
||||
const char*bits = ivl_expr_bits(expr);
|
||||
|
||||
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) {
|
||||
|
||||
case '0':
|
||||
break;
|
||||
case '1':
|
||||
assert(idx < (8*sizeof value));
|
||||
value |= 1 << idx;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%ix/load %u, %u;\n", ix, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case IVL_EX_NUMBER:
|
||||
case IVL_EX_ULONG:
|
||||
fprintf(vvp_out, " %%ix/load %u, %lu;\n", ix, ivl_expr_uvalue(expr));
|
||||
break;
|
||||
{
|
||||
long imm = get_number_immediate(expr);
|
||||
if (imm >= 0) {
|
||||
fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm);
|
||||
fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_EX_SIGNAL: {
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ extern unsigned allocate_vector_exp(ivl_expr_t exp, unsigned wid,
|
|||
|
||||
extern int number_is_unknown(ivl_expr_t ex);
|
||||
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid);
|
||||
extern unsigned long get_number_immediate(ivl_expr_t ex);
|
||||
extern long get_number_immediate(ivl_expr_t ex);
|
||||
|
||||
/*
|
||||
* draw_eval_real evaluates real value expressions. The return code
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ This instruction loads an immediate value into the addressed index
|
|||
register. The index register holds numeric values, so the <value> is a
|
||||
number. The idx value selects the index register. This is different
|
||||
from %ix/get, which loads the index register from a value in the
|
||||
thread bit vector.
|
||||
thread bit vector. The value is a signed decimal value >= 0.
|
||||
|
||||
|
||||
* %ix/add <idx>, <value>
|
||||
|
|
@ -462,7 +462,12 @@ select a part from a vector functor at <functor-label>. The
|
|||
part is pulled from the indexed bit of the addressed functor and loaded
|
||||
into the destination thread bit. The <wid> is the width of the
|
||||
part. If any bit of the desired value is outside the vector, then that
|
||||
bit is set to X. The index register 1 is interpreted as a signed value.
|
||||
bit is set to X.
|
||||
|
||||
The index register 1 is interpreted as a signed value. Even though the
|
||||
address is cannonical (from 0 to the width of the signal) the value in
|
||||
index register 1 may be <0 or >=wid. The load instruction handles
|
||||
filling in the out-of-bounds bits with x.
|
||||
|
||||
When the operation is done, the <wid> is added to index register 1, to
|
||||
provide a basic auto-increment behavior.
|
||||
|
|
|
|||
Loading…
Reference in New Issue