Commit Graph

38 Commits

Author SHA1 Message Date
Jason e8eb24f4f5 style(fpga): drop dead regex in gen_chirp_mem parser
Leftover from two alternative parsing approaches; the unused pat
triggered ruff F841. Only line_pat is actually used.
2026-04-23 04:48:23 +05:45
Jason 52a3497ea2 refactor(fpga): gen_chirp_mem sources sizing from radar_params.vh
A-3: gen_chirp_mem.py hardcoded 30 us / 0.5 us / 2048-pt / 2 segments,
duplicating the same numbers defined as RP_LONG_CHIRP_SAMPLES_3KM,
RP_SHORT_CHIRP_SAMPLES, RP_FFT_SIZE, RP_LONG_SEGMENTS_3KM in
radar_params.vh. A change on one side would silently desync the .mem
files from the RTL sample counts.

The script now parses radar_params.vh for integer RP_* macros and
derives chirp durations from LONG_CHIRP_SAMPLES / FS_SYS. Physical
baseband constants (CHIRP_BW, FS_SYS, SCALE) stay hardcoded since
they are chirp-design properties, not FPGA sizing.

Regenerated .mem files are byte-identical to pre-change output.
32/32 regression PASS.
2026-04-22 20:54:43 +05:45
Jason f39a78cb1e chore(fpga): untrack TB-generated CSV, ignore a.out
rx_final_doppler_out.csv is written by tb_radar_receiver_final.v on
every run via $fopen — it is a test-run artifact, not an oracle. It
was mistakenly tracked in an earlier commit, causing unnecessary
churn on every sim. Remove from the index and ignore going forward.

Also ignore stray a.out from iverilog one-shot compiles.

Golden references (.hex, .mem, doppler_golden_py_*.csv) remain
tracked — they are load-bearing oracles used by MF / Doppler /
receiver cosim testbenches.
2026-04-22 13:36:03 +05:45
Jason 8865e9a0ef fix(fpga): pre-bringup RTL hardening + test-suite hardening
RTL (P0 pre-bringup findings R-1/R-2/R-3/R-5/R-6):

- mti_canceller: add use_long_chirp input and waveform-boundary mute
  so the long->short transition in mode 01 no longer subtracts across
  heterogeneous waveforms (R-1). Prev buffer is overwritten in-flight
  at the boundary so the next same-waveform chirp subtracts cleanly.
- ad9484_interface_400m: 2FF sync of mmcm_locked into the 400 MHz
  domain before gating reset_n_gated (R-6).
- cic_decimator_4x_enhanced: correct max_fanout narrative (R-3).
- ad9484_interface_400m: strip stale pblock comment, note 3.0 ns
  max_delay instead (R-2).
- mti_canceller / doppler_processor: 200T-20km WARNING banners
  flagging the broken 4096-bin path (R-5). 9-bit BRAM address aliases
  silently until rewritten.
- adc_clk_mmcm.xdc: relax set_max_delay from 2.700 -> 3.000 ns,
  closes WNS with headroom on 50T build.
- radar_receiver_final: wire use_long_chirp into mti_inst.

Architecture-bump finalization (2048-pt range FFT, 512 range bins,
32 Doppler bins -> 16384 output cells per frame):

- tb/cosim/radar_scene.py: FFT_SIZE 1024 -> 2048, RANGE_BINS 64 -> 512.
- tb/gen_mf_golden_ref.py: N 1024 -> 2048.
- Regenerate all affected hex goldens (MF cases 1-4, Doppler inputs
  + py goldens, receiver integration golden_doppler.mem 2048 -> 16384).
- tb_radar_receiver_final: widen range_bin_out 6 -> 9 bits, bump
  GOLDEN_ENTRIES 2048 -> 16384, expand bitmaps/arrays to 512 bins,
  update all check messages and thresholds.
- tb_mti_canceller, tb_fullchain_mti_cfar_realdata: tie/pass
  use_long_chirp so compile still works after RTL port add.

