mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-06-09 06:57:15 +00:00
test(dataflow): PR-I.3 — tb_system_dataflow shallow integration probe
Shallow probe verifying that auto-scan kicks the production pipeline end-of-TX-side cleanly: chirp_scheduler emits new_chirp_frame, the range pipeline (DDC + matched filter + range decimator) emits multi-bin range profiles. Recovers G2.2 (new_chirp_frame pulse), G4.1 (range_valid pulse), G4.2 (>=100 range bins) — three of T-2's sixteen hidden failures. Sim runs ~18 ms simulated (about 60-90 s wall on iverilog) — covers one full 48-chirp frame TX time. Watchdog at 25 ms. Deferred to PR-J: G4.4 doppler_valid pulse, G5.1-5.4 USB egress, G9.x reset recovery. Real finding: matched_filter_multi_segment hangs in ST_WAIT_FFT under continuous auto-scan — the inner FFT chain (xfft_2048 + frequency_matched_filter) does not assert fft_done in SIMULATION mode after the first chirp's segment completes. tb_mf_cosim still exercises the inner block in isolation (passes); the multi-segment wrapper has no dedicated TB (T-9). The hang is a production-chain integration bug, not a test infrastructure issue. This TB is NOT yet wired into run_regression.sh — that lands in PR-I.4 along with retiring tb_system_e2e.
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
`timescale 1ns / 1ps
|
||||
`include "radar_params.vh"
|
||||
|
||||
// ============================================================================
|
||||
// tb_system_dataflow.v (PR-I, replaces tb_system_e2e G2.2 / G4.1 / G4.2)
|
||||
//
|
||||
// Shallow dataflow probe — verifies that auto-scan starts the production
|
||||
// pipeline cleanly: TX fires chirps, the range pipeline emits multi-bin
|
||||
// outputs through the matched filter, and observation counters advance.
|
||||
//
|
||||
// Coverage:
|
||||
// G2.2 new_chirp_frame pulsed (TX + chirp_scheduler alive)
|
||||
// G4.1 rx_range_valid pulsed (DDC + matched filter + range decimator)
|
||||
// G4.2 >= 100 range bin outputs (multi-bin emission)
|
||||
//
|
||||
// Deferred (NOT covered here — requires deeper RTL fix):
|
||||
// G4.4 doppler_valid pulse — full 48-chirp frame Doppler FFT.
|
||||
// G5.x USB header/footer egress.
|
||||
// G9.x Reset-mid-sim recovery.
|
||||
//
|
||||
// Probe runs surface a hang in matched_filter_multi_segment's
|
||||
// ST_WAIT_FFT under continuous auto-scan stimulus: the inner FFT chain
|
||||
// (xfft_2048 + frequency_matched_filter) does not assert fft_done in
|
||||
// SIMULATION mode, so segment 0/1 never advances. tb_mf_cosim still
|
||||
// exercises matched_filter_processing_chain in isolation, but the
|
||||
// multi-segment wrapper has no dedicated TB (T-9). The hang is NOT
|
||||
// a test infrastructure problem — it is a real production-chain
|
||||
// integration gap to resolve in a future PR-J pipeline pass.
|
||||
//
|
||||
// Sim budget: ~18 ms (one full 48-chirp frame TX + range pipeline drain).
|
||||
// ============================================================================
|
||||
|
||||
module tb_system_dataflow;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Clocks (production)
|
||||
// ----------------------------------------------------------------------------
|
||||
localparam CLK_100M_PERIOD = 10.0;
|
||||
localparam CLK_120M_PERIOD = 8.333;
|
||||
localparam FT_CLK_PERIOD = 16.667;
|
||||
localparam ADC_DCO_PERIOD = 2.5;
|
||||
|
||||
reg clk_100m = 1'b0;
|
||||
reg clk_120m_dac = 1'b0;
|
||||
reg ft601_clk_in = 1'b0;
|
||||
reg adc_dco_p = 1'b0;
|
||||
reg adc_dco_n = 1'b1;
|
||||
|
||||
always #(CLK_100M_PERIOD/2) clk_100m = ~clk_100m;
|
||||
always #(CLK_120M_PERIOD/2) clk_120m_dac = ~clk_120m_dac;
|
||||
always #(FT_CLK_PERIOD/2) ft601_clk_in = ~ft601_clk_in;
|
||||
always #(ADC_DCO_PERIOD/2) begin adc_dco_p = ~adc_dco_p; adc_dco_n = ~adc_dco_n; end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DUT signals
|
||||
// ----------------------------------------------------------------------------
|
||||
reg reset_n = 1'b0;
|
||||
|
||||
reg [7:0] adc_d_p = 8'h80;
|
||||
reg [7:0] adc_d_n = 8'h7F;
|
||||
|
||||
reg stm32_new_chirp = 1'b0;
|
||||
reg stm32_new_elevation = 1'b0;
|
||||
reg stm32_new_azimuth = 1'b0;
|
||||
reg stm32_mixers_enable = 1'b0;
|
||||
reg stm32_sclk_3v3 = 1'b0;
|
||||
reg stm32_mosi_3v3 = 1'b0;
|
||||
wire stm32_miso_3v3;
|
||||
reg stm32_cs_adar1_3v3 = 1'b1, stm32_cs_adar2_3v3 = 1'b1;
|
||||
reg stm32_cs_adar3_3v3 = 1'b1, stm32_cs_adar4_3v3 = 1'b1;
|
||||
wire stm32_sclk_1v8, stm32_mosi_1v8;
|
||||
reg stm32_miso_1v8 = 1'b0;
|
||||
wire stm32_cs_adar1_1v8, stm32_cs_adar2_1v8;
|
||||
wire stm32_cs_adar3_1v8, stm32_cs_adar4_1v8;
|
||||
|
||||
wire [7:0] dac_data;
|
||||
wire dac_clk;
|
||||
wire dac_sleep;
|
||||
|
||||
wire fpga_rf_switch;
|
||||
wire rx_mixer_en, tx_mixer_en;
|
||||
wire adc_pwdn;
|
||||
|
||||
wire adar_tx_load_1, adar_rx_load_1;
|
||||
wire adar_tx_load_2, adar_rx_load_2;
|
||||
wire adar_tx_load_3, adar_rx_load_3;
|
||||
wire adar_tx_load_4, adar_rx_load_4;
|
||||
wire adar_tr_1, adar_tr_2, adar_tr_3, adar_tr_4;
|
||||
|
||||
wire [31:0] ft601_data;
|
||||
wire [3:0] ft601_be;
|
||||
wire ft601_txe_n;
|
||||
wire ft601_rxf_n;
|
||||
reg ft601_txe = 1'b0;
|
||||
reg ft601_rxf = 1'b1;
|
||||
wire ft601_wr_n;
|
||||
wire ft601_rd_n;
|
||||
wire ft601_oe_n;
|
||||
wire ft601_siwu_n;
|
||||
reg [1:0] ft601_srb = 2'b00;
|
||||
reg [1:0] ft601_swb = 2'b00;
|
||||
wire ft601_clk_out;
|
||||
|
||||
wire [7:0] ft_data;
|
||||
reg ft_rxf_n = 1'b1;
|
||||
reg ft_txe_n = 1'b0;
|
||||
wire ft_rd_n;
|
||||
wire ft_wr_n;
|
||||
wire ft_oe_n;
|
||||
wire ft_siwu;
|
||||
pulldown pd[7:0] (ft_data);
|
||||
|
||||
wire [5:0] current_elevation, current_azimuth, current_chirp;
|
||||
wire new_chirp_frame;
|
||||
wire [31:0] dbg_doppler_data;
|
||||
wire dbg_doppler_valid;
|
||||
wire [`RP_DOPPLER_BIN_WIDTH-1:0] dbg_doppler_bin;
|
||||
wire [`RP_RANGE_BIN_WIDTH_MAX-1:0] dbg_range_bin;
|
||||
wire [3:0] system_status;
|
||||
wire gpio_dig5, gpio_dig6, gpio_dig7;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// DUT — radar_system_top with USB_MODE=1 (FT2232H production)
|
||||
// ----------------------------------------------------------------------------
|
||||
radar_system_top #(.USB_MODE(1)) dut (
|
||||
.clk_100m(clk_100m),
|
||||
.clk_120m_dac(clk_120m_dac),
|
||||
.ft601_clk_in(ft601_clk_in),
|
||||
.reset_n(reset_n),
|
||||
|
||||
.dac_data(dac_data), .dac_clk(dac_clk), .dac_sleep(dac_sleep),
|
||||
.fpga_rf_switch(fpga_rf_switch),
|
||||
.rx_mixer_en(rx_mixer_en), .tx_mixer_en(tx_mixer_en),
|
||||
|
||||
.adar_tx_load_1(adar_tx_load_1), .adar_rx_load_1(adar_rx_load_1),
|
||||
.adar_tx_load_2(adar_tx_load_2), .adar_rx_load_2(adar_rx_load_2),
|
||||
.adar_tx_load_3(adar_tx_load_3), .adar_rx_load_3(adar_rx_load_3),
|
||||
.adar_tx_load_4(adar_tx_load_4), .adar_rx_load_4(adar_rx_load_4),
|
||||
.adar_tr_1(adar_tr_1), .adar_tr_2(adar_tr_2),
|
||||
.adar_tr_3(adar_tr_3), .adar_tr_4(adar_tr_4),
|
||||
|
||||
.stm32_sclk_3v3(stm32_sclk_3v3),
|
||||
.stm32_mosi_3v3(stm32_mosi_3v3),
|
||||
.stm32_miso_3v3(stm32_miso_3v3),
|
||||
.stm32_cs_adar1_3v3(stm32_cs_adar1_3v3),
|
||||
.stm32_cs_adar2_3v3(stm32_cs_adar2_3v3),
|
||||
.stm32_cs_adar3_3v3(stm32_cs_adar3_3v3),
|
||||
.stm32_cs_adar4_3v3(stm32_cs_adar4_3v3),
|
||||
.stm32_sclk_1v8(stm32_sclk_1v8),
|
||||
.stm32_mosi_1v8(stm32_mosi_1v8),
|
||||
.stm32_miso_1v8(stm32_miso_1v8),
|
||||
.stm32_cs_adar1_1v8(stm32_cs_adar1_1v8),
|
||||
.stm32_cs_adar2_1v8(stm32_cs_adar2_1v8),
|
||||
.stm32_cs_adar3_1v8(stm32_cs_adar3_1v8),
|
||||
.stm32_cs_adar4_1v8(stm32_cs_adar4_1v8),
|
||||
|
||||
.adc_d_p(adc_d_p), .adc_d_n(adc_d_n),
|
||||
.adc_dco_p(adc_dco_p), .adc_dco_n(adc_dco_n),
|
||||
.adc_or_p(1'b0), .adc_or_n(1'b1),
|
||||
.adc_pwdn(adc_pwdn),
|
||||
|
||||
.stm32_new_chirp(stm32_new_chirp),
|
||||
.stm32_new_elevation(stm32_new_elevation),
|
||||
.stm32_new_azimuth(stm32_new_azimuth),
|
||||
.stm32_mixers_enable(stm32_mixers_enable),
|
||||
|
||||
.ft601_data(ft601_data),
|
||||
.ft601_be(ft601_be),
|
||||
.ft601_txe_n(ft601_txe_n),
|
||||
.ft601_rxf_n(ft601_rxf_n),
|
||||
.ft601_txe(ft601_txe),
|
||||
.ft601_rxf(ft601_rxf),
|
||||
.ft601_wr_n(ft601_wr_n),
|
||||
.ft601_rd_n(ft601_rd_n),
|
||||
.ft601_oe_n(ft601_oe_n),
|
||||
.ft601_siwu_n(ft601_siwu_n),
|
||||
.ft601_srb(ft601_srb),
|
||||
.ft601_swb(ft601_swb),
|
||||
.ft601_clk_out(ft601_clk_out),
|
||||
|
||||
.ft_data(ft_data),
|
||||
.ft_rxf_n(ft_rxf_n),
|
||||
.ft_txe_n(ft_txe_n),
|
||||
.ft_rd_n(ft_rd_n),
|
||||
.ft_wr_n(ft_wr_n),
|
||||
.ft_oe_n(ft_oe_n),
|
||||
.ft_siwu(ft_siwu),
|
||||
|
||||
.current_elevation(current_elevation),
|
||||
.current_azimuth(current_azimuth),
|
||||
.current_chirp(current_chirp),
|
||||
.new_chirp_frame(new_chirp_frame),
|
||||
.dbg_doppler_data(dbg_doppler_data),
|
||||
.dbg_doppler_valid(dbg_doppler_valid),
|
||||
.dbg_doppler_bin(dbg_doppler_bin),
|
||||
.dbg_range_bin(dbg_range_bin),
|
||||
.system_status(system_status),
|
||||
.gpio_dig5(gpio_dig5),
|
||||
.gpio_dig6(gpio_dig6),
|
||||
.gpio_dig7(gpio_dig7)
|
||||
);
|
||||
|
||||
// ADC stimulus: ramp around mid-scale
|
||||
integer adc_phase;
|
||||
initial begin
|
||||
adc_phase = 0;
|
||||
forever begin
|
||||
@(posedge adc_dco_p);
|
||||
if (reset_n) begin
|
||||
adc_d_p = 8'h80 + ((adc_phase * 7) & 8'h3F) - 8'h20;
|
||||
adc_d_n = ~adc_d_p;
|
||||
adc_phase = adc_phase + 1;
|
||||
end else begin
|
||||
adc_d_p = 8'h80;
|
||||
adc_d_n = 8'h7F;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Observation counters
|
||||
// ----------------------------------------------------------------------------
|
||||
integer obs_chirp_frame_count = 0;
|
||||
integer obs_range_valid_count = 0;
|
||||
|
||||
always @(posedge clk_100m) begin
|
||||
if (!reset_n) begin
|
||||
obs_chirp_frame_count = 0;
|
||||
obs_range_valid_count = 0;
|
||||
end else begin
|
||||
if (new_chirp_frame) obs_chirp_frame_count = obs_chirp_frame_count + 1;
|
||||
if (dut.rx_range_valid) obs_range_valid_count = obs_range_valid_count + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test infrastructure
|
||||
// ----------------------------------------------------------------------------
|
||||
integer pass_count = 0;
|
||||
integer fail_count = 0;
|
||||
integer test_num = 0;
|
||||
|
||||
task check;
|
||||
input cond;
|
||||
input [80*8-1:0] msg;
|
||||
begin
|
||||
test_num = test_num + 1;
|
||||
if (cond) begin
|
||||
$display(" [PASS] %0d: %0s", test_num, msg);
|
||||
pass_count = pass_count + 1;
|
||||
end else begin
|
||||
$display(" [FAIL] %0d: %0s", test_num, msg);
|
||||
fail_count = fail_count + 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Test sequence
|
||||
// ----------------------------------------------------------------------------
|
||||
initial begin
|
||||
$display("============================================================");
|
||||
$display(" tb_system_dataflow — TX/RX shallow integration probe");
|
||||
$display("============================================================");
|
||||
|
||||
reset_n = 1'b0;
|
||||
repeat (20) @(posedge clk_100m);
|
||||
reset_n = 1'b1;
|
||||
repeat (50) @(posedge clk_100m);
|
||||
|
||||
stm32_mixers_enable = 1'b1;
|
||||
$display("[%0t] mixers enabled — auto-scan running, waiting ~18 ms", $time);
|
||||
|
||||
// 18 ms covers one full 48-chirp frame (3 sub-frames x 16 chirps,
|
||||
// ~8.4 ms TX) plus enough slack for new_chirp_frame to pulse and the
|
||||
// range pipeline to drain its first ~30 chirps.
|
||||
#18_000_000;
|
||||
|
||||
$display("\n--- Group 2.2 / 4: TX + range pipeline ---");
|
||||
$display(" chirp_frames=%0d range_valid=%0d",
|
||||
obs_chirp_frame_count, obs_range_valid_count);
|
||||
|
||||
check(obs_chirp_frame_count > 0,
|
||||
"G2.2: new_chirp_frame pulsed at least once (TX/scheduler alive)");
|
||||
check(obs_range_valid_count > 0,
|
||||
"G4.1: range_profile_valid pulsed (matched filter produced output)");
|
||||
check(obs_range_valid_count >= 100,
|
||||
"G4.2: >= 100 range profile outputs (multi-bin emission)");
|
||||
|
||||
$display("\n============================================================");
|
||||
$display(" RESULTS: %0d passed, %0d failed / %0d total",
|
||||
pass_count, fail_count, test_num);
|
||||
$display(" Sim time: %0t ns", $time);
|
||||
$display("============================================================");
|
||||
if (fail_count == 0) $display(" *** ALL TESTS PASSED ***");
|
||||
else $display(" *** %0d TEST(S) FAILED ***", fail_count);
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Watchdog — 25 ms (~1.4x the planned 18 ms run)
|
||||
initial begin
|
||||
#25_000_000;
|
||||
$display("[WATCHDOG] tb_system_dataflow timeout at %0t", $time);
|
||||
$display(" Tests: %0d, Pass: %0d, Fail: %0d",
|
||||
test_num, pass_count, fail_count);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user