verilator/test_regress/t/t_assign_slice_overflow.v
2021-11-13 10:46:25 -05:00

180 lines
7.4 KiB
Systemverilog

// DESCRIPTION: Test that slice assignment overflows are handled correctly,
// i.e. that if you assign to a slice such that some of the bits you assign to
// do not actually exist, that those bits get correctly discarded.
// Issue #2803 existed in a number number of different codepaths in
// verilated.h and V3Expand.cpp. This test should cover all of these cases
// when run both with and without the -Ox flag to verilator.
// - Select offset constant, insert IData into CData
// - Select offset constant, insert IData into SData
// - Select offset constant, insert IData into IData
// - Select offset constant, insert QData into QData
// - Select offset constant, insert IData into WData within a word
// - Select offset constant, insert IData into WData crossing a word boundary
// - Select offset constant, insert IData into WData whole word insertion
// - Select offset constant, insert QData into WData
// - Select offset constant, insert WData into WData, several whole words
// - Select offset constant, insert WData into WData, starting at word-offset
// - Select offset constant, insert WData into WData, all other cases
// - Select offset is non-constant, destination is wide, bit-select width == 1
// - Select offset is non-constant, destination is wide, bit-select width != 1
// - Select offset is non-constant, destination is narrow
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2021 by David Turner.
// SPDX-License-Identifier: CC0-1.0
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc = 0;
// Non-constant offsets
reg varoffset1;
reg [6:0] varoffset2;
reg [6:0] varoffset3;
// Destinations for variable-offset assignments
reg [69:0] dstwide1;
reg [69:0] dstwide2;
reg [1:0] dstnarrow;
// Constant offsets
reg [6:0] constoffset;
// Destinations for constant-offset assignments
reg [2:0] dst_cdata;
reg [11:0] dst_sdata;
reg [29:0] dst_idata;
reg [59:0] dst_qdata;
reg [69:0] dst_wdata1; // assign idata within word
reg [69:0] dst_wdata2; // assign idata crossing word boundary
reg [69:0] dst_wdata3; // assign idata corresponding to whole word
reg [69:0] dst_wdata4; // assign qdata
reg [69:0] dst_wdata5; // assign wdata corresponding to several whole words
reg [69:0] dst_wdata6; // assign wdata starting at word-offset
reg [69:0] dst_wdata7; // assign wdata unaligned
always @(*) begin
// Non-constant select offset, destination narrow
dstnarrow = 2'd0;
dstnarrow[varoffset1 +: 2'd2] = 2'd2;
// Non-constant select offset, destination wide, width == 1
dstwide1 = 70'd0;
dstwide1[varoffset2 +: 1'd1] = 1'd1;
// Non-constant select offset, destination wide, width != 1
dstwide2 = 70'd0;
dstwide2[varoffset3 +: 2'd2] = 2'd2;
// Constant offset, IData into CData
constoffset = 7'd2;
dst_cdata = 3'd0;
dst_cdata[constoffset[0 +: 2] +: 3'd3] = 3'd6;
// Constant offset, IData into SData
constoffset = 7'd11;
dst_sdata = 12'd0;
dst_sdata[constoffset[0 +: 4] +: 2'd2] = 2'd2;
// Constant offset, IData into IData
constoffset = 7'd29;
dst_idata = 30'd0;
dst_idata[constoffset[0 +: 5] +: 2'd2] = 2'd2;
// Constant offset, QData into QData
constoffset = 7'd59;
dst_qdata = 60'd0;
dst_qdata[constoffset[0 +: 6] +: 2'd2] = 2'd2;
// Constant offset, IData into WData within word
constoffset = 7'd69;
dst_wdata1 = 70'd0;
dst_wdata1[constoffset +: 2'd2] = 2'd2;
// Constant offset, IData into WData crossing word boundary
constoffset = 7'd61;
dst_wdata2 = 70'd0;
dst_wdata2[constoffset +: 4'd10] = 10'd1 << 4'd9;
// Constant offset, IData into WData replacing a whole word
constoffset = 7'd64;
dst_wdata3 = 70'd0;
dst_wdata3[constoffset +: 6'd32] = 32'd1 << 3'd6;
// Constant offset, QData into WData
constoffset = 7'd31;
dst_wdata4 = 70'd0;
dst_wdata4[constoffset +: 7'd40] = 40'd1 << 7'd39;
// Constant offset, WData into WData replacing whole words
constoffset = 7'd32;
dst_wdata5 = 70'd0;
dst_wdata5[constoffset +: 7'd64] = 64'd1 << 7'd38;
// Constant offset, WData into WData offset word aligned
constoffset = 7'd32;
dst_wdata6 = 70'd0;
dst_wdata6[constoffset +: 7'd40] = 40'd1 << 7'd38;
// Constant offset, WData into WData unaligned
constoffset = 7'd1;
dst_wdata7 = 70'd0;
dst_wdata7[constoffset +: 7'd70] = 70'd1 << 7'd69;
end
// Test loop
always @ (posedge clk) begin
// State machine to avoid verilator constant-folding offset
if (cyc == 0) begin
// Initialisation
varoffset1 <= 1'd0;
varoffset2 <= 7'd0;
varoffset3 <= 7'd0;
end else if (cyc == 1) begin
// Variable offsets set here to avoid verilator constant folding
varoffset1 <= 1'd1;
varoffset2 <= 7'd70;
varoffset3 <= 7'd69;
end else if (cyc == 2) begin
// Check all destinations are 0
$write("dstwide1 = %23d, downshifted = %23d\n", dstwide1, dstwide1 >> 1);
$write("dstwide2 = %23d, downshifted = %23d\n", dstwide2, dstwide2 >> 1);
$write("dstnarrow = %23d, downshifted = %23d\n", dstnarrow, dstnarrow >> 1);
$write("dst_cdata = %23d, downshifted = %23d\n", dst_cdata, dst_cdata >> 1);
$write("dst_sdata = %23d, downshifted = %23d\n", dst_sdata, dst_sdata >> 1);
$write("dst_idata = %23d, downshifted = %23d\n", dst_idata, dst_idata >> 1);
$write("dst_qdata = %23d, downshifted = %23d\n", dst_qdata, dst_qdata >> 1);
$write("dst_wdata1 = %23d, downshifted = %23d\n", dst_wdata1, dst_wdata1 >> 1);
$write("dst_wdata2 = %23d, downshifted = %23d\n", dst_wdata2, dst_wdata2 >> 1);
$write("dst_wdata3 = %23d, downshifted = %23d\n", dst_wdata3, dst_wdata3 >> 1);
$write("dst_wdata4 = %23d, downshifted = %23d\n", dst_wdata4, dst_wdata4 >> 1);
$write("dst_wdata5 = %23d, downshifted = %23d\n", dst_wdata5, dst_wdata5 >> 1);
$write("dst_wdata6 = %23d, downshifted = %23d\n", dst_wdata6, dst_wdata6 >> 1);
$write("dst_wdata7 = %23d, downshifted = %23d\n", dst_wdata7, dst_wdata7 >> 1);
if (dstwide1 !== 70'd0 || (dstwide1 >> 1) !== 70'd0) $stop;
if (dstwide2 !== 70'd0 || (dstwide2 >> 1) !== 70'd0) $stop;
if (dstnarrow !== 2'd0 || (dstnarrow >> 1) !== 2'd0) $stop;
if (dst_cdata !== 3'd0 || (dst_cdata >> 1) !== 3'd0) $stop;
if (dst_sdata !== 12'd0 || (dst_sdata >> 1) !== 12'd0) $stop;
if (dst_idata !== 30'd0 || (dst_idata >> 1) !== 30'd0) $stop;
if (dst_qdata !== 60'd0 || (dst_qdata >> 1) !== 60'd0) $stop;
if (dst_wdata1 !== 70'd0 || (dst_wdata1 >> 1) !== 70'd0) $stop;
if (dst_wdata2 !== 70'd0 || (dst_wdata2 >> 1) !== 70'd0) $stop;
if (dst_wdata3 !== 70'd0 || (dst_wdata3 >> 1) !== 70'd0) $stop;
if (dst_wdata4 !== 70'd0 || (dst_wdata4 >> 1) !== 70'd0) $stop;
if (dst_wdata5 !== 70'd0 || (dst_wdata5 >> 1) !== 70'd0) $stop;
if (dst_wdata6 !== 70'd0 || (dst_wdata6 >> 1) !== 70'd0) $stop;
if (dst_wdata7 !== 70'd0 || (dst_wdata7 >> 1) !== 70'd0) $stop;
end else begin
$write("*-* All Finished *-*\n");
$finish;
end
cyc <= cyc + 1;
end
endmodule