Commit Graph

58 Commits

Author SHA1 Message Date
Jason 2539d46d93 merge: resolve conflicts with develop (supersede by PR #89 / #107)
Three conflicts — all resolved in favor of develop, which has a more
refined version of the same work this branch introduced:

- radar_system_top.v: develop's cleaner USB_MODE=1 comment (same value).
- run_regression.sh: develop's ${SYSTEM_RTL[@]} refactor + added
  USB_MODE=1 test variants.
- tb/radar_system_tb.v: develop's ifdef USB_MODE_1 to dump the correct
  USB instance based on mode.

The 400 MHz reset fan-out fix (nco_400m_enhanced, cic_decimator_4x_enhanced,
ddc_400m) and ADAR1000 channel-indexing fix remain intact on this branch.
2026-04-19 16:28:07 +05:45
Jason d0b3a4c969 fix(fpga): registered reset fan-out at 400 MHz; default USB to FT2232H
Replace direct !reset_n async sense with a registered active-high reset_h
(max_fanout=50) in nco_400m_enhanced, cic_decimator_4x_enhanced, and
ddc_400m.  The prior single-LUT1 / 700+ load net was the root cause of
WNS=-0.626 ns in the 400 MHz clock domain on the xc7a50t build.  Vivado
replicates the constrained register into ≈14 regional copies, each driving
≤50 loads, closing timing at 2.5 ns.

Change radar_system_top default USB_MODE from 0 (FT601) to 1 (FT2232H).
FT601 remains available for the 200T premium board via explicit parameter
override; the 50T production wrapper already hard-codes USB_MODE=1.

Regression: add usb_data_interface_ft2232h.v to PROD_RTL lint list and
both system-top TB compile commands; fix legacy radar_system_tb hierarchical
probe from gen_ft601.usb_inst to gen_ft2232h.usb_inst.

Golden reference files (rtl_bb_dc.csv, rx_final_doppler_out.csv,
golden_doppler.mem) regenerated to reflect the +1-cycle registered-reset
boundary behaviour; Receiver golden-compare passes 18/18 checks.

All 25 regression tests pass (0 failures, 0 skipped).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 20:34:52 +05:45
NawfalMotii79 d3476139e3 Merge pull request #89 from NawfalMotii79/feat/ft2232h-default-ft601-option
feat: make FT2232H default USB interface, add FT601 premium option, deprecate GUI V6
2026-04-17 22:21:58 +01:00
Jason ade1497457 Merge pull request #79 from NawfalMotii79/feat/um982-gps-driver
feat: UM982 GPS driver + deferred fixes (STM32-006, STM32-004, FPGA-001)
2026-04-16 13:54:40 +03:00
Jason f393e96d69 feat(fpga): make FT2232H default USB interface, rewrite FT601 write FSM, add clock-loss watchdog
- Set USB_MODE default to 1 (FT2232H) in radar_system_top.v; 200T build
  overrides to USB_MODE=0 via build_200t.tcl generic property
- Rewrite FT601 write FSM: 4-state architecture with 3-word packed data,
  pending-flag gating, and frame sync counter
- Add FT2232H read FSM rd_cmd_complete flag, stream field zeroing, and
  range_data_ready 1-cycle pipeline delay in both USB modules
- Implement clock-loss watchdog: ft_heartbeat toggle + 16-bit timeout
  counter drives ft_clk_lost, feeding ft_effective_reset_n via 2-stage
  ASYNC_REG synchronizer chain
- Fix sample_counter reset literal width (11'd0 -> 12'd0)
- Add FT2232H I/O timing constraints to 50T XDC; fix dac_clk comments
- Document vestigial ft601_txe_n/rxf_n ports (needed for 200T XDC)
- Tie off AGC ports on TE0713 dev wrapper
- Rewrite tb_usb_data_interface.v for new 4-state FSM (89 checks)
- Add USB_MODE=1 regression runs; remove dead CHECK 5/6 loop
- Update diag_log.h USB interface comment
2026-04-16 16:18:52 +05:45
Jason 15a9cde274 review(cosim): fix stale comment and wrong docstring derivation
golden_reference.py: update comment from 'Simplified' to 'Exact' to
match shaun0927's corrected formula.

fpga_model.py: fix adc_to_signed docstring that incorrectly derived
0x7F80 instead of 0xFF00. Verilog '/' binds tighter than '-', so
{1'b0,8'hFF,9'b0}/2 = 0x1FE00/2 = 0xFF00, not 0xFF<<8 = 0x7F80.
2026-04-16 11:07:56 +05:45
JunghwanNA a9ceb3c851 fix(cosim): align golden_reference ADC sign conversion with RTL
The golden reference used (adc_val - 128) << 9 which subtracts 65536,
but the Verilog RTL computes {1'b0,adc,9'b0} - {1'b0,8'hFF,9'b0}/2
which subtracts 0xFF00 = 65280. This creates a constant 256-LSB DC
offset between the golden reference and RTL for all 256 ADC values.

The bit-accurate model in fpga_model.py already uses the correct RTL
formula. This aligns golden_reference.py to match.

Verified: all 256 ADC input values now produce zero offset against
fpga_model.py.
2026-04-16 12:27:02 +09:00
Jason db4e73577e fix: use authoritative tx frame signal for frame sync, consistent ad9523 error path
FPGA-001: The previous fix derived frame boundaries from chirp_counter==0,
but that counter comes from plfm_chirp_controller_enhanced which overflows
to N (not wrapping at chirps_per_elev). This caused frame pulses only on
6-bit rollover (every 64 chirps) instead of every N chirps. Now wires the
CDC-synchronized tx_new_chirp_frame_sync signal from the transmitter into
radar_receiver_final, giving correct per-frame timing for any N.

STM32-004: Changed ad9523_init() failure path from Error_Handler() to
return -1, matching the pattern used by ad9523_setup() and ad9523_status()
in the same function. Both halt the system, but return -1 keeps IRQs
enabled for diagnostic output.
2026-04-16 00:33:27 +05:45
Jason 063fa081fe fix: FPGA timing margins (WNS +0.002→+0.080ns) + 11 bug fixes from code review
FPGA timing (400MHz domain WNS: +0.339ns, was +0.002ns):
- DONT_TOUCH on BUFG to prevent AggressiveExplore cascade replication
- NCO→mixer pipeline registers break critical 1.5ns route
- Clock uncertainty reduced 200ps→100ps (adequate guardband)
- Updated golden/cosim references for +1 cycle pipeline latency

STM32 bug fixes:
- Guard uint32_t underflow in processStartFlag (length<4)
- Replace unbounded strcat in getSystemStatusForGUI with snprintf
- Early-return error masking in checkSystemHealth
- Add HAL_Delay in emergency blink loop

GUI bug fixes:
- Remove 0x03 from _HARDWARE_ONLY_OPCODES (was in both sets)
- Wire real error count in V7 diagnostics panel
- Fix _stop_demo showing 'Live' label during replay mode

FPGA comment fixes + CI: add test_v7.py to pytest command

Vivado build 50t passed: 0 failing endpoints, WHS=+0.056ns
2026-04-14 00:08:26 +05:45
Jason b4d1869582 fix: 9 bugs from code review — RTL sign-ext & snapshot, thread safety, protocol fixes
- rx_gain_control.v: sign-extension fix ({agc_gain[3],agc_gain} not {1'b0,agc_gain})
  + inclusive frame_boundary snapshot via combinational helpers (Bug #7)
- v7/dashboard.py: Qt thread-safe logging via pyqtSignal bridge (Bug #1)
  + table headers corrected to 'Range (m)' / 'Velocity (m/s)' (Bug #2)
- main.cpp: guard outerAgc.applyGain() with if(outerAgc.enabled) (Bug #3)
- radar_protocol.py: replay L1 threshold detection when CFAR disabled (Bug #4)
  + IndexError guard in replay open (Bug #5) + AGC opcodes in _HARDWARE_ONLY_OPCODES
- radar_dashboard.py: AGC monitor attribute name fixes (3 labels)
- tb_rx_gain_control.v: Tests 17-19 (sign-ext, simultaneous valid+boundary, enable toggle)
- tb_cross_layer_ft2232h.v: AGC opcode vectors 0x28-0x2C in Exercise A (Bug #6)

Vivado 50T build verified: WNS=+0.002ns, WHS=+0.028ns — all timing constraints met.
All tests pass: MCU 21/21, GUI 120/120, cross-layer 29/29, FPGA 25/25 (68 checks).
2026-04-13 23:35:10 +05:45
Jason ffba27a10a feat: hybrid AGC (FPGA phases 1-3 + GUI phase 6) with timing fix
FPGA:
- rx_gain_control.v rewritten: per-frame peak/saturation tracking,
  auto-shift AGC with attack/decay/holdoff, signed gain -7 to +7
- New registers 0x28-0x2C (agc_enable/target/attack/decay/holdoff)
- status_words[4] carries AGC metrics (gain, peak, sat_count, enable)
- DIG_5 GPIO outputs saturation flag for STM32 outer loop
- Both USB interfaces (FT601 + FT2232H) updated with AGC status ports

Timing fix (WNS +0.001ns -> +0.045ns, 45x improvement):
- CIC max_fanout 4->16 on valid pipeline registers
- +200ps setup uncertainty on 400MHz domain
- ExtraNetDelay_high placement + AggressiveExplore routing

GUI:
- AGC opcodes + status parsing in radar_protocol.py
- AGC control groups in both tkinter and V7 PyQt dashboards
- 11 new AGC tests (103/103 GUI tests pass)

Cross-layer:
- AGC opcodes/defaults/status assertions added (29/29 pass)
- contract_parser.py: fixed comment stripping in concat parser

All tests green: 25 FPGA + 103 GUI + 29 cross-layer = 157 pass
2026-04-13 19:24:11 +05:45
Jason 2106e24952 fix: enforce strict ruff lint (17 rule sets) across entire repo
- Expand ruff config from E/F to 17 rule sets (B, RUF, SIM, PIE, T20,
  ARG, ERA, A, BLE, RET, ISC, TCH, UP, C4, PERF)
- Fix 907 lint errors across all Python files (GUI, FPGA cosim,
  schematics scripts, simulations, utilities, tools)
- Replace all blind except-Exception with specific exception types
- Remove commented-out dead code (ERA001) from cosim/simulation files
- Modernize typing: deprecated typing.List/Dict/Tuple to builtins
- Fix unused args/loop vars, ambiguous unicode, perf anti-patterns
- Delete legacy GUI files V1-V4
- Add V7 test suite, requirements files
- All CI jobs pass: ruff (0 errors), py_compile, pytest (92/92),
  MCU tests (20/20), FPGA regression (25/25)
2026-04-12 14:21:03 +05:45
Jason 519c95f452 fix: regenerate golden hex for dual-16pt Doppler and add real-data TBs to regression
Regenerate all real-data golden reference hex files against the current
dual 16-point FFT Doppler architecture (staggered-PRI sub-frames).
The old hex files were generated against the previous 32-point single-FFT
architecture and caused 2048/2048 mismatches in both strict real-data TBs.

Changes:
- Regenerate doppler_ref_i/q.hex, fullchain_doppler_ref_i/q.hex, and all
  downstream golden files (MTI, DC notch, CFAR) via golden_reference.py
- Add tb_doppler_realdata (exact-match, ADI CN0566 data) to regression
- Add tb_fullchain_realdata (exact-match, decim->Doppler chain) to regression
- Both TBs now pass: 2048/2048 bins exact match, MAX_ERROR=0
- Update CI comment: 23 -> 25 testbenches
- Fill in STALE_NOTICE.md with regeneration instructions

Regression: 25/25 pass, 0 fail, 0 skip. ruff check: 0 errors.
2026-04-09 02:36:14 +03:00
Jason 11aa590cf2 fix: full-repo ruff lint cleanup and CI migration to uv
Resolve all 374 ruff errors across 36 Python files (E501, E702, E722,
E741, F821, F841, invalid-syntax) bringing `ruff check .` to zero
errors repo-wide with line-length=100.

Rewrite CI workflow to use uv for dependency management, whole-repo
`ruff check .`, py_compile syntax gate, and merged python-tests job.
Add pyproject.toml with ruff config and uv dependency groups.

CI structure proposed by hcm444.
2026-04-09 02:05:34 +03:00
Jason 57de32b172 fix: resolve all ruff lint errors across V6+ GUIs, v7 module, and FPGA cosim scripts
Fixes 25 remaining manual lint errors after auto-fix pass (94 auto-fixed earlier):
- GUI_V6.py: noqa on availability imports, bare except, unused vars, F811 redefs
- GUI_V6_Demo.py: unused app variable
- v7/models.py: noqa F401 on 8 try/except availability-check imports
- FPGA cosim: unused header/status/span vars, ambiguous 'l' renamed to 'line',
  E701 while-on-one-line split, F841 padding vars annotated

Also adds v7/ module, GUI_PyQt_Map.py, and GUI_V7_PyQt.py to version control.
Expands CI lint job to cover all 21 maintained Python files (was 4).

All 58 Python tests pass. Zero ruff errors on all target files.
2026-04-08 19:11:40 +03:00
Jason 408f4d126f feat(usb): add FT2232H USB 2.0 interface for 50T production board
Replace FT601 (USB 3.0, 32-bit) with FT2232H (USB 2.0, 8-bit) on the
50T production board per updated Eagle schematic (commit 0db0e7b).
USB 3.0 via FT601 remains available on the 200T premium board.

RTL changes:
- Add usb_data_interface_ft2232h.v: 245 Sync FIFO interface with toggle
  CDC (3-stage) for reliable 100MHz->60MHz clock domain crossing,
  mux-based byte serialization for 11-byte data packets, 26-byte status
  packets, and 4-byte sequential command read FSM
- Add USB_MODE parameter to radar_system_top.v with generate block:
  USB_MODE=0 selects FT601 (200T), USB_MODE=1 selects FT2232H (50T)
- Wire FT2232H ports in radar_system_top_50t.v with USB_MODE=1 override,
  connect ft_clkout to shared clock input port
- Add post-DSP retiming register in ddc_400m.v to fix marginal 400MHz
  timing path (WNS improved from +0.070ns to +0.088ns)

Constraints:
- Add FT2232H pin assignments for all 15 signals on Bank 35 (LVCMOS33)
- Add 60MHz ft_clkout clock constraint (16.667ns) on MRCC N-type pin C4
- Add CLOCK_DEDICATED_ROUTE FALSE for N-type MRCC workaround
- Add CDC false paths between ft_clkout and clk_100m/clk_120m_dac

Build scripts:
- Add PLIO-9 DRC demotion and CLOCK_DEDICATED_ROUTE property in build_50t.tcl
- Add usb_data_interface_ft2232h.v to build_200t.tcl explicit file list

Python host:
- Add FT2232HConnection class using pyftdi SyncFIFO (VID 0x0403:0x6010)
- Add compact 11-byte packet parser for FT2232H data packets
- Update RadarAcquisition to support both FT601 and FT2232H connections

Test results:
- iverilog regression: 23/23 PASS
- Vivado Build 15 (XC7A50T): WNS=+0.088ns, WHS=+0.059ns, 0 violations
- DSP48E1: 112/120 (93.3%), LUTs: 10,060/32,600 (30.9%)
2026-04-07 19:22:16 +03:00
Jason 1e284767cd fix(test,docs): remove dead xfft_32 files, update test infra for dual-16 FFT, add regression guide
- Remove xfft_32.v, tb_xfft_32.v, and fft_twiddle_32.mem (dead code
  since PR #33 moved Doppler to dual 16-pt FFT architecture)
- Update run_regression.sh: xfft_16 in PROD_RTL, remove xfft_32 from
  EXTRA_RTL and all compile commands
- Update tb_fft_engine.v to test with N=16 / fft_twiddle_16.mem
- Update validate_mem_files.py: validate fft_twiddle_16.mem instead of 32
- Update testbenches and golden data from main_cleanup branch to match
  dual-16 architecture (tb_doppler_cosim, tb_doppler_realdata,
  tb_fullchain_realdata, tb_fullchain_mti_cfar_realdata, tb_system_e2e,
  radar_receiver_final, golden_doppler.mem)
- Update CONTRIBUTING.md with full regression test instructions covering
  FPGA, MCU, GUI, co-simulation, and formal verification

Regression: 23/23 FPGA, 20/20 MCU, 57/58 GUI, 56/56 mem validation,
all co-sim scenarios PASS.
2026-04-07 02:51:48 +03:00
Serhii ffc89f0bbd fix(rtl,gui,cosim,formal): adapt surrounding files for dual 16-pt FFT (follow-up to PR #33)
- radar_system_top.v: DC notch now masks to dop_bin[3:0] per sub-frame so both sub-frames get their DC zeroed correctly; rename DOPPLER_FFT_SIZE → DOPPLER_FRAME_CHIRPS to avoid confusion with the per-FFT size (now 16)
- radar_dashboard.py: remove fftshift (crosses sub-frame boundary), display raw Doppler bins, remove dead velocity constants
- golden_reference.py: model dual 16-pt FFT with per-sub-frame Hamming window, update DC notch and CFAR to match RTL
- fv_doppler_processor.sby: reference xfft_16.v / fft_twiddle_16.mem, raise BMC depth to 512 and cover to 1024
- fv_radar_mode_controller.sby: raise cover depth to 600
- fv_radar_mode_controller.v: pin cfg_* to reduced constants (documented as single-config proof), fix Property 5 mode guard, strengthen Cover 1
- STALE_NOTICE.md: document that real-data hex files are stale and need regeneration with external dataset

Closes #39
2026-04-06 23:15:50 +03:00
Jason a577b7628b Fix staggered-PRF Doppler processing with dual 16-point FFTs 2026-03-27 23:05:28 +02:00
Jason 4985eccbae Wire self-test results (0x31) to USB status readback path, add fpga_self_test to regression
- usb_data_interface.v: Add 3 self-test status inputs, expand status packet
  from 7 words (header + 5 data + footer) to 8 words (header + 6 data + footer).
  New status_words[5] carries {busy, detail[7:0], flags[4:0]}.
- radar_system_top.v: Wire self_test_flags_latched, self_test_detail_latched,
  self_test_busy to usb_data_interface ports. Add opcode 0x31 as status
  readback alias so host can read self-test results.
- tb_usb_data_interface.v: Add self-test port connections, verify word 5 in
  Group 16, add Group 18 (busy flag + partial failure variant). 81 checks pass.
- run_regression.sh: Add fpga_self_test.v to PROD_RTL lint list and system-
  level compile lists. Add tb_fpga_self_test as Phase 1 unit test.
- 24/24 regression tests pass, lint clean (0 errors, 4 advisory warnings).
2026-03-20 20:03:11 +02:00
Jason f8d80cc96e Add radar dashboard GUI with replay mode for real ADI CN0566 data visualization, FPGA self-test module, and co-sim npy arrays 2026-03-20 19:02:06 +02:00
Jason 7a44f19432 Full-chain MTI+CFAR real-data co-simulation: bit-exact match across all 10247 checkpoints (decim->MTI->Doppler->DC notch->CFAR) using ADI CN0566 data 2026-03-20 17:16:12 +02:00
Jason ed629e7559 Integrate MTI canceller and DC notch filter for ground clutter removal
MTI canceller (2-pulse, H(z)=1-z^{-1}) between range decimator and
Doppler processor. Subtracts previous chirp from current, nulling DC
Doppler (stationary clutter). Pass-through when host_mti_enable=0.

DC notch filter (post-Doppler, pre-CFAR) zeros bins within
+/-host_dc_notch_width of DC. Complements MTI for residual clutter.

New host registers: 0x26 (mti_enable), 0x27 (dc_notch_width).
Both default to 0 (disabled) - fully backward-compatible.

Verification: 23/23 regression, 29/29 MTI standalone, 3/3 real-data
co-sim (5137/5137 exact match) all PASS.
2026-03-20 16:39:17 +02:00
Jason f71923b67d Integrate CA-CFAR detector: replace fixed-threshold comparator with adaptive sliding-window CFAR engine (22/22 regression PASS)
- Add cfar_ca.v: CA/GO/SO-CFAR with BRAM magnitude buffer, host-configurable
  guard cells, training cells, alpha multiplier, and mode selection
- Replace old threshold detector block in radar_system_top.v with cfar_ca
  instantiation; backward-compatible (cfar_enable defaults to 0)
- Add 5 new host registers: guard (0x21), train (0x22), alpha (0x23),
  mode (0x24), enable (0x25)
- Expose doppler_frame_done_out from radar_receiver_final for CFAR frame sync
- Add tb_cfar_ca.v standalone testbench (14 tests, 24 checks)
- Add Group 14 E2E tests: 13 checks covering range-mode (0x20) and all
  CFAR config registers (0x21-0x25) through full USB command path
- Update run_regression.sh with CFAR in lint, Phase 1, and integration compiles
2026-03-20 04:57:34 +02:00
Jason e93bc33c6c Production fixes 1-7: detection bugs, cfar→threshold rename, digital gain control, Doppler mismatch protection, decimator watchdog, bypass_mode dead code removal, range-mode register (21/21 regression PASS)
Fix 1: Combinational magnitude + non-sticky detection flag (tb: 23/23)
Fix 2: Rename all cfar_* signals to detect_*/threshold_* (honest naming)
Fix 3: New rx_gain_control.v between DDC and FFT, opcode 0x16 (tb: 33/33)
Fix 4: Clamp host_chirps_per_elev to DOPPLER_FFT_SIZE, error flag (E2E: 54/54)
Fix 5: Decimator watchdog timeout, 256-cycle limit (tb: 63/63)
Fix 6: Remove bypass_mode dead code from ddc_400m.v (DDC tb: 21/21)
Fix 7: Range-mode register 0x20 with status readback (USB tb: 77/77)
2026-03-20 04:38:35 +02:00
Jason 0b0643619c Real-data co-simulation: range FFT, Doppler, full-chain all 2048/2048 exact match
ADI CN0566 Phaser 10.525 GHz X-band radar data validation:
- golden_reference.py: bit-accurate Python model with range_bin_decimator
- tb_range_fft_realdata.v: 1024/1024 exact match
- tb_doppler_realdata.v: 2048/2048 exact match
- tb_fullchain_realdata.v: decimator+Doppler 2048/2048 exact match
- 19/19 FPGA regression unaffected
2026-03-20 03:19:22 +02:00
Jason 0773001708 E2E integration test + RTL fixes: mixer sequencing, USB data-pending flags, receiver toggle wiring (19/19 FPGA)
RTL fixes discovered via new end-to-end testbench:
- plfm_chirp_controller: TX/RX mixer enables now mutually exclusive
  by FSM state (Fix #4), preventing simultaneous TX+RX activation
- usb_data_interface: stream control reset default 3'b001 (range-only),
  added doppler/cfar data_pending sticky flags, write FSM triggers on
  range_valid only — eliminates startup deadlock (Fix #5)
- radar_receiver_final: STM32 toggle signals wired through for mode-00
  pass-through, dynamic frame detection via host_chirps_per_elev
- radar_system_top: STM32 toggle signal wiring to receiver instance
- chirp_memory_loader_param: explicit readmemh range for short chirp

Test infrastructure:
- New tb_system_e2e.v: 46 checks across 12 groups (reset, TX, safety,
  RX, USB R/W, CDC, beam scanning, reset recovery, stream control,
  latency budgets, watchdog)
- tb_usb_data_interface: Tests 21/22/56 updated for data_pending
  architecture (preload flags, verify consumption instead of state)
- tb_chirp_controller: mixer tests T7.1/T7.2 updated for Fix #4
- run_regression.sh: PASS/FAIL regex fixed to match only [PASS]/[FAIL]
  markers, added E2E test entry
- Updated rx_final_doppler_out.csv golden data
2026-03-20 01:45:00 +02:00
Jason 7cdfa486e5 Gap 2 GUI Settings: runtime chirp timing, stream control gating, status readback (18/18 FPGA, 20/20 MCU)
Register map: 0x10-0x15 chirp timing overrides, 0xFF status readback,
0x03 CFAR threshold now wired to actual compare, 0x04 stream control
gates USB write FSM. Status readback sends 7-word packet (0xBB header,
5 status words, 0x55 footer) via toggle CDC.

radar_mode_controller: 6 cfg_* input ports replace hardcoded parameters.
usb_data_interface: stream_control CDC, status_request toggle CDC,
  SEND_STATUS state (3'd7), stream gating in IDLE/HEADER/RANGE/DOPPLER.
radar_system_top: 6 host registers + command decode for 0x10-0x15/0xFF.
radar_receiver_final: 6 host_* timing passthrough ports.

Testbench coverage: RMC 81 checks (+TG16 runtime reconfig), USB 77
checks (+TG15 stream gating, TG16 status readback, TG17 chirp opcodes).
Fixed iverilog 13.0 forward-ref for status_req_toggle_100m.
2026-03-19 23:54:48 +02:00
Jason e5d1b3cfc3 Gap 4 USB Read Path: wire host-to-FPGA command path with toggle CDC, add read path tests
- usb_data_interface.v: Add FT601 read FSM (RD_IDLE/OE_ASSERT/READING/
  DEASSERT/PROCESS) + cmd_data/valid/opcode/addr/value output ports
- radar_system_top.v: Connect cmd_* ports from usb_inst, add toggle CDC
  for cmd_valid (ft601_clk -> clk_100m), add command decode registers
  (mode/trigger/cfar_threshold/stream_control), wire host_mode and
  host_trigger to rx_inst
- radar_receiver_final.v: Add host_mode[1:0] and host_trigger input
  ports, replace hardcoded mode/trigger in radar_mode_controller instance
- tb_usb_data_interface.v: Connect cmd_* ports, add host data bus driver,
  add Test Groups 12 (single command), 13 (multiple commands), 14
  (read/write interleave). USB TB now has 55 checks.

Regression: 18/18 PASS
2026-03-19 23:16:26 +02:00
Jason c6103b37de Gap 7 MMCM jitter cleaner + CIC comb CREG pipeline + XDC clock-name fix
MMCM (Gap 7):
- Add adc_clk_mmcm.v: MMCME2_ADV wrapper (VCO=800MHz, CLKOUT0=400MHz)
- Modify ad9484_interface_400m.v: replace BUFG with MMCM path, gate reset on mmcm_locked
- Add adc_clk_mmcm.xdc: CDC false paths for clk_mmcm_out0 <-> clk_100m

XDC Fix (Build 19 WNS=-0.011 root cause):
- Remove conflicting create_generated_clock -name clk_400m_mmcm
- Replace all clk_400m_mmcm references with Vivado auto-generated clk_mmcm_out0
- CDC false paths now correctly apply to actual timing paths

CIC CREG Pipeline (Build 18 critical path fix):
- Explicit DSP48E1 for comb[0] with CREG=1/AREG=1/BREG=1/PREG=1
- Absorbs integrator_sampled_comb fabric FDRE into DSP48 C-port register
- Eliminates 0.643ns fabric->DSP routing delay (Build 18 tightest path)
- +1 cycle comb latency via data_valid_comb_0_out pipeline
- Move shared register declarations above ifndef SIMULATION (iverilog fix)
- Update golden data for +1 cycle CIC pipeline shift

Build scripts: build19_mmcm.tcl, build20_mmcm_creg.tcl
Regression: 18/18 FPGA pass, 20/20 MCU pass
Build 20 launched on remote Vivado (pending results)
2026-03-19 22:59:46 +02:00
Jason 94ffdb8f77 Add Phase 0 Vivado-style lint to regression runner, update golden data
Adds two-layer lint pass (iverilog -Wall + custom static checks) that
catches part-select OOB errors and case-without-default warnings before
pushing to remote Vivado. Catches the exact Synth 8-524 class error that
broke Build 18 initial attempt. Lint errors abort regression; warnings
are advisory. Regenerated golden data for BRAM-migrated matched filter.
2026-03-19 21:19:07 +02:00
Jason ed6f79c6d3 FIR DSP48 pipelining (BREG+MREG) + matched filter BRAM migration with overlap cache
FIR: Add coeff_reg/mult_reg pipeline stages to fix 68 DPIP-1 + 35 DPOP-2
DRC warnings. Valid pipeline widened 7→9 bits (+2 cycle latency).

Matched filter: Migrate input_buffer_i/q from register arrays to BRAM
(~33K FF savings). Overlap-save uses register cache captured during
ST_PROCESSING to avoid BRAM read/write conflicts during overlap copy.
New ST_OVERLAP_COPY state writes cached tail samples back sequentially.

Both changes pass 18/18 FPGA regression. Golden data regenerated for
+2 FIR latency baseline.
2026-03-19 20:39:01 +02:00
Jason f4ff2715ca Fix matched filter golden test paths (40/40 pass, was 37/40) 2026-03-19 12:20:37 +02:00
Jason 463ebef554 CIC comb pipeline registers, BUFG sim guard, system TB fix, regression runner
- cic_decimator_4x_enhanced.v: Add integrator_sampled_comb and
  data_valid_comb_pipe pipeline stages between integrator sampling and
  comb computation to break the critical path (matches remote 40cda0f)
- radar_system_top.v: Wrap 3 BUFG instances in ifdef SIMULATION guard
  with pass-through assigns for iverilog compatibility
- radar_system_tb.v: Convert generate_radar_echo function to task and
  move sin_lut declaration before task (iverilog declaration-order fix),
  add modular index clamping to prevent LUT out-of-bounds
- run_regression.sh: Automated regression runner for all 18 FPGA
  testbenches with --quick mode. Results: 17 pass, 1 pre-existing fail
- .gitignore: Exclude *.vvp, *.vcd simulation artifacts
2026-03-19 11:31:46 +02:00
Jason f6877aab64 Phase 1 hardware bring-up prep: ILA debug probes, CDC waivers, programming scripts
- Rename latency_buffer_2159 -> latency_buffer (module + file + all refs)
- Add CDC waivers for 5 verified false-positive criticals to XDC
- Add ILA debug probe insertion script (4 cores, 126 probe bits, 2 clock domains)
- Add FPGA programming script (7-step flow with DONE pin verification)
- Add ILA capture script (4 scenarios + health check, CSV export)
- Add debug_ila.xdc with MARK_DEBUG fallback attributes
- Full regression clean: 13/13 suites, 266/266 checks, 2048/2048 golden match
2026-03-18 01:28:42 +02:00
Jason 47606a4459 Rewrite integration testbench with golden self-reference comparison + physics bounds checks
Replace smoke-test integration TB (10 liveness checks) with golden
comparison architecture (18 checks). Two compile-time modes:
- GOLDEN_GENERATE: dumps 2048 Doppler outputs to golden_doppler.mem
- Default: loads golden, compares within ±2 LSB tolerance per channel

New checks: G1 golden comparison (2048/2048 exact match verified),
B1a/b DDC energy bounds, B2a/b Doppler per-bin energy, B3 exact count,
B4 full 64x32 bin coverage, B5 no duplicate indices.

Fault injection verified: zeroing FIR coeff[15] causes 2048/2048
golden mismatches (max err 1234/1443 LSB), confirming regression guard.
2026-03-17 20:56:28 +02:00
Jason fcf3999e39 Fix CDC reset domain bug (P0), strengthen testbenches with 31 structural assertions
Split cdc_adc_to_processing reset_n into src_reset_n/dst_reset_n so source
and destination clock domains use correctly-synchronized resets. Previously
cdc_chirp_counter's destination-side sync chain (100MHz) was reset by
sys_reset_120m_n (120MHz domain), causing 30 CDC critical warnings.

RTL changes:
- cdc_modules.v: split reset port, source logic uses src_reset_n,
  destination sync chains + output logic use dst_reset_n
- radar_system_top.v: cdc_chirp_counter gets proper per-domain resets
- ddc_400m.v: CDC_FIR_i/q use reset_n_400m (src) and reset_n (dst)
- formal/fv_cdc_adc.v: updated wrapper for new port interface

Build 7 fixes (previously untouched):
- radar_transmitter.v: SPI level-shifter assigns, STM32 GPIO CDC sync
- latency_buffer_2159.v: BRAM read registration
- constraints: ft601 IOB -quiet fix
- tb_latency_buffer.v: updated for BRAM changes

Testbench hardening (tb_cdc_modules.v, +31 new assertions):
- A5-A7: split-domain reset tests (staggered deassertion, independent
  dst reset while src active — catches the P0 bug class)
- A8: port connectivity (no X/Z on outputs)
- B7: cdc_single_bit port connectivity
- C6: cdc_handshake reset recovery + port connectivity

Full regression: 13/13 test suites pass (257 total assertions).
2026-03-17 19:38:09 +02:00
Jason 6fc5a10785 Fix range_bin_decimator overflow guard priority bug: group completion now takes precedence over overflow guard in ST_PROCESS, ensuring all OUTPUT_BINS outputs are emitted when sufficient input samples exist. Split formal property 5 into 5a (upper bound) and 5b (exact count when start_bin=0), added Cover 4 for overflow guard path, reduced BMC depth to 50. 2026-03-17 15:41:06 +02:00
Jason 5fd632bc47 Fix all 10 CDC bugs from report_cdc audit, add overflow guard in range_bin_decimator
CDC fixes across 6 RTL files based on post-implementation report_cdc analysis:
- P0: sync stm32_mixers_enable and new_chirp_pulse to clk_120m via toggle CDC
       in radar_transmitter, add ft601 reset synchronizer and USB holding
       registers with proper edge detection in usb_data_interface
- P1: add ASYNC_REG to edge_detector, convert new_chirp_frame to toggle CDC,
       fix USB valid edge detect to use fully-synced signal
- P2: register Gray encoding in cdc_adc_to_processing source domain, sync
       ft601_txe and stm32_mixers_enable for status_reg in radar_system_top
- Safety: add in_bin_count overflow guard in range_bin_decimator to prevent
          downstream BRAM corruption

All 13 regression test suites pass (159 individual tests).
2026-03-17 13:48:47 +02:00
Jason a9c857c447 Remove 15 dead files, move radar_system_tb.v to tb/ directory
Dead modules removed (7 tracked, 8 untracked debug files):
- fft_1024_forward.v, fft_1024_inverse.v (wrap non-existent IP)
- lvds_to_cmos_400m.v, level_shifter_interface.v (unused)
- chirp_lut_init.v (orphan initial block)
- usb_packet_analyzer.v (never instantiated)
- debug_fft*.v x8 (standalone debug scripts)
- cntrt.xdc (stale duplicate of upstream XDC)

Moved radar_system_tb.v from root to tb/ (correct location).
All regression tests pass: integration 10/10, Doppler 14/14, MF 3/3.
2026-03-17 01:08:26 +02:00
Jason 6d27ab7217 Fix NCO XSim test 12: widen zero-crossing range for DSP48E1 quantization
DSP48E1 lookup table quantization causes dithering near zero crossings
at low frequencies (1 MHz), producing ~11 sign transitions vs ~5 expected.
Widen accepted range from [3,8] to [3,15].
2026-03-16 23:23:06 +02:00
Jason ffe36b42dc Fix NCO XSim test 12: add pipeline warmup and sample skip for 1 MHz zero-crossing test 2026-03-16 23:21:25 +02:00
Jason 49eb6169b6 Widen ft601_be to [3:0] for 32-bit FT601 mode, fix NCO XSim TB
- Expand ft601_be from [1:0] to [3:0] across RTL, top-level, testbenches,
  and XDC (uncomment be[2:3] pin assignments B21/A21)
- Fix NCO XSim testbench: correct reset check (0x7FFF not 0), add pipeline
  warmup and sample skip for DSP48E1 quadrature test
- All local regression tests pass (39/39 USB, 10/10 integration, all co-sim)
2026-03-16 23:17:38 +02:00
Jason b823d83feb Add new testbenches and fix USB clock forwarding test
New testbenches:
- tb_latency_buffer.v: 13/13 tests for BRAM delay line (P1-3)
- tb_cdc_modules.v: 27/27 tests for all 3 CDC primitives (P1-4)
- tb_ad9484_xsim.v: XSim testbench for AD9484 with Xilinx BUFIO/IDDR
- tb_nco_xsim.v: XSim testbench for NCO DSP48E1 path verification

Fixes:
- tb_usb_data_interface.v: updated test 33 from divide-by-2 check to
  ODDR-style clock forwarding verification (39/39 pass)
- rx_final_doppler_out.csv: updated golden reference after bug fixes
2026-03-16 22:24:34 +02:00
Jason f154edbd20 Regenerate chirp .mem files, add USB testbench, convert radar_system_tb to Verilog-2001
- Regenerate all 10 chirp .mem files with correct AERIS-10 parameters
  (gen_chirp_mem.py: phase = pi*chirp_rate*t^2, 4 segments x 1024)
- Add gen_chirp_mem.py script for reproducible .mem generation
- Add tb_usb_data_interface.v testbench (39/39 PASS)
- Convert radar_system_tb.v from SystemVerilog to Verilog-2001:
  replace $sin() with LUT, inline integer decl, SVA with procedural checks
- All testbenches pass: integration 10/10, MF 3/3, multi-seg 32/32,
  DDC 4/4, Doppler 14/14, USB 39/39, .mem validation 56/56
- Vivado timing closure confirmed: WNS=+0.021ns on xc7a100t-csg324-1
2026-03-16 19:53:40 +02:00
Jason 17b70bdcff Fix overlap-save: fill full 1024-sample buffer per segment, zero-pad last partial segment
Previously segment 0 only filled positions [0:895], leaving [896:1023]
as zeros from the initial block. These zeros propagated into the overlap
region of subsequent segments, corrupting the convolution.

Fix: change buffer-full threshold from SEGMENT_ADVANCE (896) to
BUFFER_SIZE (1024). Add zero-padding for the last segment when chirp
data runs out before the buffer is full. Updated testbench accordingly.

Verified: multi-segment 32/32 PASS, integration test 10/10 PASS.
2026-03-16 19:15:23 +02:00
Jason 39f78d4349 Fix RTL Bug #3: S_IDLE->S_ACCUMULATE now writes first sample immediately
Previously the S_IDLE->S_ACCUMULATE transition consumed one data_valid
cycle without writing to BRAM, losing the first sample. The testbench
worked around this by sending sample[0] twice.

Fix: drive mem_we + data capture in S_IDLE on the transition cycle and
advance write_range_bin to 1. Testbench workaround removed.

Verified: 3/3 Doppler co-sim BIT-PERFECT, integration test 10/10 PASS.
2026-03-16 19:08:16 +02:00
Jason 2db32af1d0 Add .mem file validator: verify FFT twiddle + chirp .mem files against radar parameters (55/56 PASS) 2026-03-16 19:02:45 +02:00
Jason e76925391c Fix multi-seg/chain handshake deadlock + add radar_receiver_final integration test (10/10 PASS)
RTL fix: matched_filter_multi_segment.v ST_WAIT_FFT now waits for
processing chain to complete ALL 1024 outputs and return to IDLE
before advancing to next segment. Previously, it transitioned on the
first fft_pc_valid edge, causing the chain to still be outputting
while multi-seg started collecting data for the next segment. This
broke the handshake and caused permanent deadlock after segment 0.

Also fixes forward reference of sample_addr_from_chain in
radar_receiver_final.v (declaration moved before first use).

New files:
- tb/tb_radar_receiver_final.v: P0 integration test for full RX
  pipeline (ADC->DDC->MF->range_bin_decimator->doppler), 10 checks
- tb/ad9484_interface_400m_stub.v: behavioral ADC stub for iverilog

All existing tests still pass: multi-seg 32/32, MF co-sim 3/3,
Doppler co-sim 14/14.
2026-03-16 18:51:08 +02:00
Jason a5a5e96a57 Fix ddc_input_interface 18->16 bit overflow: add saturation at positive full scale
Bug: rounding logic 'adc_i <= ddc_i[17:2] + ddc_i[1]' overflows when
ddc_i[17:2]=0x7FFF and ddc_i[1]=1, causing 0x7FFF+1=0x8000 (sign flip
from max positive to most negative value).

Fix: add explicit saturation — clamp to 0x7FFF when truncated value is
max positive and round bit is set. Negative values cannot overflow since
rounding only moves toward zero.

New testbench: tb_ddc_input_interface.v with 26 tests covering rounding,
truncation, overflow saturation at positive boundary, negative full scale,
valid synchronization, and sync error detection.
2026-03-16 18:14:06 +02:00