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.
Remove unused imports (deque, sys, Opcode, struct, _REPLAY_ADJUSTABLE_OPCODES)
across 4 active Python files and refactor semicolons to separate statements
in radar_protocol.py. Add ruff lint job to CI workflow targeting only the
active files (excludes legacy GUI_V*.py and v7/).
Three parallel jobs covering all AERIS-10 test infrastructure:
- Python dashboard tests (58): protocol, connection, replay, opcodes, e2e
- MCU firmware tests (20): bug regression (15) + Gap-3 safety (5)
- FPGA regression (23 TBs + lint): unit, integration, and system e2e
Triggers on push/PR to main and develop branches.
Accidentally included SSH key path, hostname, port, and internal server
paths in the build quick-reference section. Replaced with generic
instructions.
Add USB Interface Architecture section documenting the USB_MODE parameter,
generate block mechanism, per-target wrapper pattern, FT2232H pin map, and
build quick-reference. Update top modules table (50T now uses
radar_system_top_50t), bank voltage tables, and signal differences to
reflect the FT2232H/FT601 dual-interface design.
Replace FT601Connection with FT2232HConnection in radar_dashboard.py and
smoke_test.py. Both files had broken imports after FT601Connection was
removed from radar_protocol.py. Also update requirements_dashboard.txt
(ftd3xx -> pyftdi) and GUI_versions.txt descriptions.
Align test suite with FT601 removal from radar_protocol.py:
- Replace FT601Connection with FT2232HConnection throughout
- Rewrite _make_data_packet() to build 11-byte packets (was 35-byte)
- Update data packet roundtrip test for 11-byte format
- Fix truncation test threshold (20 -> 6 bytes, since packets are 11)
- Update ReplayConnection frame_len assertions (35 -> 11 per packet)
57 passed, 1 skipped (h5py), 0 failed.
- Add set_false_path -hold for source-synchronous ADC IDDR paths in
adc_clk_mmcm.xdc (eliminates 8 hold violations from build 12)
- Add DDR falling-edge input delay constraints to xc7a50t_ftg256.xdc
(parity with 200T XDC)
- Reorganize scripts/ into target subdirectories: 50t/, 200t/, te0712/,
te0713/, utils/ so users can run the correct build for their hardware
- Delete obsolete build scripts (build17-20) superseded by build_50t/200t
- Update project_root paths in all moved scripts (.. -> ../..)
Add (* USE_DSP = "no" *) attribute to FIR lowpass adder tree registers
(add_l1, add_l2, add_l3, accumulator_reg) to prevent Vivado from
inferring DSP48E1 slices for pure addition operations.
Each fir_lowpass_parallel_enhanced instance was using 47 DSPs (32 for
multiply + 15 for the adder tree). The 15 adder-tree DSPs per instance
(30 total for I/Q pair) performed only PCIN+A:B additions with no
multiplier usage. On the XC7A50T with only 120 DSP48E1 slices, this
caused 100% DSP utilization and forced FFT butterfly complex multipliers
to spill into 18-level fabric carry chains (WNS=-1.103ns).
Moving these 36-bit additions to fabric CARRY4 chains (~9 CARRY4 per
add, ~2ns propagation) is well within the 10ns clock period and frees
~30 DSPs for the FFT engine to use native DSP48E1 multipliers.
Regression: 23/23 FPGA tests PASS (attribute is synthesis-only).
Build attempt 10 produced a valid bitstream but with only 315 LUTs and
15 DSPs — opt_design removed all logic feeding unconnected _nc wires.
Adding (* DONT_TOUCH = "TRUE" *) on the u_core instance prevents
Vivado from optimizing away the internal radar pipeline logic.
The XC7A50T-FTG256 has only 69 usable IO pins but radar_system_top
declares 182 port bits. Previous attempts to remove unconstrained
ports via TCL caused opt_design to cascade-remove all driving logic.
New approach: radar_system_top_50t.v is a thin wrapper that:
- Exposes only the 64 physically-connected ports (ADC, DAC, SPI, clocks)
- Instantiates radar_system_top internally with full logic preserved
- Ties off unused inputs (FT601 bus, ext trigger) to safe defaults
- Leaves unused outputs internally connected (no IOBs created)
Updated build_50t_test.tcl to use radar_system_top_50t as top module
and removed the now-unnecessary port removal TCL code.
remove_port fails on connected ports with [Coretcl 2-28]. Add
disconnect_net step before remove_port to properly detach the
port from its driving/driven nets in the synthesized netlist.
The 50T FTG256 has only 69 usable IO pins but the RTL declares 182 port
bits. launch_runs spawns a child process that cannot remove ports.
Switch to direct opt_design/place_design/route_design flow so we can
remove 118 unconstrained ports (FT601 USB, dac_clk, status/debug) from
the netlist before placement, avoiding [Place 30-58] IO overflow.
The placer enforces a single VCCO per bank. LVDS_25 forces Bank 14
to VCCO=2.5V, which conflicts with LVCMOS33 (needs 3.3V). Changing
adc_pwdn to LVCMOS25 resolves [Place 30-372] bank incompatibility.
The AD9484 PWDN pin has CMOS-level thresholds (~0.8V), so 2.5V
output drives it correctly.
set_property SEVERITY in the parent Vivado process does not propagate
to the child process spawned by launch_runs. Write a drc_waivers_50t.tcl
hook and attach it via STEPS.OPT_DESIGN.TCL.PRE so BIVC-1, NSTD-1,
and UCIO-1 are demoted to warnings inside the impl_1 run context.
Three issues prevented the 50T (FTG256) build from completing:
1. LVDS standard: LVDS_33 and LVDS do not exist on 7-series HR banks.
Changed to LVDS_25 (the only valid differential input standard).
IBUFDS inputs are VCCO-independent, so LVDS_25 works correctly even
with Bank 14 VCCO=3.3V.
2. BIVC-1 DRC: Bank 14 has LVDS_25 (needs 2.5V) and LVCMOS33 adc_pwdn
(needs 3.3V). Since all LVDS ports are inputs (IBUFDS only), the
voltage conflict does not affect functionality. Demoted to warning.
3. Pin overflow: 113 ports vs 69 available FTG256 pins. The 118
unconstrained port bits (FT601 unwired, status/debug unrouted,
dac_clk unconnected) cause NSTD-1/UCIO-1 DRC errors. Demoted to
warnings since these ports have no physical connections on this board.
Also added: CFGBVS/CONFIG_VOLTAGE settings, build_50t_test.tcl to repo.
LVDS_33 is not a valid I/O standard on 7-series FPGAs. The correct
standard for LVDS inputs in HR banks with VCCO != 2.5V is LVDS, which
works with any VCCO for input-only buffers (IBUFDS). LVDS_25 requires
VCCO=2.5V exactly.
Note: the 50T FTG256 build still fails at placement due to pin overflow
(113 ports vs 69 available pins) — this is a pre-existing package
limitation unrelated to this fix.
The IBUFDS primitives in ad9484_interface_400m.v hardcoded LVDS_25 and
DIFF_TERM TRUE, which overrode XDC constraints. On the XC7A50T (Bank 14
VCCO=3.3V), this caused a BIVC-1 DRC error: LVDS_25 requires VCCO=2.5V,
conflicting with adc_pwdn (LVCMOS33, VCCO=3.3V) in the same bank.
Changes:
- ad9484_interface_400m.v: IBUFDS parameters changed from LVDS_25/DIFF_TERM
TRUE to DEFAULT/DIFF_TERM FALSE, delegating control to XDC per target
- xc7a50t_ftg256.xdc: Re-enable DIFF_TERM TRUE (safe now that RTL does not
hardcode LVDS_25), update DRC Fix History with correct root cause
Build scripts (17-21): STATS.WNS/TNS/WHS/THS/TPWS from get_property can
return empty strings in Vivado 2025.2 after write_bitstream auto-launch.
Wrap in catch with N/A fallback. Guard all expr delta calculations and
signoff comparisons with [string is double -strict] checks.
XDC (xc7a50t_ftg256): Fix PLIO-9 by moving clk_120m_dac from C13 (N-type)
to D13 (P-type MRCC) — clock inputs require P-type MRCC pin. Fix BIVC-1 by
disabling DIFF_TERM on Bank 14 LVDS pairs to resolve VCCO conflict with
single-ended adc_pwdn (LVCMOS33) on T5 — requires external termination.
- Escape [extra] → \[extra\] to prevent TCL interpreting it as a command
(Vivado resolved 'extra' to 'extract_files' causing ERROR [Common 17-163])
- Fix implementation status check: accept 'write_bitstream' status as success
(Vivado auto-proceeds to write_bitstream, making status != '*Complete*')
- Wrap bitstream launch_runs in catch{} to handle already-running case
Fixes applied to: build17, build18, build19, build20, build21
- 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.
- 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