test(fpga): F-2.2 adversarial mid-frame reset sweep + F-0.1 TB plumbing
G9B adds a 4-iteration reset sweep on top of the existing e2e harness: - Reset is injected at four offsets (3/7/12/18 us) into a steady-state auto-scan burst, with mixed short/long hold durations (20-120 clk_100m) to exercise asynchronous assert paths through the FSM + CDCs. - Each iteration asserts: system_status drops to 0 during reset, new_chirp_frame resumes post-release, and obs_range_valid_count advances — proving the full DDC->MF chain recovers, not just the transmitter FSM. The stub and three existing testbenches are updated to drive the new adc_or_p/n ports tied to 1'b0/1'b1, matching the F-0.1 RTL change.
This commit is contained in:
@@ -19,6 +19,10 @@ module ad9484_interface_400m (
|
|||||||
input wire [7:0] adc_d_n,
|
input wire [7:0] adc_d_n,
|
||||||
input wire adc_dco_p,
|
input wire adc_dco_p,
|
||||||
input wire adc_dco_n,
|
input wire adc_dco_n,
|
||||||
|
// Audit F-0.1: AD9484 OR (overrange) LVDS pair — stub treats adc_or_p as
|
||||||
|
// the single-ended overrange flag, adc_or_n is ignored.
|
||||||
|
input wire adc_or_p,
|
||||||
|
input wire adc_or_n,
|
||||||
|
|
||||||
// System Interface
|
// System Interface
|
||||||
input wire sys_clk,
|
input wire sys_clk,
|
||||||
@@ -27,7 +31,8 @@ module ad9484_interface_400m (
|
|||||||
// Output at 400MHz domain
|
// Output at 400MHz domain
|
||||||
output wire [7:0] adc_data_400m,
|
output wire [7:0] adc_data_400m,
|
||||||
output wire adc_data_valid_400m,
|
output wire adc_data_valid_400m,
|
||||||
output wire adc_dco_bufg
|
output wire adc_dco_bufg,
|
||||||
|
output wire adc_overrange_400m
|
||||||
);
|
);
|
||||||
|
|
||||||
// Pass-through clock (no BUFG needed in simulation)
|
// Pass-through clock (no BUFG needed in simulation)
|
||||||
@@ -50,4 +55,15 @@ end
|
|||||||
assign adc_data_400m = adc_data_400m_reg;
|
assign adc_data_400m = adc_data_400m_reg;
|
||||||
assign adc_data_valid_400m = adc_data_valid_400m_reg;
|
assign adc_data_valid_400m = adc_data_valid_400m_reg;
|
||||||
|
|
||||||
|
// Audit F-0.1: 1-cycle pipeline of adc_or_p to match the real IDDR+register
|
||||||
|
// capture path. TB drives adc_or_p directly with the overrange flag.
|
||||||
|
reg adc_overrange_400m_reg;
|
||||||
|
always @(posedge adc_dco_p or negedge reset_n) begin
|
||||||
|
if (!reset_n)
|
||||||
|
adc_overrange_400m_reg <= 1'b0;
|
||||||
|
else
|
||||||
|
adc_overrange_400m_reg <= adc_or_p;
|
||||||
|
end
|
||||||
|
assign adc_overrange_400m = adc_overrange_400m_reg;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -487,6 +487,8 @@ radar_system_top #(
|
|||||||
.adc_d_n(adc_d_n),
|
.adc_d_n(adc_d_n),
|
||||||
.adc_dco_p(adc_dco_p),
|
.adc_dco_p(adc_dco_p),
|
||||||
.adc_dco_n(adc_dco_n),
|
.adc_dco_n(adc_dco_n),
|
||||||
|
.adc_or_p(1'b0),
|
||||||
|
.adc_or_n(1'b1),
|
||||||
.adc_pwdn(adc_pwdn),
|
.adc_pwdn(adc_pwdn),
|
||||||
|
|
||||||
// STM32 Control
|
// STM32 Control
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ radar_receiver_final dut (
|
|||||||
// ADC "LVDS" -- stub treats adc_d_p as single-ended data
|
// ADC "LVDS" -- stub treats adc_d_p as single-ended data
|
||||||
.adc_d_p(adc_data),
|
.adc_d_p(adc_data),
|
||||||
.adc_d_n(~adc_data), // Complement (ignored by stub)
|
.adc_d_n(~adc_data), // Complement (ignored by stub)
|
||||||
|
.adc_or_p(1'b0), // F-0.1: no overrange stimulus in this TB
|
||||||
|
.adc_or_n(1'b1),
|
||||||
.adc_dco_p(clk_400m), // 400 MHz clock
|
.adc_dco_p(clk_400m), // 400 MHz clock
|
||||||
.adc_dco_n(~clk_400m), // Complement (ignored by stub)
|
.adc_dco_n(~clk_400m), // Complement (ignored by stub)
|
||||||
.adc_pwdn(),
|
.adc_pwdn(),
|
||||||
|
|||||||
@@ -427,6 +427,8 @@ radar_system_top #(
|
|||||||
.adc_d_n(adc_d_n),
|
.adc_d_n(adc_d_n),
|
||||||
.adc_dco_p(adc_dco_p),
|
.adc_dco_p(adc_dco_p),
|
||||||
.adc_dco_n(adc_dco_n),
|
.adc_dco_n(adc_dco_n),
|
||||||
|
.adc_or_p(1'b0),
|
||||||
|
.adc_or_n(1'b1),
|
||||||
.adc_pwdn(adc_pwdn),
|
.adc_pwdn(adc_pwdn),
|
||||||
|
|
||||||
.stm32_new_chirp(stm32_new_chirp),
|
.stm32_new_chirp(stm32_new_chirp),
|
||||||
@@ -938,6 +940,106 @@ initial begin
|
|||||||
|
|
||||||
$display("");
|
$display("");
|
||||||
|
|
||||||
|
// ================================================================
|
||||||
|
// GROUP 9B: Adversarial reset sweep (audit F-2.2)
|
||||||
|
// ================================================================
|
||||||
|
// Drive the same auto-scan pipeline, then inject reset at four distinct
|
||||||
|
// offsets relative to a known-good start of operation. For each offset
|
||||||
|
// the system must:
|
||||||
|
// (a) present system_status == 0 while held in reset
|
||||||
|
// (b) produce at least one additional new_chirp_frame within the
|
||||||
|
// observation window after reset release
|
||||||
|
// (c) advance obs_range_valid_count (confirms full DDC+MF chain resumes)
|
||||||
|
// The four offsets are chosen to hit mid-chirp, mid-listen, and around
|
||||||
|
// the short/long chirp boundary, which covers the interesting FSM and
|
||||||
|
// CDC transitions in the pipeline.
|
||||||
|
$display("--- Group 9B: Adversarial reset sweep (F-2.2) ---");
|
||||||
|
begin : reset_sweep
|
||||||
|
integer sweep_i;
|
||||||
|
integer sweep_baseline_range;
|
||||||
|
integer sweep_baseline_chirp;
|
||||||
|
integer sweep_offsets [0:3];
|
||||||
|
integer sweep_holds [0:3];
|
||||||
|
reg sweep_ok;
|
||||||
|
|
||||||
|
// Reset injection offsets (ns) after the last auto-scan reconfigure.
|
||||||
|
// 3 us / 7 us / 12 us / 18 us — sprayed across a short-chirp burst.
|
||||||
|
sweep_offsets[0] = 3000;
|
||||||
|
sweep_offsets[1] = 7000;
|
||||||
|
sweep_offsets[2] = 12000;
|
||||||
|
sweep_offsets[3] = 18000;
|
||||||
|
// Reset-assert durations mix short (~20 clk_100m) and long (~120)
|
||||||
|
sweep_holds[0] = 200;
|
||||||
|
sweep_holds[1] = 1200;
|
||||||
|
sweep_holds[2] = 400;
|
||||||
|
sweep_holds[3] = 800;
|
||||||
|
|
||||||
|
for (sweep_i = 0; sweep_i < 4; sweep_i = sweep_i + 1) begin
|
||||||
|
// Re-seed auto-scan from a clean base each iteration
|
||||||
|
reset_n = 0;
|
||||||
|
bfm_rx_wr_ptr = 0;
|
||||||
|
bfm_rx_rd_ptr = 0;
|
||||||
|
#200;
|
||||||
|
reset_n = 1;
|
||||||
|
#500;
|
||||||
|
stm32_mixers_enable = 1;
|
||||||
|
ft601_txe = 0;
|
||||||
|
bfm_send_cmd(8'h04, 8'h00, 16'h0001);
|
||||||
|
#500;
|
||||||
|
bfm_send_cmd(8'h01, 8'h00, 16'h0001);
|
||||||
|
bfm_send_cmd(8'h10, 8'h00, 16'd100);
|
||||||
|
bfm_send_cmd(8'h11, 8'h00, 16'd200);
|
||||||
|
bfm_send_cmd(8'h12, 8'h00, 16'd100);
|
||||||
|
bfm_send_cmd(8'h13, 8'h00, 16'd20);
|
||||||
|
bfm_send_cmd(8'h14, 8'h00, 16'd100);
|
||||||
|
bfm_send_cmd(8'h15, 8'h00, 16'd4);
|
||||||
|
|
||||||
|
// Let the pipeline reach steady-state and capture a baseline
|
||||||
|
#30000;
|
||||||
|
sweep_baseline_range = obs_range_valid_count;
|
||||||
|
sweep_baseline_chirp = obs_chirp_frame_count;
|
||||||
|
|
||||||
|
// Wait out the configured offset, then assert reset asynchronously
|
||||||
|
#(sweep_offsets[sweep_i]);
|
||||||
|
reset_n = 0;
|
||||||
|
#(sweep_holds[sweep_i]);
|
||||||
|
sweep_ok = (system_status == 4'b0000);
|
||||||
|
check(sweep_ok,
|
||||||
|
"G9B.a: system_status drops to 0 during injected reset");
|
||||||
|
|
||||||
|
// Release reset, re-configure (regs are cleared), allow recovery
|
||||||
|
reset_n = 1;
|
||||||
|
#500;
|
||||||
|
stm32_mixers_enable = 1;
|
||||||
|
ft601_txe = 0;
|
||||||
|
bfm_send_cmd(8'h04, 8'h00, 16'h0001);
|
||||||
|
#500;
|
||||||
|
bfm_send_cmd(8'h01, 8'h00, 16'h0001);
|
||||||
|
bfm_send_cmd(8'h10, 8'h00, 16'd100);
|
||||||
|
bfm_send_cmd(8'h11, 8'h00, 16'd200);
|
||||||
|
bfm_send_cmd(8'h12, 8'h00, 16'd100);
|
||||||
|
bfm_send_cmd(8'h13, 8'h00, 16'd20);
|
||||||
|
bfm_send_cmd(8'h14, 8'h00, 16'd100);
|
||||||
|
bfm_send_cmd(8'h15, 8'h00, 16'd4);
|
||||||
|
|
||||||
|
sweep_baseline_range = obs_range_valid_count;
|
||||||
|
sweep_baseline_chirp = obs_chirp_frame_count;
|
||||||
|
#60000; // 60 us — two+ short-chirp frames
|
||||||
|
|
||||||
|
check(obs_chirp_frame_count > sweep_baseline_chirp,
|
||||||
|
"G9B.b: new_chirp_frame resumes after injected reset");
|
||||||
|
check(obs_range_valid_count > sweep_baseline_range,
|
||||||
|
"G9B.c: range pipeline resumes after injected reset");
|
||||||
|
|
||||||
|
$display(" [F-2.2] iter=%0d offset=%0dns hold=%0dns chirps=+%0d ranges=+%0d",
|
||||||
|
sweep_i, sweep_offsets[sweep_i], sweep_holds[sweep_i],
|
||||||
|
obs_chirp_frame_count - sweep_baseline_chirp,
|
||||||
|
obs_range_valid_count - sweep_baseline_range);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
$display("");
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
// GROUP 10: STREAM CONTROL (Gap 2)
|
// GROUP 10: STREAM CONTROL (Gap 2)
|
||||||
// ================================================================
|
// ================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user