File: t_math_insert_bound.v

package info (click to toggle)
verilator 5.038-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 162,552 kB
  • sloc: cpp: 139,204; python: 20,931; ansic: 10,222; yacc: 6,000; lex: 1,925; makefile: 1,260; sh: 494; perl: 282; fortran: 22
file content (100 lines) | stat: -rw-r--r-- 2,860 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// 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