sim: make the EXI clock rate configurable; default was 8x too slow

bba_top derived its EXI clock from HALF, defaulting to 3.4 MHz against the
real GC's ~27 MHz.  At that rate the whole CDC response latency fits inside
one bit time, so the suite passed green on a design that failed on console --
this is how both the wrong-header-format and the TX-pop-threshold bugs
reached hardware with everything green.

HALF is now EXI_HALF-configurable (default 8 for fast regression).  At the
real rate, EXI_HALF=1, every read comes back shifted right by ONE BIT:
04 02 02 00 -> 02 01 01 00, NWAYS 0x17 -> 0x0B.  That is a bit-level sampling
misalignment, not the byte-level latency chased earlier: at 54 MHz capture
there are only 2 ticks per EXI bit and the 2-stage FFSynchronizer on EXI CLK
costs 2 ticks, a whole bit.

Recorded as an open bug in CLAUDE.md with the measurements.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 12:36:50 +02:00
parent 399fbf02a4
commit 7df0c97c78
2 changed files with 43 additions and 1 deletions
+14 -1
View File
@@ -398,6 +398,7 @@ class BBATop(Elaboratable):
# ↔ BBARegisterFile (exi domain) ↔ sync modules, across all three clock domains.
if __name__ == "__main__":
import os
import sys
from amaranth.sim import Simulator, Period
@@ -405,7 +406,19 @@ if __name__ == "__main__":
status_panel=True) # also exercise the panel wiring
errors = []
HALF = 8 # capture ticks per SPI half-period (well-oversampled)
# Capture ticks per SPI half-period -> EXI rate = 54 MHz / (2 * HALF).
# HALF=8 3.4 MHz fast regression default
# HALF=2 13.5 MHz
# HALF=1 27 MHz THE HARDWARE RATE
# ⚠️ The default is 8, which clocks EXI EIGHT TIMES SLOWER than the real
# GC. At that rate the whole CDC response latency hides inside a single
# bit time, so this suite passed green while hardware failed outright --
# that is how both the header-format and pop-threshold bugs reached a
# console. Run `EXI_HALF=1 python -m exi_bba.bba_top` before trusting any
# timing-related change; at 27 MHz reads currently come back shifted right
# by one bit (04 02 02 00 -> 02 01 01 00, NWAYS 0x17 -> 0x0B), which is an
# open bug.
HALF = int(os.environ.get("EXI_HALF", "8"))
async def spi_byte(ctx, mosi_val):
"""Drive one EXI Mode-3 byte; return the assembled MISO byte."""