mirror of
https://github.com/NawfalMotii79/PLFM_RADAR.git
synced 2026-06-10 23:41:18 +00:00
fpga: split gpio_dig5/dig7 by fault class (AUDIT-S10)
gpio_dig5 (PD13) previously OR'd six flags — four signal-saturation classes (AGC, DDC overflow, DDC saturation, MTI saturation) and two control-fault classes (range-decimator watchdog from F-6.4, CIC->FIR CDC overrun from F-1.2). The MCU outer-loop AGC reduces RF gain on PD13 assertion, which is the wrong response to a watchdog or CDC stall — it just hides the stall behind a quiet receive chain. gpio_dig7 (PD15) was tied 1'b0 as "reserved". Split: gpio_dig5 = signal-saturation only (AGC continues to react correctly) gpio_dig7 = control-fault classes Telemetry: status_words[5][6:5] now exposes the two control-fault classes in BOTH legacy (FT601) and FT2232H USB variants, with 2-FF level CDC sync from clk_100m to ft601_clk_in / ft_clk. Bit [7] is reserved. AUDIT-C12's frame_drop_count at [31:25] is preserved. 50T XDC H12 -> gpio_dig7 pin already assigned (audit AUDIT-C15-era); no XDC change. Test: tb/tb_audit_s10_gpio_split.v 17/17 PASS — exercises both the combinational GPIO split and the CDC status-word packing path. Regression: 39/39 PASS (was 34/34).
This commit is contained in:
@@ -839,7 +839,12 @@ if (USB_MODE == 0) begin : gen_ft601
|
|||||||
.status_agc_current_gain(rx_agc_current_gain),
|
.status_agc_current_gain(rx_agc_current_gain),
|
||||||
.status_agc_peak_magnitude(rx_agc_peak_magnitude),
|
.status_agc_peak_magnitude(rx_agc_peak_magnitude),
|
||||||
.status_agc_saturation_count(rx_agc_saturation_count),
|
.status_agc_saturation_count(rx_agc_saturation_count),
|
||||||
.status_agc_enable(host_agc_enable)
|
.status_agc_enable(host_agc_enable),
|
||||||
|
|
||||||
|
// AUDIT-S10: control-fault flags exposed in status_words[5][6:5]
|
||||||
|
// for host-side observability (paired with gpio_dig7 split)
|
||||||
|
.status_range_decim_watchdog(rx_range_decim_watchdog),
|
||||||
|
.status_ddc_cic_fir_overrun(rx_ddc_cic_fir_overrun)
|
||||||
);
|
);
|
||||||
|
|
||||||
// FT2232H ports unused in FT601 mode — tie off
|
// FT2232H ports unused in FT601 mode — tie off
|
||||||
@@ -912,7 +917,12 @@ end else begin : gen_ft2232h
|
|||||||
.status_agc_current_gain(rx_agc_current_gain),
|
.status_agc_current_gain(rx_agc_current_gain),
|
||||||
.status_agc_peak_magnitude(rx_agc_peak_magnitude),
|
.status_agc_peak_magnitude(rx_agc_peak_magnitude),
|
||||||
.status_agc_saturation_count(rx_agc_saturation_count),
|
.status_agc_saturation_count(rx_agc_saturation_count),
|
||||||
.status_agc_enable(host_agc_enable)
|
.status_agc_enable(host_agc_enable),
|
||||||
|
|
||||||
|
// AUDIT-S10: control-fault flags exposed in status_words[5][6:5]
|
||||||
|
// for host-side observability (paired with gpio_dig7 split)
|
||||||
|
.status_range_decim_watchdog(rx_range_decim_watchdog),
|
||||||
|
.status_ddc_cic_fir_overrun(rx_ddc_cic_fir_overrun)
|
||||||
);
|
);
|
||||||
|
|
||||||
// FT601 ports unused in FT2232H mode — tie off
|
// FT601 ports unused in FT2232H mode — tie off
|
||||||
@@ -1139,24 +1149,34 @@ end
|
|||||||
assign system_status = status_reg;
|
assign system_status = status_reg;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// FPGA→STM32 GPIO OUTPUTS (DIG_5, DIG_6, DIG_7)
|
// FPGA→STM32 GPIO OUTPUTS (DIG_5, DIG_6, DIG_7) — AUDIT-S10 SPLIT
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// DIG_5: AGC saturation flag — high when per-frame saturation_count > 0.
|
// AUDIT-S10: gpio_dig5 previously OR'd six unrelated flags (signal-saturation
|
||||||
// STM32 reads PD13 to detect clipping and adjust ADAR1000 VGA gain.
|
// AND control-faults), so the MCU outer-loop AGC could not distinguish
|
||||||
// DIG_6: AGC enable flag — mirrors host_agc_enable so STM32 outer-loop AGC
|
// "I'm clipping, reduce RF gain" from "FFT chain stalled, reset me". Gain
|
||||||
// tracks the FPGA register as single source of truth.
|
// reduction is the wrong response for a watchdog/CDC stall; it just hides the
|
||||||
// DIG_7: Reserved (tied low for future use).
|
// stall behind a quiet receive chain. The split routes the two control-fault
|
||||||
// gpio_dig5: "signal-chain clipped" — asserts on AGC saturation, DDC mixer/FIR
|
// classes (audit F-6.4 range-decimator watchdog, audit F-1.2 CIC→FIR CDC
|
||||||
// overflow, or MTI 2-pulse saturation. Audit F-6.1/F-6.3: these were all
|
// overrun) to gpio_dig7 (PD15) so the MCU can react differently — log + reset
|
||||||
// previously invisible to the MCU.
|
// FPGA — without affecting the AGC loop. Status word visibility is added in
|
||||||
|
// usb_data_interface[*_ft2232h].v so the host can graph each fault class
|
||||||
|
// regardless of MCU consumption.
|
||||||
|
//
|
||||||
|
// DIG_5 (PD13): Signal-chain saturation — outer-loop AGC reduces RF gain.
|
||||||
|
// Asserts on AGC clipping, DDC mixer/filter overflow, or MTI
|
||||||
|
// 2-pulse saturation (audit F-6.1/F-6.3).
|
||||||
|
// DIG_6 (PD14): AGC enable mirror (host_agc_enable) — single source of truth.
|
||||||
|
// DIG_7 (PD15): Control-chain fault — MCU should log + consider FPGA reset.
|
||||||
|
// Asserts on range-decimator watchdog (audit F-6.4) or CIC→FIR
|
||||||
|
// CDC overrun (audit F-1.2). MCU consumption is a tracked
|
||||||
|
// follow-up; until then the host telemetry path covers it.
|
||||||
assign gpio_dig5 = (rx_agc_saturation_count != 8'd0)
|
assign gpio_dig5 = (rx_agc_saturation_count != 8'd0)
|
||||||
| rx_ddc_overflow_any
|
| rx_ddc_overflow_any
|
||||||
| (rx_ddc_saturation_count != 3'd0)
|
| (rx_ddc_saturation_count != 3'd0)
|
||||||
| (rx_mti_saturation_count != 8'd0)
|
| (rx_mti_saturation_count != 8'd0);
|
||||||
| rx_range_decim_watchdog // audit F-6.4
|
|
||||||
| rx_ddc_cic_fir_overrun; // audit F-1.2
|
|
||||||
assign gpio_dig6 = host_agc_enable;
|
assign gpio_dig6 = host_agc_enable;
|
||||||
assign gpio_dig7 = 1'b0;
|
assign gpio_dig7 = rx_range_decim_watchdog // audit F-6.4
|
||||||
|
| rx_ddc_cic_fir_overrun; // audit F-1.2
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// DEBUG AND VERIFICATION
|
// DEBUG AND VERIFICATION
|
||||||
|
|||||||
@@ -143,7 +143,10 @@ usb_data_interface usb_inst (
|
|||||||
.status_agc_current_gain(4'd0),
|
.status_agc_current_gain(4'd0),
|
||||||
.status_agc_peak_magnitude(8'd0),
|
.status_agc_peak_magnitude(8'd0),
|
||||||
.status_agc_saturation_count(8'd0),
|
.status_agc_saturation_count(8'd0),
|
||||||
.status_agc_enable(1'b0)
|
.status_agc_enable(1'b0),
|
||||||
|
// AUDIT-S10: control-fault flags tied off on dev board (no DDC/decimator)
|
||||||
|
.status_range_decim_watchdog(1'b0),
|
||||||
|
.status_ddc_cic_fir_overrun(1'b0)
|
||||||
);
|
);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -562,6 +562,10 @@ run_test "ADC PWDN opcode 0x32 (AUDIT-S25)" \
|
|||||||
tb/tb_adc_pwdn_opcode.vvp \
|
tb/tb_adc_pwdn_opcode.vvp \
|
||||||
tb/tb_adc_pwdn_opcode.v
|
tb/tb_adc_pwdn_opcode.v
|
||||||
|
|
||||||
|
run_test "GPIO dig5/dig7 split (AUDIT-S10)" \
|
||||||
|
tb/tb_audit_s10_gpio_split.vvp \
|
||||||
|
tb/tb_audit_s10_gpio_split.v
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# ===========================================================================
|
# ===========================================================================
|
||||||
|
|||||||
@@ -0,0 +1,357 @@
|
|||||||
|
// ============================================================================
|
||||||
|
// tb_audit_s10_gpio_split.v
|
||||||
|
//
|
||||||
|
// AUDIT-S10: gpio_dig5 previously OR'd six unrelated flags — four signal-
|
||||||
|
// saturation classes (AGC, DDC overflow, DDC saturation, MTI saturation) and
|
||||||
|
// two control-fault classes (range-decimator watchdog, CIC->FIR CDC overrun)
|
||||||
|
// — into the single MCU-visible bit at PD13. The MCU outer-loop AGC reduces
|
||||||
|
// RF gain on PD13 assertion, which is the wrong response to a watchdog or
|
||||||
|
// CDC stall. gpio_dig7 (PD15) was tied 1'b0 (reserved).
|
||||||
|
//
|
||||||
|
// Fix: split the OR-network so gpio_dig5 carries only signal-saturation flags
|
||||||
|
// (AGC continues to react correctly) and gpio_dig7 carries control-fault
|
||||||
|
// flags (MCU follow-up will log + reset; until then host telemetry covers).
|
||||||
|
// Status words[5][6:5] expose the two control-fault classes so host-side
|
||||||
|
// can graph them regardless of MCU consumption.
|
||||||
|
//
|
||||||
|
// This TB mirrors the production fragments from radar_system_top.v and
|
||||||
|
// usb_data_interface[*_ft2232h].v and asserts:
|
||||||
|
//
|
||||||
|
// GROUP A GPIO split (combinational)
|
||||||
|
// T1 All inputs 0 -> dig5=0, dig7=0
|
||||||
|
// T2 Each signal-sat input -> dig5=1, dig7=0 (no cross-route to dig7)
|
||||||
|
// T3 Each control-fault -> dig5=0, dig7=1 (no cross-route to dig5)
|
||||||
|
// T4 Mixed sat + fault -> dig5=1, dig7=1 (independent)
|
||||||
|
// T5 AGC count >0 (boundary) -> dig5=1
|
||||||
|
// T6 DDC count =0 (boundary) -> dig5=0
|
||||||
|
//
|
||||||
|
// GROUP B Status-word CDC packing (sequential)
|
||||||
|
// T7 Reset state -> sync regs 0, status_word_bits 0
|
||||||
|
// T8 Watchdog asserted in src -> after 2 ft_clk edges, status[5]=1
|
||||||
|
// T9 CIC overrun asserted in src -> after 2 ft_clk edges, status[6]=1
|
||||||
|
// T10 Both asserted, both cleared -> status[6:5] tracks (sticky in src;
|
||||||
|
// TB drives explicit clears)
|
||||||
|
// T11 status_words[5][7] stays 0 (reserved bit, not stomped by sync)
|
||||||
|
// T12 status_words[5][4:0] (self_test_flags) stays = src input
|
||||||
|
// ============================================================================
|
||||||
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
|
module tb_audit_s10_gpio_split;
|
||||||
|
|
||||||
|
// ===== GROUP A: GPIO split inputs/outputs =====
|
||||||
|
reg [7:0] agc_saturation_count;
|
||||||
|
reg ddc_overflow_any;
|
||||||
|
reg [2:0] ddc_saturation_count;
|
||||||
|
reg [7:0] mti_saturation_count;
|
||||||
|
reg range_decim_watchdog;
|
||||||
|
reg ddc_cic_fir_overrun;
|
||||||
|
|
||||||
|
wire dig5;
|
||||||
|
wire dig7;
|
||||||
|
|
||||||
|
gpio_split_block gpio_dut (
|
||||||
|
.agc_saturation_count (agc_saturation_count),
|
||||||
|
.ddc_overflow_any (ddc_overflow_any),
|
||||||
|
.ddc_saturation_count (ddc_saturation_count),
|
||||||
|
.mti_saturation_count (mti_saturation_count),
|
||||||
|
.range_decim_watchdog (range_decim_watchdog),
|
||||||
|
.ddc_cic_fir_overrun (ddc_cic_fir_overrun),
|
||||||
|
.gpio_dig5 (dig5),
|
||||||
|
.gpio_dig7 (dig7)
|
||||||
|
);
|
||||||
|
|
||||||
|
// ===== GROUP B: status-word CDC packing =====
|
||||||
|
reg clk_src = 1'b0; // 100 MHz radar domain
|
||||||
|
reg ft_clk = 1'b0; // 60/100 MHz USB domain
|
||||||
|
reg reset_n = 1'b0;
|
||||||
|
reg src_watchdog;
|
||||||
|
reg src_overrun;
|
||||||
|
reg [4:0] src_self_test_flags;
|
||||||
|
reg status_req_pulse;
|
||||||
|
|
||||||
|
wire [31:0] status_word_5;
|
||||||
|
|
||||||
|
status_packing_block status_dut (
|
||||||
|
.clk (clk_src),
|
||||||
|
.ft_clk (ft_clk),
|
||||||
|
.reset_n (reset_n),
|
||||||
|
.status_range_decim_watchdog (src_watchdog),
|
||||||
|
.status_ddc_cic_fir_overrun (src_overrun),
|
||||||
|
.status_self_test_flags (src_self_test_flags),
|
||||||
|
.status_req_pulse_ft (status_req_pulse),
|
||||||
|
.status_word_5 (status_word_5)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 100 MHz src clock
|
||||||
|
always #5 clk_src = ~clk_src;
|
||||||
|
// 60 MHz ft_clk (~16.67 ns)
|
||||||
|
always #8 ft_clk = ~ft_clk;
|
||||||
|
|
||||||
|
// ----- bookkeeping -----
|
||||||
|
integer pass = 0;
|
||||||
|
integer fail = 0;
|
||||||
|
|
||||||
|
task check_dig (input [127:0] label, input expected_dig5, input expected_dig7);
|
||||||
|
begin
|
||||||
|
#1; // settle combinational
|
||||||
|
if (dig5 === expected_dig5 && dig7 === expected_dig7) begin
|
||||||
|
$display(" [PASS] %0s: dig5=%b dig7=%b", label, dig5, dig7);
|
||||||
|
pass = pass + 1;
|
||||||
|
end else begin
|
||||||
|
$display(" [FAIL] %0s: dig5=%b (exp %b) dig7=%b (exp %b)",
|
||||||
|
label, dig5, expected_dig5, dig7, expected_dig7);
|
||||||
|
fail = fail + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task check_status (input [127:0] label, input [31:0] mask, input [31:0] expected);
|
||||||
|
begin
|
||||||
|
if ((status_word_5 & mask) === (expected & mask)) begin
|
||||||
|
$display(" [PASS] %0s: word5=%h (masked %h)",
|
||||||
|
label, status_word_5, status_word_5 & mask);
|
||||||
|
pass = pass + 1;
|
||||||
|
end else begin
|
||||||
|
$display(" [FAIL] %0s: word5=%h masked %h (exp %h)",
|
||||||
|
label, status_word_5, status_word_5 & mask, expected & mask);
|
||||||
|
fail = fail + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
task pulse_status_req;
|
||||||
|
begin
|
||||||
|
@(posedge ft_clk); #1;
|
||||||
|
status_req_pulse = 1'b1;
|
||||||
|
@(posedge ft_clk); #1;
|
||||||
|
status_req_pulse = 1'b0;
|
||||||
|
// Allow the registered status_words update to land.
|
||||||
|
@(posedge ft_clk); #1;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$display("============================================================");
|
||||||
|
$display("AUDIT-S10: gpio_dig split + status_words[5][6:5] visibility");
|
||||||
|
$display("============================================================");
|
||||||
|
|
||||||
|
// ---- GROUP A: GPIO split ----
|
||||||
|
agc_saturation_count = 8'd0;
|
||||||
|
ddc_overflow_any = 1'b0;
|
||||||
|
ddc_saturation_count = 3'd0;
|
||||||
|
mti_saturation_count = 8'd0;
|
||||||
|
range_decim_watchdog = 1'b0;
|
||||||
|
ddc_cic_fir_overrun = 1'b0;
|
||||||
|
|
||||||
|
// T1
|
||||||
|
check_dig("T1 all zero", 1'b0, 1'b0);
|
||||||
|
|
||||||
|
// T2 each signal-sat individually
|
||||||
|
agc_saturation_count = 8'd1;
|
||||||
|
check_dig("T2a agc_sat>0", 1'b1, 1'b0);
|
||||||
|
agc_saturation_count = 8'd0;
|
||||||
|
|
||||||
|
ddc_overflow_any = 1'b1;
|
||||||
|
check_dig("T2b ddc_overflow", 1'b1, 1'b0);
|
||||||
|
ddc_overflow_any = 1'b0;
|
||||||
|
|
||||||
|
ddc_saturation_count = 3'd1;
|
||||||
|
check_dig("T2c ddc_sat>0", 1'b1, 1'b0);
|
||||||
|
ddc_saturation_count = 3'd0;
|
||||||
|
|
||||||
|
mti_saturation_count = 8'd1;
|
||||||
|
check_dig("T2d mti_sat>0", 1'b1, 1'b0);
|
||||||
|
mti_saturation_count = 8'd0;
|
||||||
|
|
||||||
|
// T3 each control-fault individually
|
||||||
|
range_decim_watchdog = 1'b1;
|
||||||
|
check_dig("T3a watchdog", 1'b0, 1'b1);
|
||||||
|
range_decim_watchdog = 1'b0;
|
||||||
|
|
||||||
|
ddc_cic_fir_overrun = 1'b1;
|
||||||
|
check_dig("T3b cic_fir_overrun", 1'b0, 1'b1);
|
||||||
|
ddc_cic_fir_overrun = 1'b0;
|
||||||
|
|
||||||
|
// T4 mixed
|
||||||
|
agc_saturation_count = 8'd5;
|
||||||
|
range_decim_watchdog = 1'b1;
|
||||||
|
check_dig("T4 mixed sat+fault", 1'b1, 1'b1);
|
||||||
|
agc_saturation_count = 8'd0;
|
||||||
|
range_decim_watchdog = 1'b0;
|
||||||
|
|
||||||
|
// T5 boundary: largest agc count
|
||||||
|
agc_saturation_count = 8'hFF;
|
||||||
|
check_dig("T5 agc_sat=FF", 1'b1, 1'b0);
|
||||||
|
agc_saturation_count = 8'd0;
|
||||||
|
|
||||||
|
// T6 boundary: ddc_sat=0 stays low
|
||||||
|
ddc_saturation_count = 3'd0;
|
||||||
|
check_dig("T6 ddc_sat=0", 1'b0, 1'b0);
|
||||||
|
|
||||||
|
// ---- GROUP B: status-word CDC packing ----
|
||||||
|
src_watchdog = 1'b0;
|
||||||
|
src_overrun = 1'b0;
|
||||||
|
src_self_test_flags = 5'b00000;
|
||||||
|
status_req_pulse = 1'b0;
|
||||||
|
|
||||||
|
// Apply reset
|
||||||
|
reset_n = 1'b0;
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
reset_n = 1'b1;
|
||||||
|
repeat (3) @(posedge ft_clk);
|
||||||
|
|
||||||
|
// T7 reset state
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T7 reset state",
|
||||||
|
32'h000000E0, // [7:5]
|
||||||
|
32'h00000000);
|
||||||
|
|
||||||
|
// T8 watchdog asserted only
|
||||||
|
@(posedge clk_src); #1;
|
||||||
|
src_watchdog = 1'b1;
|
||||||
|
// give 4 ft_clk for sync chain to settle
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T8 watchdog asserted",
|
||||||
|
32'h00000060, // [6:5]
|
||||||
|
32'h00000020); // [5]=1
|
||||||
|
|
||||||
|
// T9 cic_fir_overrun asserted only (clear watchdog first)
|
||||||
|
@(posedge clk_src); #1;
|
||||||
|
src_watchdog = 1'b0;
|
||||||
|
src_overrun = 1'b1;
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T9 cic_fir_overrun asserted",
|
||||||
|
32'h00000060,
|
||||||
|
32'h00000040); // [6]=1
|
||||||
|
|
||||||
|
// T10 both, then both cleared
|
||||||
|
@(posedge clk_src); #1;
|
||||||
|
src_watchdog = 1'b1;
|
||||||
|
src_overrun = 1'b1;
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T10a both asserted",
|
||||||
|
32'h00000060,
|
||||||
|
32'h00000060); // [6:5]=11
|
||||||
|
|
||||||
|
@(posedge clk_src); #1;
|
||||||
|
src_watchdog = 1'b0;
|
||||||
|
src_overrun = 1'b0;
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T10b both cleared",
|
||||||
|
32'h00000060,
|
||||||
|
32'h00000000);
|
||||||
|
|
||||||
|
// T11 reserved bit [7] stays 0 even when neighbours are 1
|
||||||
|
@(posedge clk_src); #1;
|
||||||
|
src_watchdog = 1'b1;
|
||||||
|
src_overrun = 1'b1;
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T11 [7] reserved stays 0",
|
||||||
|
32'h00000080, // [7] only
|
||||||
|
32'h00000000);
|
||||||
|
|
||||||
|
// T12 self_test_flags pass through unchanged
|
||||||
|
@(posedge clk_src); #1;
|
||||||
|
src_watchdog = 1'b0;
|
||||||
|
src_overrun = 1'b0;
|
||||||
|
src_self_test_flags = 5'b10110;
|
||||||
|
repeat (5) @(posedge ft_clk);
|
||||||
|
pulse_status_req();
|
||||||
|
check_status("T12 self_test_flags untouched",
|
||||||
|
32'h0000001F,
|
||||||
|
32'h00000016);
|
||||||
|
|
||||||
|
$display("============================================================");
|
||||||
|
$display("AUDIT-S10 RESULTS: pass=%0d fail=%0d", pass, fail);
|
||||||
|
$display("============================================================");
|
||||||
|
if (fail == 0) $display("[OVERALL] PASS");
|
||||||
|
else $display("[OVERALL] FAIL");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#1_000_000;
|
||||||
|
$display("[FATAL] timeout");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// gpio_split_block — mirrors the production fragment from radar_system_top.v
|
||||||
|
// post AUDIT-S10. Two combinational ORs:
|
||||||
|
// gpio_dig5 = signal-saturation classes (AGC + DDC + MTI)
|
||||||
|
// gpio_dig7 = control-fault classes (range-decimator watchdog + CIC->FIR
|
||||||
|
// CDC overrun)
|
||||||
|
// ============================================================================
|
||||||
|
module gpio_split_block (
|
||||||
|
input wire [7:0] agc_saturation_count,
|
||||||
|
input wire ddc_overflow_any,
|
||||||
|
input wire [2:0] ddc_saturation_count,
|
||||||
|
input wire [7:0] mti_saturation_count,
|
||||||
|
input wire range_decim_watchdog,
|
||||||
|
input wire ddc_cic_fir_overrun,
|
||||||
|
output wire gpio_dig5,
|
||||||
|
output wire gpio_dig7
|
||||||
|
);
|
||||||
|
assign gpio_dig5 = (agc_saturation_count != 8'd0)
|
||||||
|
| ddc_overflow_any
|
||||||
|
| (ddc_saturation_count != 3'd0)
|
||||||
|
| (mti_saturation_count != 8'd0);
|
||||||
|
assign gpio_dig7 = range_decim_watchdog
|
||||||
|
| ddc_cic_fir_overrun;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// status_packing_block — mirrors the production CDC fragment from
|
||||||
|
// usb_data_interface.v (and usb_data_interface_ft2232h.v) for the AUDIT-S10
|
||||||
|
// telemetry path. Source-domain inputs cross to ft_clk via 2-FF level sync,
|
||||||
|
// then pack into status_words[5][6:5]. Self-test flags pass through into
|
||||||
|
// status_words[5][4:0] for a sanity check that the packing keeps the
|
||||||
|
// neighbouring fields untouched. Bit [7] is intentionally reserved.
|
||||||
|
// ============================================================================
|
||||||
|
module status_packing_block (
|
||||||
|
input wire clk, // 100 MHz radar domain (unused but mirrors prod port list)
|
||||||
|
input wire ft_clk,
|
||||||
|
input wire reset_n,
|
||||||
|
input wire status_range_decim_watchdog,
|
||||||
|
input wire status_ddc_cic_fir_overrun,
|
||||||
|
input wire [4:0] status_self_test_flags,
|
||||||
|
input wire status_req_pulse_ft,
|
||||||
|
output reg [31:0] status_word_5
|
||||||
|
);
|
||||||
|
(* ASYNC_REG = "TRUE" *) reg range_decim_watchdog_sync_0;
|
||||||
|
reg range_decim_watchdog_sync_1;
|
||||||
|
(* ASYNC_REG = "TRUE" *) reg ddc_cic_fir_overrun_sync_0;
|
||||||
|
reg ddc_cic_fir_overrun_sync_1;
|
||||||
|
|
||||||
|
always @(posedge ft_clk or negedge reset_n) begin
|
||||||
|
if (!reset_n) begin
|
||||||
|
range_decim_watchdog_sync_0 <= 1'b0;
|
||||||
|
range_decim_watchdog_sync_1 <= 1'b0;
|
||||||
|
ddc_cic_fir_overrun_sync_0 <= 1'b0;
|
||||||
|
ddc_cic_fir_overrun_sync_1 <= 1'b0;
|
||||||
|
status_word_5 <= 32'd0;
|
||||||
|
end else begin
|
||||||
|
range_decim_watchdog_sync_0 <= status_range_decim_watchdog;
|
||||||
|
range_decim_watchdog_sync_1 <= range_decim_watchdog_sync_0;
|
||||||
|
ddc_cic_fir_overrun_sync_0 <= status_ddc_cic_fir_overrun;
|
||||||
|
ddc_cic_fir_overrun_sync_1 <= ddc_cic_fir_overrun_sync_0;
|
||||||
|
|
||||||
|
if (status_req_pulse_ft) begin
|
||||||
|
status_word_5 <= {7'd0, 1'b0, // [31:24] busy slot tied 0 in TB
|
||||||
|
8'd0, // [23:16] reserved
|
||||||
|
8'd0, // [15:8] detail tied 0 in TB
|
||||||
|
1'd0, // [7] reserved
|
||||||
|
ddc_cic_fir_overrun_sync_1, // [6]
|
||||||
|
range_decim_watchdog_sync_1, // [5]
|
||||||
|
status_self_test_flags}; // [4:0]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
@@ -141,7 +141,10 @@ module tb_ft2232h_frame_drop;
|
|||||||
.status_agc_current_gain(status_agc_current_gain),
|
.status_agc_current_gain(status_agc_current_gain),
|
||||||
.status_agc_peak_magnitude(status_agc_peak_magnitude),
|
.status_agc_peak_magnitude(status_agc_peak_magnitude),
|
||||||
.status_agc_saturation_count(status_agc_saturation_count),
|
.status_agc_saturation_count(status_agc_saturation_count),
|
||||||
.status_agc_enable(status_agc_enable)
|
.status_agc_enable(status_agc_enable),
|
||||||
|
// AUDIT-S10: control-fault flags tied off (frame-drop TB scope)
|
||||||
|
.status_range_decim_watchdog(1'b0),
|
||||||
|
.status_ddc_cic_fir_overrun(1'b0)
|
||||||
);
|
);
|
||||||
|
|
||||||
task pulse_frame_complete;
|
task pulse_frame_complete;
|
||||||
|
|||||||
@@ -144,7 +144,10 @@ module tb_usb_data_interface;
|
|||||||
.status_agc_current_gain (status_agc_current_gain),
|
.status_agc_current_gain (status_agc_current_gain),
|
||||||
.status_agc_peak_magnitude (status_agc_peak_magnitude),
|
.status_agc_peak_magnitude (status_agc_peak_magnitude),
|
||||||
.status_agc_saturation_count(status_agc_saturation_count),
|
.status_agc_saturation_count(status_agc_saturation_count),
|
||||||
.status_agc_enable (status_agc_enable)
|
.status_agc_enable (status_agc_enable),
|
||||||
|
// AUDIT-S10: control-fault flags tied off (pre-existing TB scope)
|
||||||
|
.status_range_decim_watchdog(1'b0),
|
||||||
|
.status_ddc_cic_fir_overrun (1'b0)
|
||||||
);
|
);
|
||||||
|
|
||||||
// ── Test bookkeeping ───────────────────────────────────────
|
// ── Test bookkeeping ───────────────────────────────────────
|
||||||
|
|||||||
@@ -103,7 +103,15 @@ module usb_data_interface (
|
|||||||
input wire [3:0] status_agc_current_gain,
|
input wire [3:0] status_agc_current_gain,
|
||||||
input wire [7:0] status_agc_peak_magnitude,
|
input wire [7:0] status_agc_peak_magnitude,
|
||||||
input wire [7:0] status_agc_saturation_count,
|
input wire [7:0] status_agc_saturation_count,
|
||||||
input wire status_agc_enable
|
input wire status_agc_enable,
|
||||||
|
|
||||||
|
// AUDIT-S10: control-fault flags (clk domain). Exposed in status_words[5]
|
||||||
|
// [6:5] so host-side telemetry can graph each fault class independently
|
||||||
|
// of the gpio_dig7 split (which only the MCU observes). Both flags are
|
||||||
|
// sticky/slow-changing in the source domain (set on event, cleared by
|
||||||
|
// monitor reset), so 2-stage level CDC into ft601_clk_in is sufficient.
|
||||||
|
input wire status_range_decim_watchdog, // audit F-6.4
|
||||||
|
input wire status_ddc_cic_fir_overrun // audit F-1.2
|
||||||
);
|
);
|
||||||
|
|
||||||
// USB packet structure (same as before)
|
// USB packet structure (same as before)
|
||||||
@@ -314,6 +322,13 @@ wire stream_cfar_en = stream_ctrl_sync_1[2];
|
|||||||
// NOTE: status_req_toggle_100m declared above (before source-domain always block)
|
// NOTE: status_req_toggle_100m declared above (before source-domain always block)
|
||||||
(* ASYNC_REG = "TRUE" *) reg [1:0] status_req_sync;
|
(* ASYNC_REG = "TRUE" *) reg [1:0] status_req_sync;
|
||||||
reg status_req_sync_prev;
|
reg status_req_sync_prev;
|
||||||
|
|
||||||
|
// AUDIT-S10: 2-stage level CDC for control-fault flags (clk → ft601_clk_in).
|
||||||
|
// Sticky/slow-changing in source domain so 2-FF sync is sufficient.
|
||||||
|
(* ASYNC_REG = "TRUE" *) reg range_decim_watchdog_sync_0;
|
||||||
|
reg range_decim_watchdog_sync_1;
|
||||||
|
(* ASYNC_REG = "TRUE" *) reg ddc_cic_fir_overrun_sync_0;
|
||||||
|
reg ddc_cic_fir_overrun_sync_1;
|
||||||
wire status_req_ft601 = status_req_sync[1] ^ status_req_sync_prev;
|
wire status_req_ft601 = status_req_sync[1] ^ status_req_sync_prev;
|
||||||
|
|
||||||
// Status snapshot: captured in ft601_clk domain when status request arrives.
|
// Status snapshot: captured in ft601_clk domain when status request arrives.
|
||||||
@@ -346,6 +361,11 @@ always @(posedge ft601_clk_in or negedge ft601_effective_reset_n) begin
|
|||||||
status_req_sync <= 2'b00;
|
status_req_sync <= 2'b00;
|
||||||
status_req_sync_prev <= 1'b0;
|
status_req_sync_prev <= 1'b0;
|
||||||
status_word_idx <= 3'd0;
|
status_word_idx <= 3'd0;
|
||||||
|
// AUDIT-S10: control-fault flag CDC reset
|
||||||
|
range_decim_watchdog_sync_0 <= 1'b0;
|
||||||
|
range_decim_watchdog_sync_1 <= 1'b0;
|
||||||
|
ddc_cic_fir_overrun_sync_0 <= 1'b0;
|
||||||
|
ddc_cic_fir_overrun_sync_1 <= 1'b0;
|
||||||
end else begin
|
end else begin
|
||||||
// Synchronize valid strobes (2-stage sync chain)
|
// Synchronize valid strobes (2-stage sync chain)
|
||||||
range_valid_sync <= {range_valid_sync[0], range_valid};
|
range_valid_sync <= {range_valid_sync[0], range_valid};
|
||||||
@@ -360,6 +380,12 @@ always @(posedge ft601_clk_in or negedge ft601_effective_reset_n) begin
|
|||||||
status_req_sync <= {status_req_sync[0], status_req_toggle_100m};
|
status_req_sync <= {status_req_sync[0], status_req_toggle_100m};
|
||||||
status_req_sync_prev <= status_req_sync[1];
|
status_req_sync_prev <= status_req_sync[1];
|
||||||
|
|
||||||
|
// AUDIT-S10: control-fault flag CDC (clk → ft601_clk_in, 2-stage)
|
||||||
|
range_decim_watchdog_sync_0 <= status_range_decim_watchdog;
|
||||||
|
range_decim_watchdog_sync_1 <= range_decim_watchdog_sync_0;
|
||||||
|
ddc_cic_fir_overrun_sync_0 <= status_ddc_cic_fir_overrun;
|
||||||
|
ddc_cic_fir_overrun_sync_1 <= ddc_cic_fir_overrun_sync_0;
|
||||||
|
|
||||||
// Gap 2: Capture status snapshot when request arrives in ft601 domain
|
// Gap 2: Capture status snapshot when request arrives in ft601 domain
|
||||||
if (status_req_ft601) begin
|
if (status_req_ft601) begin
|
||||||
// Pack register values into 5x 32-bit status words
|
// Pack register values into 5x 32-bit status words
|
||||||
@@ -380,10 +406,17 @@ always @(posedge ft601_clk_in or negedge ft601_effective_reset_n) begin
|
|||||||
status_chirps_mismatch, // [10] TX-G mismatch flag
|
status_chirps_mismatch, // [10] TX-G mismatch flag
|
||||||
8'd0, // [9:2] reserved
|
8'd0, // [9:2] reserved
|
||||||
status_range_mode}; // [1:0]
|
status_range_mode}; // [1:0]
|
||||||
// Word 5: Self-test results {reserved[6:0], busy, reserved[7:0], detail[7:0], reserved[2:0], flags[4:0]}
|
// Word 5: {reserved[6:0], self_test_busy[24], reserved[23:16],
|
||||||
|
// self_test_detail[15:8], reserved[7], cic_fir_overrun[6],
|
||||||
|
// range_decim_watchdog[5], self_test_flags[4:0]}
|
||||||
|
// AUDIT-S10: bits [6:5] expose control-fault classes that route
|
||||||
|
// to gpio_dig7 — gives host visibility regardless of MCU consumption.
|
||||||
status_words[5] <= {7'd0, status_self_test_busy,
|
status_words[5] <= {7'd0, status_self_test_busy,
|
||||||
8'd0, status_self_test_detail,
|
8'd0, status_self_test_detail,
|
||||||
3'd0, status_self_test_flags};
|
1'd0, // [7] reserved
|
||||||
|
ddc_cic_fir_overrun_sync_1, // [6] audit F-1.2
|
||||||
|
range_decim_watchdog_sync_1, // [5] audit F-6.4
|
||||||
|
status_self_test_flags}; // [4:0]
|
||||||
end
|
end
|
||||||
|
|
||||||
// Delayed version of sync[1] for edge detection
|
// Delayed version of sync[1] for edge detection
|
||||||
|
|||||||
@@ -163,7 +163,14 @@ module usb_data_interface_ft2232h (
|
|||||||
input wire [3:0] status_agc_current_gain,
|
input wire [3:0] status_agc_current_gain,
|
||||||
input wire [7:0] status_agc_peak_magnitude,
|
input wire [7:0] status_agc_peak_magnitude,
|
||||||
input wire [7:0] status_agc_saturation_count,
|
input wire [7:0] status_agc_saturation_count,
|
||||||
input wire status_agc_enable
|
input wire status_agc_enable,
|
||||||
|
|
||||||
|
// AUDIT-S10: control-fault flags (clk domain). Exposed in status_words[5]
|
||||||
|
// [6:5] so host-side telemetry can graph each fault class independently
|
||||||
|
// of the gpio_dig7 split. 2-stage level CDC into ft_clk; sticky/slow-
|
||||||
|
// changing source so 2-FF sync is sufficient.
|
||||||
|
input wire status_range_decim_watchdog, // audit F-6.4
|
||||||
|
input wire status_ddc_cic_fir_overrun // audit F-1.2
|
||||||
);
|
);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -594,6 +601,13 @@ wire status_req_ft = status_toggle_sync[2] ^ status_toggle_prev;
|
|||||||
(* ASYNC_REG = "TRUE" *) reg [6:0] frame_drop_sync_0;
|
(* ASYNC_REG = "TRUE" *) reg [6:0] frame_drop_sync_0;
|
||||||
reg [6:0] frame_drop_sync_1;
|
reg [6:0] frame_drop_sync_1;
|
||||||
|
|
||||||
|
// --- AUDIT-S10: control-fault flag CDC (clk → ft_clk, 2-stage level sync) ---
|
||||||
|
// Sticky/slow-changing in source domain so 2-FF sync is sufficient.
|
||||||
|
(* ASYNC_REG = "TRUE" *) reg range_decim_watchdog_sync_0;
|
||||||
|
reg range_decim_watchdog_sync_1;
|
||||||
|
(* ASYNC_REG = "TRUE" *) reg ddc_cic_fir_overrun_sync_0;
|
||||||
|
reg ddc_cic_fir_overrun_sync_1;
|
||||||
|
|
||||||
wire stream_range_en = stream_ctrl_sync_1[0];
|
wire stream_range_en = stream_ctrl_sync_1[0];
|
||||||
wire stream_doppler_en = stream_ctrl_sync_1[1];
|
wire stream_doppler_en = stream_ctrl_sync_1[1];
|
||||||
wire stream_cfar_en = stream_ctrl_sync_1[2];
|
wire stream_cfar_en = stream_ctrl_sync_1[2];
|
||||||
@@ -708,6 +722,11 @@ always @(posedge ft_clk or negedge ft_effective_reset_n) begin
|
|||||||
stream_ctrl_sync_1 <= `RP_STREAM_CTRL_DEFAULT;
|
stream_ctrl_sync_1 <= `RP_STREAM_CTRL_DEFAULT;
|
||||||
frame_drop_sync_0 <= 7'd0;
|
frame_drop_sync_0 <= 7'd0;
|
||||||
frame_drop_sync_1 <= 7'd0;
|
frame_drop_sync_1 <= 7'd0;
|
||||||
|
// AUDIT-S10: control-fault flag CDC reset
|
||||||
|
range_decim_watchdog_sync_0 <= 1'b0;
|
||||||
|
range_decim_watchdog_sync_1 <= 1'b0;
|
||||||
|
ddc_cic_fir_overrun_sync_0 <= 1'b0;
|
||||||
|
ddc_cic_fir_overrun_sync_1 <= 1'b0;
|
||||||
for (si = 0; si < 6; si = si + 1)
|
for (si = 0; si < 6; si = si + 1)
|
||||||
status_words[si] <= 32'd0;
|
status_words[si] <= 32'd0;
|
||||||
wr_state <= WR_IDLE;
|
wr_state <= WR_IDLE;
|
||||||
@@ -752,6 +771,12 @@ always @(posedge ft_clk or negedge ft_effective_reset_n) begin
|
|||||||
frame_drop_sync_0 <= frame_drop_count;
|
frame_drop_sync_0 <= frame_drop_count;
|
||||||
frame_drop_sync_1 <= frame_drop_sync_0;
|
frame_drop_sync_1 <= frame_drop_sync_0;
|
||||||
|
|
||||||
|
// AUDIT-S10: control-fault flag CDC (clk → ft_clk for status read)
|
||||||
|
range_decim_watchdog_sync_0 <= status_range_decim_watchdog;
|
||||||
|
range_decim_watchdog_sync_1 <= range_decim_watchdog_sync_0;
|
||||||
|
ddc_cic_fir_overrun_sync_0 <= status_ddc_cic_fir_overrun;
|
||||||
|
ddc_cic_fir_overrun_sync_1 <= ddc_cic_fir_overrun_sync_0;
|
||||||
|
|
||||||
// Status snapshot on request
|
// Status snapshot on request
|
||||||
if (status_req_ft) begin
|
if (status_req_ft) begin
|
||||||
// Word 0: {0xFF, mode[1:0], stream[5:0], threshold[15:0]}
|
// Word 0: {0xFF, mode[1:0], stream[5:0], threshold[15:0]}
|
||||||
@@ -768,13 +793,19 @@ always @(posedge ft_clk or negedge ft_effective_reset_n) begin
|
|||||||
status_chirps_mismatch, // [10] TX-G mismatch flag
|
status_chirps_mismatch, // [10] TX-G mismatch flag
|
||||||
8'd0, // [9:2] reserved
|
8'd0, // [9:2] reserved
|
||||||
status_range_mode}; // [1:0]
|
status_range_mode}; // [1:0]
|
||||||
// AUDIT-C12: frame_drop_count exposed at status_words[5][31:25]
|
// Word 5: {frame_drop_count[31:25], self_test_busy[24],
|
||||||
// (was 7'd0 reserved). Saturates at 127. Counts frame_complete
|
// reserved[23:16], self_test_detail[15:8], reserved[7],
|
||||||
// events that arrived while previous frame was still in WR_FSM
|
// cic_fir_overrun[6], range_decim_watchdog[5],
|
||||||
// transit (silent frame drop indicator for host visibility).
|
// self_test_flags[4:0]}
|
||||||
|
// AUDIT-C12: bits [31:25] = frame_drop_count (silent frame drops).
|
||||||
|
// AUDIT-S10: bits [6:5] expose control-fault classes that route to
|
||||||
|
// gpio_dig7 — gives host visibility regardless of MCU consumption.
|
||||||
status_words[5] <= {frame_drop_sync_1, status_self_test_busy,
|
status_words[5] <= {frame_drop_sync_1, status_self_test_busy,
|
||||||
8'd0, status_self_test_detail,
|
8'd0, status_self_test_detail,
|
||||||
3'd0, status_self_test_flags};
|
1'd0, // [7] reserved
|
||||||
|
ddc_cic_fir_overrun_sync_1, // [6] audit F-1.2
|
||||||
|
range_decim_watchdog_sync_1, // [5] audit F-6.4
|
||||||
|
status_self_test_flags}; // [4:0]
|
||||||
end
|
end
|
||||||
|
|
||||||
// ================================================================
|
// ================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user