Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | ROMA: Formal verification of TileLink bus seems to be complete. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | formal |
Files: | files | file ages | folders |
SHA3-256: |
b014c7b07f6f536ae3c0756aa91c3c31 |
User & Date: | kc5tja 2018-08-30 04:57:22 |
Context
2018-08-30
| ||
18:11 | Per ZipCPU's suggestion, I didn't need the initial block if I qualified some of my assertions more thoroughly. check-in: d5debe2752 user: kc5tja tags: formal | |
04:57 | ROMA: Formal verification of TileLink bus seems to be complete. check-in: b014c7b07f user: kc5tja tags: formal | |
2018-08-29
| ||
18:44 | WIP ROMA: Qualify A-channel transaction by comparing opcode. Verify that o_d_valid should be negated for as long as we lack a read result. Remove reg qualifier from all signals we "assign" to. Generate o_a_ready based on state of bits_so_far. Passes bmc; fails to prove inductively. Cause is o_d_valid && i_d_ready true while not engaged in an actual transaction. Cannot figure out how to tell prover that this is an impossible condition. check-in: 2f8acc4498 user: kc5tja tags: formal | |
Changes
Changes to cores/roma/rtl/verilog/properties.vf.
1 2 3 4 5 | reg past_valid = 0; always @(posedge i_clk) past_valid <= 1; always #1 i_clk <= ~i_clk; | < < < < < | < > | > > > > | > > > > > > | > > > > > > | > | > > > | > > > | > > > | > > | > > > > > > > > > | | > > > > > | > | > > | > | | > > > > > > > > > > > | | 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 | reg past_valid = 0; always @(posedge i_clk) past_valid <= 1; always #1 i_clk <= ~i_clk; // After power-on, ROMA must be reset to put it into a known-good state. always @(posedge i_clk) if(!past_valid) begin assume(i_reset); assume(i_a_valid == 0); end always @(posedge i_clk) if($past(i_reset)) begin assert(state_waiting_for_get_request); assert(!state_waiting_for_flash); assert(!state_waiting_to_deliver_results); end // The ROMA core exists in one of three major states, which execute sequentially // and cyclicly: // // 1. Waiting for a GET operation on the A-channel. // 2. Waiting for flash ROM to respond with the requested data. // 3. Waiting for the master to retrieve its payload on D-channel. wire [2:0] states = { state_waiting_for_get_request, state_waiting_for_flash, state_waiting_to_deliver_results }; always @(posedge i_clk) if(past_valid && !i_reset) assert((states == 3'b001) || (states == 3'b010) || (states == 3'b100)); always @(posedge i_clk) if(past_valid && !$past(i_reset) && $fell(state_waiting_for_get_request)) assert(state_waiting_for_flash); always @(posedge i_clk) if(past_valid && !$past(i_reset) && $fell(state_waiting_for_flash)) assert(state_waiting_to_deliver_results); always @(posedge i_clk) if(past_valid && !$past(i_reset) && $fell(state_waiting_to_deliver_results)) assert(state_waiting_for_get_request); // Since we're expecting a GET operation only when we're waiting for one, // we let o_a_ready serve as a flag indicating that to the outside world. always @(*) assert(o_a_ready == state_waiting_for_get_request); // When we get a GET request on A-channel, we must change states. always @(posedge i_clk) if(past_valid && !$past(i_reset) && $past(o_a_ready) && $past(i_a_valid) && ($past(i_a_opcode) == `A_OPC_GET)) begin assert(!state_waiting_for_get_request); assert(state_waiting_for_flash); assert(!state_waiting_to_deliver_results); end // Since waiting for flash ROM to complete means waiting for the entire commnad // and address to be sent to the chip, and payload to come back from the chip, // which totals 96 bits, we keep track of how many bits have transpired with // bits_so_far, and we note that state_waiting_for_flash is asserted while this // counter hasn't expired yet. always @(*) assert(state_waiting_for_flash == (bits_so_far <= 96)); // After we're done transferring bits from the flash chip, the counter will // have elapsed at most 97 times. always @(posedge i_clk) assert(bits_so_far <= 97); // We note that state_waiting_to_deliver_results is asserted for the duration of // the ROMA core's attempt to return results. This matches o_d_valid's behavior // precisely. always @(*) assert(o_d_valid == state_waiting_to_deliver_results); // After a system reset, the core must be in an idle state. always @(posedge i_clk) if($past(i_reset)) begin assert(bits_so_far == 97); end always @(*) cover(i_d_ready && o_d_valid && (o_d_data == 64'hDEADBEEFFEEDFACE)); |
Changes to cores/roma/rtl/verilog/roma.sby.
1 2 | [options] mode prove | | | 1 2 3 4 5 6 7 8 9 10 | [options] mode prove depth 200 [engines] smtbmc [script] read -incdir ../../../../../include/verilog read -formal -sv roma.v |
︙ | ︙ |
Changes to cores/roma/rtl/verilog/roma.v.
︙ | ︙ | |||
53 54 55 56 57 58 59 | input i_a_valid; output o_a_ready; output reg [2:0] o_d_opcode; output [63:0] o_d_data; output [1:0] o_d_size; output reg [1:0] o_d_source; | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > < < < < | 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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | input i_a_valid; output o_a_ready; output reg [2:0] o_d_opcode; output [63:0] o_d_data; output [1:0] o_d_size; output reg [1:0] o_d_source; output o_d_valid; input i_d_ready; output o_spi_mosi; input i_spi_miso; output o_spi_clk; output reg o_spi_cs; // The three major states of the ROMA core. reg state_waiting_for_get_request; reg state_waiting_for_flash; reg state_waiting_to_deliver_results; always @(posedge i_clk) begin state_waiting_for_get_request <= state_waiting_for_get_request; state_waiting_for_flash <= state_waiting_for_flash; state_waiting_to_deliver_results <= state_waiting_to_deliver_results; if(i_reset) begin state_waiting_for_get_request <= 1; state_waiting_for_flash <= 0; state_waiting_to_deliver_results <= 0; end else if(o_a_ready && i_a_valid && (i_a_opcode == `A_OPC_GET)) begin state_waiting_for_get_request <= 0; state_waiting_for_flash <= 1; state_waiting_to_deliver_results <= 0; end else if(bits_so_far == 7'd96) begin state_waiting_for_get_request <= 0; state_waiting_for_flash <= 0; state_waiting_to_deliver_results <= 1; end else if(o_d_valid && i_d_ready) begin state_waiting_for_get_request <= 1; state_waiting_for_flash <= 0; state_waiting_to_deliver_results <= 0; end end reg [32:0] send_message; reg [6:0] bits_so_far; reg getting_data; wire is_read_request = (i_a_valid && o_a_ready && (i_a_opcode === `A_OPC_GET)); wire can_start_receiving_data = (bits_so_far == 7'd32); wire finished_receiving_data = (bits_so_far == 7'd96); wire d_channel_handoff = (o_d_valid && i_d_ready); assign o_a_ready = state_waiting_for_get_request; assign o_d_valid = state_waiting_to_deliver_results; assign o_d_size = `D_SIZ_DWORD; assign o_spi_clk = i_clk & o_spi_cs; always @(posedge i_clk) begin o_d_opcode <= o_d_opcode; o_d_source <= o_d_source; if(i_reset) begin o_d_opcode <= 0; end else if(finished_receiving_data) begin o_d_opcode <= `D_OPC_GET_DATA; o_d_source <= i_a_source; end else if(d_channel_handoff) begin o_d_opcode <= 0; end end always @(posedge i_clk) begin o_spi_cs <= o_spi_cs; |
︙ | ︙ | |||
158 159 160 161 162 163 164 | rxd[7:0], rxd[15:8], rxd[23:16], rxd[31:24], rxd[39:32], rxd[47:40], rxd[55:48], rxd[63:56] }; `ifdef FORMAL initial begin bits_so_far <= 97; | | > > > | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | rxd[7:0], rxd[15:8], rxd[23:16], rxd[31:24], rxd[39:32], rxd[47:40], rxd[55:48], rxd[63:56] }; `ifdef FORMAL initial begin bits_so_far <= 97; state_waiting_for_get_request <= 1; state_waiting_for_flash <= 0; state_waiting_to_deliver_results <= 0; end `include "properties.vf" `endif endmodule |