diff --git a/elab_expr.cc b/elab_expr.cc index d6372d5f2..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. @@ -1580,61 +1582,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.