Add SymbiYosys formal verification for 6 modules, fix 2 doppler bugs
Formal verification (SymbiYosys + smtbmc/z3): - cdc_single_bit: BMC PASS depth 80, cover PASS 3/3 - cdc_handshake: BMC PASS depth 100, cover PASS 4/4 - cdc_adc_to_processing: BMC PASS depth 80, cover PASS - radar_mode_controller: BMC PASS depth 200, cover PASS 8/8 - range_bin_decimator: cover PASS 7/7, BMC running (step 61+) - doppler_processor: cover running (step 133/150), BMC running (step 35+) DUT bug fixes found by formal: - doppler_processor: write_chirp_index overflow past CHIRPS_PER_FRAME-1 in S_ACCUMULATE frame-complete branch (reset to 0) - doppler_processor: read_doppler_index unclamped prefetch in S_LOAD_FFT causing OOB BRAM reads (clamped to DOPPLER_FFT_SIZE-1) CDC fix (prior session, included): - cdc_modules: async reset changed to sync reset on all CDC sync chains to prevent metastability on reset deassertion RTL changes for formal observability: - Added ifdef FORMAL output ports to cdc_handshake (6), cdc_adc (2), radar_mode_controller (2), range_bin_decimator (5), doppler_processor (11)
This commit is contained in:
@@ -17,6 +17,10 @@ module cdc_adc_to_processing #(
|
||||
input wire src_valid,
|
||||
output wire [WIDTH-1:0] dst_data,
|
||||
output wire dst_valid
|
||||
`ifdef FORMAL
|
||||
,output wire [WIDTH-1:0] fv_src_data_reg,
|
||||
output wire [1:0] fv_src_toggle
|
||||
`endif
|
||||
);
|
||||
|
||||
// Gray encoding for safe CDC
|
||||
@@ -50,8 +54,8 @@ module cdc_adc_to_processing #(
|
||||
reg dst_valid_reg = 0;
|
||||
reg [1:0] prev_dst_toggle = 2'b00;
|
||||
|
||||
// Source domain: capture data and toggle
|
||||
always @(posedge src_clk or negedge reset_n) begin
|
||||
// Source domain: capture data and toggle — synchronous reset
|
||||
always @(posedge src_clk) begin
|
||||
if (!reset_n) begin
|
||||
src_data_reg <= 0;
|
||||
src_toggle <= 2'b00;
|
||||
@@ -97,8 +101,8 @@ module cdc_adc_to_processing #(
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Detect new data
|
||||
always @(posedge dst_clk or negedge reset_n) begin
|
||||
// Detect new data — synchronous reset
|
||||
always @(posedge dst_clk) begin
|
||||
if (!reset_n) begin
|
||||
dst_data_reg <= 0;
|
||||
dst_valid_reg <= 0;
|
||||
@@ -119,11 +123,18 @@ module cdc_adc_to_processing #(
|
||||
|
||||
assign dst_data = dst_data_reg;
|
||||
assign dst_valid = dst_valid_reg;
|
||||
|
||||
`ifdef FORMAL
|
||||
assign fv_src_data_reg = src_data_reg;
|
||||
assign fv_src_toggle = src_toggle;
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
|
||||
// ============================================================================
|
||||
// CDC FOR SINGLE BIT SIGNALS
|
||||
// Uses synchronous reset on sync chain to avoid metastability on reset
|
||||
// deassertion. Matches cdc_adc_to_processing best practice.
|
||||
// ============================================================================
|
||||
module cdc_single_bit #(
|
||||
parameter STAGES = 3
|
||||
@@ -137,7 +148,7 @@ module cdc_single_bit #(
|
||||
|
||||
(* ASYNC_REG = "TRUE" *) reg [STAGES-1:0] sync_chain;
|
||||
|
||||
always @(posedge dst_clk or negedge reset_n) begin
|
||||
always @(posedge dst_clk) begin
|
||||
if (!reset_n) begin
|
||||
sync_chain <= 0;
|
||||
end else begin
|
||||
@@ -151,6 +162,7 @@ endmodule
|
||||
|
||||
// ============================================================================
|
||||
// CDC FOR MULTI-BIT WITH HANDSHAKE
|
||||
// Uses synchronous reset to avoid metastability on reset deassertion.
|
||||
// ============================================================================
|
||||
module cdc_handshake #(
|
||||
parameter WIDTH = 32
|
||||
@@ -164,6 +176,14 @@ module cdc_handshake #(
|
||||
output wire [WIDTH-1:0] dst_data,
|
||||
output wire dst_valid,
|
||||
input wire dst_ready
|
||||
`ifdef FORMAL
|
||||
,output wire fv_src_busy,
|
||||
output wire fv_dst_ack,
|
||||
output wire fv_dst_req_sync,
|
||||
output wire [1:0] fv_src_ack_sync_chain,
|
||||
output wire [1:0] fv_dst_req_sync_chain,
|
||||
output wire [WIDTH-1:0] fv_src_data_reg_hs
|
||||
`endif
|
||||
);
|
||||
|
||||
// Source domain
|
||||
@@ -178,9 +198,18 @@ module cdc_handshake #(
|
||||
reg dst_req_sync = 0;
|
||||
(* ASYNC_REG = "TRUE" *) reg [1:0] dst_req_sync_chain = 2'b00;
|
||||
reg dst_ack = 0;
|
||||
|
||||
`ifdef FORMAL
|
||||
assign fv_src_busy = src_busy;
|
||||
assign fv_dst_ack = dst_ack;
|
||||
assign fv_dst_req_sync = dst_req_sync;
|
||||
assign fv_src_ack_sync_chain = src_ack_sync_chain;
|
||||
assign fv_dst_req_sync_chain = dst_req_sync_chain;
|
||||
assign fv_src_data_reg_hs = src_data_reg;
|
||||
`endif
|
||||
|
||||
// Source clock domain
|
||||
always @(posedge src_clk or negedge reset_n) begin
|
||||
// Source clock domain — synchronous reset
|
||||
always @(posedge src_clk) begin
|
||||
if (!reset_n) begin
|
||||
src_data_reg <= 0;
|
||||
src_busy <= 0;
|
||||
@@ -200,8 +229,8 @@ module cdc_handshake #(
|
||||
end
|
||||
end
|
||||
|
||||
// Destination clock domain
|
||||
always @(posedge dst_clk or negedge reset_n) begin
|
||||
// Destination clock domain — synchronous reset
|
||||
always @(posedge dst_clk) begin
|
||||
if (!reset_n) begin
|
||||
dst_data_reg <= 0;
|
||||
dst_valid_reg <= 0;
|
||||
|
||||
Reference in New Issue
Block a user