Test-suite hardening (coverage audit findings):

- tb_mti_canceller T12: 10 new assertions exercising R-1 waveform-
  boundary mute across a long/long/short/short/long sequence. Catches
  a regression that re-enables subtraction across the boundary.
- tb_fir_lowpass: replace tautological check(1'b1, ...) on coefficient
  symmetry with a real hierarchical check coeff[k]===coeff[31-k];
  replace always-pass overflow check with a well-driven (not X/Z)
  assertion on filter_overflow.
- tb_matched_filter_processing_chain: replace three always-pass peak-
  bin placeholders with peak-to-mean-|out| > 2x ratio checks (catches
  flat/zero output that the old tautologies silently accepted).
- tb_cdc_modules M2: replace always-pass narrow-pulse check with a
  well-defined-output assertion on the synchronizer.
- tb_nco_400m: replace always-pass freq-switch check with a swing +
  no-X assertion across 200 post-switch samples.
- tb_system_e2e G12.1: replace check(1, ...) with test_num > 20 so
  it catches a stalled TB that skipped prior groups.
- tb_multiseg_cosim TEST 4: replace always-pass placeholder with a
  bitmap that asserts segment_request visited all 4 values.
- tb_mf_chain_synth and tb_fullchain_mti_cfar_realdata: add DEPRECATED
  headers plus \$fatal guards (ifndef ALLOW_STALE_*) so they cannot
  be silently re-enabled in CI with stale 1024-bin goldens against
  current 2048-pt RTL.

Regression: 32 passed, 0 failed. MTI TB grew 30 -> 39 checks;
receiver integration grew 17 -> 18 checks with 16384/16384 golden
match at tolerance +/- 2 LSB.
2026-04-22 13:23:38 +05:45
Jason c668652ba8 merge(wave3/tier2): port testbenches and cosim goldens for fft-2048
Regression goes from 21/32 -> 27/32 passing.

TB files updated from feat/fft-2048-upgrade (FFT_SIZE=2048 / 512 range
bins / Manhattan magnitude / 2-segment matched filter):
  - tb/tb_mf_cosim.v            (range_profile_{i,q} port names)
  - tb/tb_matched_filter_processing_chain.v  (long_chirp port names)
  - tb/tb_range_bin_decimator.v (new 2048->512 DUT)
  - tb/tb_radar_mode_controller.v (XOR edge detector)
  - tb/tb_doppler_cosim.v       (2048-deep inputs)
  - tb/tb_multiseg_cosim.v
  - tb/tb_mf_chain_synth.v

Cosim infrastructure regenerated with FFT_SIZE=2048:
  - tb/cosim/gen_mf_cosim_golden.py
  - tb/cosim/gen_doppler_golden.py
  - tb/cosim/compare_mf.py, compare_doppler.py
  - tb/cosim/fpga_model.py
  - All mf_* and doppler_* goldens/inputs regenerated

Deliberately NOT taken:
  - tb/tb_radar_receiver_final.v — kept p0's version because the merged
    radar_receiver_final requires tx_frame_start + adc_or_p/n inputs
    that fft's TB does not drive. Its 3 failures (G1 golden mismatch,
    B3/B5 hardcoded 64-bin limits) are tracked as known issues; TB
    needs a 64->512 bin rewrite + golden regen against merged RTL.

Known remaining failures (5/32):
  - Doppler Co-Sim x3: python compare mismatch — goldens generated
    against fft's reset/DDC behavior; merged RTL uses p0's reset
    strategy. Needs golden regen against merged RTL.
  - Receiver Integration: TB has stale 64-bin localparams/widths.
  - Matched Filter Chain: 3/40 "peak magnitude > 0" checks fail on
    behavioral-FFT cases. Pre-existing on fft branch (known brittle).
