From 925f5fb608b12ad0c29cc38b8f870e3677bb276b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 4 Jun 2023 15:58:26 -0700 Subject: [PATCH 1/2] Fix incorrect assert for partial oob write to function return value Partial out-of-bounds write to a function's return value will trigger an assert, even though the operation is valid. The assert checks that the truncated value has the expected width, but instead it should check that the non-truncated value has the expected with. Move the assert before the truncation to fix this. Signed-off-by: Lars-Peter Clausen --- vvp/vthread.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 2b35315b05..397bc7ba94 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -5453,6 +5453,7 @@ bool of_RET_VEC4(vthread_t thr, vvp_code_t cp) vthread_t fun_thr = get_func(thr); assert(index < get_max(fun_thr, val)); + assert(val.size() == wid); unsigned depth = get_depth(fun_thr, index, val); int64_t off = off_index ? thr->words[off_index].w_int : 0; @@ -5472,7 +5473,6 @@ bool of_RET_VEC4(vthread_t thr, vvp_code_t cp) fun_thr->parent->poke_vec4(depth, val); } else { vvp_vector4_t tmp_dst = fun_thr->parent->peek_vec4(depth); - assert(val.size() == wid); tmp_dst.set_vec(off, val); fun_thr->parent->poke_vec4(depth, tmp_dst); } From 4ab59dd55e28a3084ed9a54ddd9ecdfba3967a6a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 4 Jun 2023 15:57:38 -0700 Subject: [PATCH 2/2] Add regression tests for oob write to function return value Check that partial and fully out-of-bound writes to a function's return value are handled correctly. Check this for both 4-state and 2-state vectors. Signed-off-by: Lars-Peter Clausen --- ivtest/ivltests/pv_wr_fn_vec2.v | 99 ++++++++++++++++++++++++++ ivtest/ivltests/pv_wr_fn_vec4.v | 106 ++++++++++++++++++++++++++++ ivtest/regress-vvp.list | 2 + ivtest/vvp_tests/pv_wr_fn_vec2.json | 5 ++ ivtest/vvp_tests/pv_wr_fn_vec4.json | 4 ++ 5 files changed, 216 insertions(+) create mode 100644 ivtest/ivltests/pv_wr_fn_vec2.v create mode 100644 ivtest/ivltests/pv_wr_fn_vec4.v create mode 100644 ivtest/vvp_tests/pv_wr_fn_vec2.json create mode 100644 ivtest/vvp_tests/pv_wr_fn_vec4.json diff --git a/ivtest/ivltests/pv_wr_fn_vec2.v b/ivtest/ivltests/pv_wr_fn_vec2.v new file mode 100644 index 0000000000..04bedb284c --- /dev/null +++ b/ivtest/ivltests/pv_wr_fn_vec2.v @@ -0,0 +1,99 @@ +// Check that blocking partial writes to a 2-state vector function return value +// are correctly handled. + +module test; + + reg failed = 1'b0; + + `define check(val, exp) \ + if (exp !== val) begin \ + $display("FAILED. Got %b, expected %b.", val, exp); \ + failed = 1'b1; \ + end + + function bit [3:0] f; + integer i; + + // Immediate index + + // Within bounds + f = 'h0; + f[2:1] = 2'b10; + `check(f, 4'b0100) + + // Partially oob at high and low side + f = 'h0; + f[4:-1] = 6'b101010; + `check(f, 4'b0101) + // Partially oob at low side + f = 'h0; + f[0:-1] = 2'b10; + `check(f, 4'b0001) + // Partially oob at high side + f = 'h0; + f[4:3] = 2'b01; + `check(f, 4'b1000) + // Fully oob at low side + f = 'h0; + f[-1:-2] = 2'b11; + `check(f, 4'b0000) + // Fully oob at high side + f = 'h0; + f[6:5] = 2'b11; + `check(f, 4'b0000) + + // Variable index + + // Within bounds + i = 1; + f = 'h0; + f[i+:2] = 2'b10; + `check(f, 4'b0100) + + // Partially oob at high and low side + i = -1; + f = 'h0; + f[i+:6] = 6'b101010; + `check(f, 4'b0101) + + // Partially oob at low side + i = -1; + f = 'h0; + f[i+:2] = 2'b10; + `check(f, 4'b0001) + + // Partially oob at high side + i = 3; + f = 'h0; + f[i+:2] = 2'b01; + `check(f, 4'b1000) + + // Fully oob at low side + i = -2; + f = 'h0; + f[i+:2] = 2'b11; + `check(f, 4'b0000) + + // Fully oob at high side + i = 5; + f = 'h0; + f[i+:2] = 2'b11; + `check(f, 4'b0000) + + // Undefined index + i = 'hx; + f = 'h0; + f[i+:2] = 2'b11; + `check(f, 4'b0000) + endfunction + + initial begin + bit [3:0] x; + x = f(); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/ivltests/pv_wr_fn_vec4.v b/ivtest/ivltests/pv_wr_fn_vec4.v new file mode 100644 index 0000000000..88fddd4f0c --- /dev/null +++ b/ivtest/ivltests/pv_wr_fn_vec4.v @@ -0,0 +1,106 @@ +// Check that blocking partial writes to a 4-state vector function return value +// are correctly handled. + +module test; + + reg failed = 1'b0; + + `define check(val, exp) \ + if (exp !== val) begin \ + $display("FAILED. Got %b, expected %b.", val, exp); \ + failed = 1'b1; \ + end + + integer i; + + function reg [3:0] f(input reg unused); + begin + // Immediate index + + // Within bounds + f = 'hx; + f[2:1] = 2'b10; + `check(f, 4'bx10x) + + // Partially oob at high and low side + f = 'hx; + f[4:-1] = 6'b101010; + `check(f, 4'b0101) + + // Partially oob at low side + f = 'hx; + f[0:-1] = 2'b10; + `check(f, 4'bxxx1) + + // Partially oob at high side + f = 'hx; + f[4:3] = 2'b01; + `check(f, 4'b1xxx) + + // Fully oob at low side + f = 'hx; + f[-1:-2] = 2'b11; + `check(f, 4'bxxxx) + + // Fully oob at high side + f = 'hx; + f[6:5] = 2'b11; + `check(f, 4'bxxxx) + + // Variable index + + // Within bounds + i = 1; + f = 'hx; + f[i+:2] = 2'b10; + `check(f, 4'bx10x) + + // Partially oob at high and low side + i = -1; + f = 'hx; + f[i+:6] = 6'b101010; + `check(f, 4'b0101) + + // Partially oob at low side + i = -1; + f = 'hx; + f[i+:2] = 2'b10; + `check(f, 4'bxxx1) + + // Partially oob at high side + i = 3; + f = 'hx; + f[i+:2] = 2'b01; + `check(f, 4'b1xxx) + + // Fully oob at low side + i = -2; + f = 'hx; + f[i+:2] = 2'b11; + `check(f, 4'bxxxx) + + // Fully oob at high side + i = 5; + f = 'hx; + f[i+:2] = 2'b11; + `check(f, 4'bxxxx) + + // Undefined index + i = 'hx; + f = 'hx; + f[i+:2] = 2'b11; + `check(f, 4'bxxxx) + end + endfunction + + reg [3:0] x; + + initial begin + x = f(1'b0); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index beecf80b21..36e24c3871 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -31,6 +31,8 @@ pr1388974 vvp_tests/pr1388974.json pr1388974-vlog95 vvp_tests/pr1388974-vlog95.json pr903 vvp_tests/pr903.json pr903-vlog95 vvp_tests/pr903-vlog95.json +pv_wr_fn_vec2 vvp_tests/pv_wr_fn_vec2.json +pv_wr_fn_vec4 vvp_tests/pv_wr_fn_vec4.json struct_packed_write_read vvp_tests/struct_packed_write_read.json struct_packed_write_read2 vvp_tests/struct_packed_write_read2.json sv_array_cassign6 vvp_tests/sv_array_cassign6.json diff --git a/ivtest/vvp_tests/pv_wr_fn_vec2.json b/ivtest/vvp_tests/pv_wr_fn_vec2.json new file mode 100644 index 0000000000..577fe52a29 --- /dev/null +++ b/ivtest/vvp_tests/pv_wr_fn_vec2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "pv_wr_fn_vec2.v", + "iverilog-args" : [ "-g2009" ] +} diff --git a/ivtest/vvp_tests/pv_wr_fn_vec4.json b/ivtest/vvp_tests/pv_wr_fn_vec4.json new file mode 100644 index 0000000000..7e787d84df --- /dev/null +++ b/ivtest/vvp_tests/pv_wr_fn_vec4.json @@ -0,0 +1,4 @@ +{ + "type" : "normal", + "source" : "pv_wr_fn_vec4.v" +}