diff --git a/ivtest/ivltests/assign_op_oob.v b/ivtest/ivltests/assign_op_oob.v new file mode 100644 index 000000000..14897d930 --- /dev/null +++ b/ivtest/ivltests/assign_op_oob.v @@ -0,0 +1,44 @@ +// Check that the assignment operator is supported for out-of-bounds indices. +// The write should be skipped, but side effects of the right-hand side +// expression should still get evaluated. + +module test; + + // Check that wider than 32 works + logic [39:0] a[1:0]; + integer i; + logic [39:0] j = 0; + + function logic [39:0] f; + j++; + return j; + endfunction + + initial begin + a[0] = 23; + a[1] = 42; + + // Immediate out-of-bounds indices + a[-1] += f(); + a[2] += f(); + a['hx] += f(); + + // Variable out-of-bounds indices + i = -1; + a[i] += f(); + i = 2; + a[i] += f(); + i = 'hx; + a[i] += f(); + + // Check that the in-bounds elements do not get affected by out-of-bounds + // updates. Check that the left-hand side of the operator assignment gets + // evaluated. + if (a[0] == 23 && a[1] == 42 && j == 6) begin + $display("PASSED"); + end else begin + $display("FAILED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 6c3afca56..bcc4f0047 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -99,6 +99,7 @@ array_packed normal,-g2005-sv ivltests assign_op_after_cmp1 normal,-g2009 ivltests assign_op_after_cmp2 normal,-g2009 ivltests assign_op_concat normal,-g2009 ivltests +assign_op_oob normal,-g2009 ivltests assign_op_type normal,-g2009 ivltests bitp1 normal,-g2005-sv ivltests bits normal,-g2005-sv ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index bde6fa422..5886acce3 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -792,6 +792,7 @@ writemem-invalid RE ivltests gold=writemem-invalid-vlog95.gold # For Verilog 95 signed is supported as an option (-pallowsigned=1). array6 normal,-pallowsigned=1 ivltests +assign_op_oob normal,-g2009,-pallowsigned=1 ivltests assign_op_type normal,-g2009,-pallowsigned=1 ivltests bitp1 normal,-g2009,-pallowsigned=1 ivltests bits normal,-g2009,-pallowsigned=1 ivltests diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index e240fd619..123b2d405 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -21,6 +21,7 @@ # include # include # include +# include /* * These functions handle the blocking assignment. Use the %set @@ -101,8 +102,10 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice it to select the word, and pay no further heed to the expression itself. */ if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) { - assert(! number_is_unknown(word_ix)); - use_word = get_number_immediate(word_ix); + if (number_is_unknown(word_ix)) + use_word = ULONG_MAX; // The largest valid index is ULONG_MAX - 1 + else + use_word = get_number_immediate(word_ix); word_ix = 0; } @@ -164,8 +167,12 @@ static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%load/vec4a v%p, 3;\n", sig); } else { - assert(wid <= 32); - fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, %u;\n", wid); + if (wid <= 32) { + fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, %u;\n", wid); + } else { + fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, 32;\n"); + fprintf(vvp_out, " %%pad/s %u;\n", wid); + } } } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) { @@ -321,6 +328,7 @@ static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, clr_word(word_idx); } else { fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word); + fprintf(vvp_out," %%pop/vec4 1;\n"); } break;