Kestrel-3

Check-in [b014c7b07f]
Login

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: b014c7b07f6f536ae3c0756aa91c3c3184adb39205b14483722539db654b1b50
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to cores/roma/rtl/verilog/properties.vf.

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
reg past_valid = 0;
always @(posedge i_clk) past_valid <= 1;

always #1 i_clk <= ~i_clk;

// The TileLink port should always work as follows:
// 1.  While idle, o_a_ready is asserted, indicating we're ready for transactions.
//     o_d_valid should also be negated, since we have nothing to respond with.
// 2.  We receive an address and GET opcode on the A-channel.
// 3.  After some time, we present the data on o_d_data and assert o_d_valid.
// 4.  After o_d_valid && i_d_ready, we return to the idle condition.

// After power-on or reset, the TileLink port must be in the idle state.
always @(posedge i_clk)
if(!past_valid) begin
	assume(i_reset);

end

always @(posedge i_clk)
if(!past_valid || $past(i_reset)) begin




	assert(o_a_ready == 1);






	assert(o_d_valid == 0);







	assume(i_a_valid);

	assume(i_a_opcode == `A_OPC_GET);



	assume(i_d_ready);



end




// We receive a GET request on the A-channel.


reg processing_request = 0;





always @(posedge i_clk)





if(i_reset) processing_request <= 0;
else if(i_a_valid && o_a_ready && (i_a_opcode == `A_OPC_GET)) processing_request <= 1;





else if(processing_request && finished_receiving_data) processing_request <= 0;


// If we're processing a request, we must negate o_a_ready.


// This prevents any masters from sending a request we can't yet handle.
always @(posedge i_clk)

if(processing_request) assert(!o_a_ready);

// While we're processing a request, we must keep o_d_valid negated.








always @(posedge i_clk)



if(processing_request) assert(!o_d_valid);

always @(*) cover(i_d_ready && o_d_valid && (o_d_data == 64'hDEADBEEFFEEDFACE));





<
<
<
<
<
|

<



>



|
>
>
>
>
|
>
>
>
>
>
>
|
>
>
>
>
>

>
|
>
|
>
>
>
|
>
>
>
|
>
>
>

|
>
>
|
>

>
>
>

>
>
>
>
>
|
|
>
>
>
>
>
|
>

|
>
>
|

>
|

|
>
>
>
>
>
>
>
>

>
>
>
|


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
3
4
5
6
7
8
9
10
[options]
mode prove
depth 100

[engines]
smtbmc

[script]
read -incdir ../../../../../include/verilog
read -formal -sv roma.v


|







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
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
	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 reg o_d_valid;
	input i_d_ready;

	output o_spi_mosi;
	input i_spi_miso;
	output o_spi_clk;
	output reg o_spi_cs;


































	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 = (bits_so_far == 7'd97);


	assign o_d_size = `D_SIZ_DWORD;
	assign o_spi_clk = i_clk & o_spi_cs;

	always @(posedge i_clk) begin
		o_d_valid <= o_d_valid;
		o_d_opcode <= o_d_opcode;
		o_d_source <= o_d_source;

		if(i_reset) begin
			o_d_valid <= 0;
			o_d_opcode <= 0;
		end
		else if(finished_receiving_data) begin
			o_d_valid <= 1;
			o_d_opcode <= `D_OPC_GET_DATA;
			o_d_source <= i_a_source;
		end
		else if(d_channel_handoff) begin
			o_d_valid <= 0;
			o_d_opcode <= 0;
		end
	end

	always @(posedge i_clk) begin
		o_spi_cs <= o_spi_cs;








|






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|
>
>




<




<



<




<







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
165



166
167
168
169
170
171
		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;
		o_d_valid <= 0;



	end

`include "properties.vf"
`endif

endmodule







|
>
>
>






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