From 392b162024df41f3f5e52387edc3b12c5d1bf4d1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 12 Jun 2008 21:41:11 -0700 Subject: [PATCH 1/2] 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. --- elab_expr.cc | 59 +++------------------------------------------ tgt-vvp/eval_expr.c | 42 ++++++++++++-------------------- tgt-vvp/vvp_priv.h | 2 +- vvp/opcodes.txt | 9 +++++-- 4 files changed, 28 insertions(+), 84 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index d6372d5f2..82399cb1c 100644 --- a/elab_expr.cc +++ b/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; } /* diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index b18761c98..2ce6e15bc 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -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); diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index cb4406bf3..4a5a29d31 100644 --- a/tgt-vvp/vvp_priv.h +++ b/tgt-vvp/vvp_priv.h @@ -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 diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 3a8935a94..a52f6a5a6 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -369,7 +369,7 @@ This instruction loads an immediate value into the addressed index register. The index register holds numeric values, so the 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 , @@ -462,7 +462,12 @@ select a part from a vector functor at . The part is pulled from the indexed bit of the addressed functor and loaded into the destination thread bit. The 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 is added to index register 1, to provide a basic auto-increment behavior. From a74f2827b20833675a303f3aa6790376f9df243b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 12 Jun 2008 21:56:46 -0700 Subject: [PATCH 2/2] Part select of signals is always unsigned. Part select of an entire signal returns just the NetESignal itself, but since part selects are always unsigned, even if the selected signal is signed, we need to cast the NetESignal to unsigned first. --- elab_expr.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 82399cb1c..2939b91d9 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1567,9 +1567,11 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, // If the part select covers exactly the entire // vector, then do not bother with it. Return the - // signal itself. - if (sb_lsb == 0 && wid == net->vector_width()) + // signal itself, casting to unsigned if necessary. + if (sb_lsb == 0 && wid == net->vector_width()) { + net->cast_signed(false); return net; + } // If the part select covers NONE of the vector, then return a // constant X.