|
| 1 | +[tasks] |
| 2 | +bmc |
| 3 | +prove |
| 4 | +prove_f: prove |
| 5 | +prove_v: prove_f prove |
| 6 | +bmc_b2a: bmc btor_aig |
| 7 | +prove_b2a: prove btor_aig |
| 8 | +prove_f_b2a: prove_f prove btor_aig |
| 9 | +prove_v_b2a: prove_v prove_f prove btor_aig |
| 10 | + |
| 11 | +[options] |
| 12 | +prove: |
| 13 | +mode prove |
| 14 | +-- |
| 15 | + |
| 16 | +bmc: |
| 17 | +mode bmc |
| 18 | +-- |
| 19 | + |
| 20 | +prove_f: expect fail |
| 21 | +prove_v: vcd_sim on |
| 22 | +btor_aig: btor_aig on |
| 23 | + |
| 24 | +[engines] |
| 25 | +bmc: abc bmc3 |
| 26 | +prove: abc --keep-going pdr |
| 27 | + |
| 28 | +[script] |
| 29 | +prove_f: read -define NO_FULL_SKIP=1 |
| 30 | +read -formal fifo.sv |
| 31 | +prep -top fifo |
| 32 | + |
| 33 | +[file fifo.sv] |
| 34 | +// address generator/counter |
| 35 | +module addr_gen |
| 36 | +#( parameter MAX_DATA=16 |
| 37 | +) ( input en, clk, rst, |
| 38 | + output reg [3:0] addr |
| 39 | +); |
| 40 | + initial addr <= 0; |
| 41 | + |
| 42 | + // async reset |
| 43 | + // increment address when enabled |
| 44 | + always @(posedge clk or posedge rst) |
| 45 | + if (rst) |
| 46 | + addr <= 0; |
| 47 | + else if (en) begin |
| 48 | + if (addr == MAX_DATA-1) |
| 49 | + addr <= 0; |
| 50 | + else |
| 51 | + addr <= addr + 1; |
| 52 | + end |
| 53 | +endmodule |
| 54 | + |
| 55 | +// Define our top level fifo entity |
| 56 | +module fifo |
| 57 | +#( parameter MAX_DATA=16 |
| 58 | +) ( input wen, ren, clk, rst, |
| 59 | + input [7:0] wdata, |
| 60 | + output [7:0] rdata, |
| 61 | + output [4:0] count, |
| 62 | + output full, empty |
| 63 | +); |
| 64 | + wire wskip, rskip; |
| 65 | + reg [4:0] data_count; |
| 66 | + |
| 67 | + // fifo storage |
| 68 | + // async read, sync write |
| 69 | + wire [3:0] waddr, raddr; |
| 70 | + reg [7:0] data [MAX_DATA-1:0]; |
| 71 | + always @(posedge clk) |
| 72 | + if (wen) |
| 73 | + data[waddr] <= wdata; |
| 74 | + assign rdata = data[raddr]; |
| 75 | + // end storage |
| 76 | + |
| 77 | + // addr_gen for both write and read addresses |
| 78 | + addr_gen #(.MAX_DATA(MAX_DATA)) |
| 79 | + fifo_writer ( |
| 80 | + .en (wen || wskip), |
| 81 | + .clk (clk ), |
| 82 | + .rst (rst), |
| 83 | + .addr (waddr) |
| 84 | + ); |
| 85 | + |
| 86 | + addr_gen #(.MAX_DATA(MAX_DATA)) |
| 87 | + fifo_reader ( |
| 88 | + .en (ren || rskip), |
| 89 | + .clk (clk ), |
| 90 | + .rst (rst), |
| 91 | + .addr (raddr) |
| 92 | + ); |
| 93 | + |
| 94 | + // status signals |
| 95 | + initial data_count <= 0; |
| 96 | + |
| 97 | + always @(posedge clk or posedge rst) begin |
| 98 | + if (rst) |
| 99 | + data_count <= 0; |
| 100 | + else if (wen && !ren && data_count < MAX_DATA) |
| 101 | + data_count <= data_count + 1; |
| 102 | + else if (ren && !wen && data_count > 0) |
| 103 | + data_count <= data_count - 1; |
| 104 | + end |
| 105 | + |
| 106 | + assign full = data_count == MAX_DATA; |
| 107 | + assign empty = (data_count == 0) && ~rst; |
| 108 | + assign count = data_count; |
| 109 | + |
| 110 | + // overflow protection |
| 111 | +`ifndef NO_FULL_SKIP |
| 112 | + // write while full => overwrite oldest data, move read pointer |
| 113 | + assign rskip = wen && !ren && data_count >= MAX_DATA; |
| 114 | + // read while empty => read invalid data, keep write pointer in sync |
| 115 | + assign wskip = ren && !wen && data_count == 0; |
| 116 | +`else |
| 117 | + assign rskip = 0; |
| 118 | + assign wskip = 0; |
| 119 | +`endif // NO_FULL_SKIP |
| 120 | + |
| 121 | +`ifdef FORMAL |
| 122 | + // observers |
| 123 | + wire [4:0] addr_diff; |
| 124 | + assign addr_diff = waddr >= raddr |
| 125 | + ? waddr - raddr |
| 126 | + : waddr + MAX_DATA - raddr; |
| 127 | + |
| 128 | + // tests |
| 129 | + always @(posedge clk) begin |
| 130 | + if (~rst) begin |
| 131 | + // waddr and raddr can only be non zero if reset is low |
| 132 | + w_nreset: cover (waddr || raddr); |
| 133 | + |
| 134 | + // count never more than max |
| 135 | + a_oflow: assert (count <= MAX_DATA); |
| 136 | + a_oflow2: assert (waddr < MAX_DATA); |
| 137 | + |
| 138 | + // count should be equal to the difference between writer and reader address |
| 139 | + a_count_diff: assert (count == addr_diff |
| 140 | + || count == MAX_DATA && addr_diff == 0); |
| 141 | + |
| 142 | + // count should only be able to increase or decrease by 1 |
| 143 | + a_counts: assert (count == 0 |
| 144 | + || count == $past(count) |
| 145 | + || count == $past(count) + 1 |
| 146 | + || count == $past(count) - 1); |
| 147 | + |
| 148 | + // read/write addresses can only increase (or stay the same) |
| 149 | + a_raddr: assert (raddr == 0 |
| 150 | + || raddr == $past(raddr) |
| 151 | + || raddr == $past(raddr + 1)); |
| 152 | + a_waddr: assert (waddr == 0 |
| 153 | + || waddr == $past(waddr) |
| 154 | + || waddr == $past(waddr + 1)); |
| 155 | + |
| 156 | + // full and empty work as expected |
| 157 | + a_full: assert (!full || count == MAX_DATA); |
| 158 | + w_full: cover (wen && !ren && count == MAX_DATA-1); |
| 159 | + a_empty: assert (!empty || count == 0); |
| 160 | + w_empty: cover (ren && !wen && count == 1); |
| 161 | + |
| 162 | + // reading/writing non zero values |
| 163 | + w_nzero_write: cover (wen && wdata); |
| 164 | + w_nzero_read: cover (ren && rdata); |
| 165 | + end else begin |
| 166 | + // waddr and raddr are zero while reset is high |
| 167 | + a_reset: assert (!waddr && !raddr); |
| 168 | + w_reset: cover (rst); |
| 169 | + |
| 170 | + // outputs are zero while reset is high |
| 171 | + a_zero_out: assert (!empty && !full && !count); |
| 172 | + end |
| 173 | + end |
| 174 | + |
| 175 | + // if we have verific we can also do the following additional tests |
| 176 | + // read/write enables enable |
| 177 | + ap_raddr2: assert property (@(posedge clk) disable iff (rst) ren |=> $changed(raddr)); |
| 178 | + ap_waddr2: assert property (@(posedge clk) disable iff (rst) wen |=> $changed(waddr)); |
| 179 | + |
| 180 | + // read/write needs enable UNLESS full/empty |
| 181 | + ap_raddr3: assert property (@(posedge clk) disable iff (rst) !ren && !full |=> $stable(raddr)); |
| 182 | + ap_waddr3: assert property (@(posedge clk) disable iff (rst) !wen && !empty |=> $stable(waddr)); |
| 183 | + |
| 184 | + // use block formatting for w_underfill so it's easier to describe in docs |
| 185 | + // and is more readily comparable with the non SVA implementation |
| 186 | + property write_skip; |
| 187 | + @(posedge clk) disable iff (rst) |
| 188 | + !wen |=> $changed(waddr); |
| 189 | + endproperty |
| 190 | + w_underfill: cover property (write_skip); |
| 191 | + |
| 192 | + // look for an overfill where the value in memory changes |
| 193 | + // the change in data makes certain that the value is overriden |
| 194 | + let d_change = (wdata != rdata); |
| 195 | + property read_skip; |
| 196 | + @(posedge clk) disable iff (rst) |
| 197 | + !ren && d_change |=> $changed(raddr); |
| 198 | + endproperty |
| 199 | + w_overfill: cover property (read_skip); |
| 200 | + |
| 201 | +`endif // FORMAL |
| 202 | + |
| 203 | +endmodule |
| 204 | + |
0 commit comments