verilator/test_regress/t/t_math_insert_bound.v

101 lines
2.8 KiB
Systemverilog
Raw Normal View History

// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2024 by Paul Swirhun.
// SPDX-License-Identifier: CC0-1.0
// Demonstrates the bug in https://github.com/verilator/verilator/issues/4850
//
// Specifically, _vl_insert_WI() writes to lword and hword when lword != hword
// may be unsafe, because (for example), lword was the highest valid place to
// perform a write and hword is out-of-bounds (and will in fact clobber other
// state in the generated C++ struct!).
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc = 13;
// These need to be generated/consumed in this testbench so that
// they do not get pruned away when verilated
logic insert = '0;
logic [3:0] used, free;
logic [95:0] data;
always_ff @(posedge clk) begin
insert <= '1;
cyc <= cyc - 1;
`ifdef TEST_VERBOSE
$write("used [4'd%2d], free [4'd%2d], data = [96'h%012x]\n", used, free, data);
`endif
if (used + free != 12) begin
$write("used [4'd%2d] + free [4'd%2d] != 4'd12\n", used, free);
$stop();
end
if (used == 0) begin
$write("used [4'd%2d] was clobbered (should always be nonzero).\n", used);
$stop();
end
if (cyc == 0) begin
if (used == 12 && free == 0 && data == 96'hFF) begin
$write("*-* All Finished *-*\n");
$finish;
end else begin
$write("Test Failed! used/free/data had unexpected final value(s).\n");
$stop();
end
end
end
dut dut_i(
.clk(clk),
.insert(insert),
.used(used),
.free(free),
.data(data)
);
endmodule
module dut(
input logic clk,
input logic insert,
output logic [3:0] used,
output logic [3:0] free,
output logic [95:0] data
);
// This declaration order matters -- the fact that d_data is *before* d_used/d_free
// means that with the existing bug, writes to d_data that extend beyond its length
// will overwrite other fields in the state struct -- basically an "unsafe writes"
// problem because the existing code wrote beyond the end of the array d_data.
logic [11:0][7:0] d_data = '1, d_data_next;
logic [3:0] d_used = 4'd1, d_free = 4'd11, d_used_next;
assign used = d_used;
assign free = d_free;
assign data = d_data;
always_ff @(posedge clk) begin
d_data <= d_data_next;
d_used <= d_used_next;
d_free <= 12 - d_used_next;
end
always_comb begin
d_data_next = d_data;
d_used_next = d_used;
if ((insert == 1'b1) && (d_free >= {3'b0, insert})) begin
// This write to d_data would clobber d_used before the issue was fixed
d_data_next[d_used+:4] = 32'd0;
d_used_next += 4'd1;
end
end
endmodule