2026-04-21 03:04:52 +05:45
Jason 60e49c7da6 feat(fpga): integrate 2048-pt FFT upgrade — non-conflicting RTL (wave 1/3)
File-scoped cherry-pick from feat/fft-2048-upgrade (e9705e4) for modules
that only the fft branch modified:

  RTL:
    cfar_ca.v                        512-row CFAR
    chirp_memory_loader_param.v      2-segment × 2048-sample loader
    doppler_processor.v              16384-deep doppler memory
    fft_engine.v                     2048-pt FFT
    matched_filter_multi_segment.v   2-seg overlap-save, BRAM overlap_cache
    matched_filter_processing_chain.v
    radar_mode_controller.v          XOR edge detector
    radar_params.vh                  (new) single source of truth
    range_bin_decimator.v            2048 -> 512 output bins
    rx_gain_control.v

  Memory:
    fft_twiddle_2048.mem             (new) 2048-pt FFT twiddles
    long_chirp_seg0_{i,q}.mem        2048-sample seg 0 (was 1024)
    long_chirp_seg1_{i,q}.mem        2048-sample seg 1 (was 1024)
    long_chirp_seg{2,3}_{i,q}.mem    deleted (4-seg -> 2-seg collapse)

  Gen:
    tb/cosim/gen_chirp_mem.py        regen script for mem files above

Waves 2 and 3 follow: manual merge for dual-modified files
(radar_system_top, usb_data_interface_ft2232h, mti_canceller,
radar_receiver_final), and CFAR pipeline from 2401f5f keeping p0's
CIC/DDC reset strategy.
2026-04-21 01:52:32 +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
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 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 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 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 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 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 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 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 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 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 17731dd482 Fix doppler_processor windowing pipeline bugs + multi-segment buffer_write_ptr bug, add co-sim suites
RTL bug fixes:
- doppler_processor.v: Add S_PRE_READ state to prime BRAM pipeline, restructure
  S_LOAD_FFT with sub-counter staging, fix BRAM address off-by-one
  (read_doppler_index <= fft_sample_counter + 2, was +1). All 3 Doppler
  co-sim scenarios now achieve BIT-PERFECT match (correlation=1.0, energy=1.0).
- matched_filter_multi_segment.v: Move buffer_write_ptr >= SEGMENT_ADVANCE check
  outside if(ddc_valid) block to prevent FSM deadlock. 32/32 tests PASS.

New co-simulation infrastructure:
- Doppler co-sim: tb_doppler_cosim.v (14/14 structural checks),
  gen_doppler_golden.py (3 scenarios: stationary/moving/two_targets),
  compare_doppler.py (bit-perfect thresholds)
- Multi-segment co-sim: tb_multiseg_cosim.v (32/32), gen_multiseg_golden.py
  with short and long test vector suites
2026-03-16 18:09:26 +02:00
Jason e506a80db5 Add matched-filter co-simulation: bit-perfect validation of Python model vs synthesis-branch RTL (4/4 scenarios, correlation=1.0) 2026-03-16 16:23:01 +02:00
Jason baa24fd01e Add Phase 0.5 DDC co-simulation suite: bit-accurate Python model, scene generator, and 5/5 scenario validation
Bit-accurate Python model (fpga_model.py) mirrors full DDC RTL chain:
NCO -> mixer -> CIC -> FIR with exact fixed-point arithmetic matching
RTL DSP48E1 pipeline behavior including CREG=1 delay on CIC int_0.

Synthetic radar scene generator (radar_scene.py) produces ADC test
vectors for 5 scenarios: DC, single target (500m), multi-target (5),
noise-only, and 1 MHz sine wave.

DDC co-sim testbench (tb_ddc_cosim.v) feeds hex vectors through RTL
DDC and exports baseband I/Q to CSV. All 5 scenarios compile and run
with Icarus Verilog (iverilog -g2001 -DSIMULATION).

Comparison framework (compare.py) validates Python vs RTL using
statistical metrics (RMS ratio, DC offset, peak ratio) rather than
exact sample match due to RTL LFSR phase dithering. Results: 5/5 PASS.
2026-03-16 16:01:40 +02:00