da21a080d9dfebd44136b561a1c75a28f2392c2e
The TX failure was a TESTBENCH artifact, not a design bug. Between
transactions the bench raised CS for one HP -- 18.5 ns at EXI_HALF=1 -- but
cs_active reaches the exi domain through a 2-stage FFSynchronizer at 24 MHz,
so the register file never saw one transaction end and swallowed the next
one's header as write data. A real host leaves microseconds between
exi_deselect() and the next exi_select(). With a realistic gap the 34-byte TX
frame now matches byte-for-byte at the hardware rate.
At EXI_HALF=1 (27 MHz) bba_top now passes device ID, PAR read/write, NWAYS,
RWP and TX. The one remaining failure is the SPRAM/DMA stream, offset by
exactly one byte.
Root cause of that offset, and it is not architectural: bba_top.py:171 does
m.d.comb += ClockSignal("sync").eq(ClockSignal("exi"))
so exi and sync are LITERALLY THE SAME CLOCK NET. Every AsyncFIFO between
them is pure overhead. The SPRAM round trip pays two needless CDC crossings
(~6 cycles, ~250 ns) on top of the arbiter and SPRAM access, giving ~375 ns
against the ~170 ns the protocol's turnaround byte actually leaves once the rx
crossing is subtracted. Register reads are unaffected because their response
is immediate; only SPRAM is late.
Fix direction: merge the two domains and replace the exi<->sync AsyncFIFOs and
PulseSynchronizers with plain SyncFIFOs/signals. That removes the latency,
drops a lot of logic, and cannot change behaviour because the clocks are
already identical.
Known failing, both testing removed behaviour rather than new bugs:
* exi_capture's own testbench asserts the CS-fall flush and the old MISO
slot timing; the flush no longer exists (header pops drain the FIFO).
* exi_j4's T3 re-enumerate is off by a byte.
Still WIP -- do not flash.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Description
No description provided
Languages
Python
84.9%
C
12.4%
Shell
1.1%
Dockerfile
0.7%
Makefile
0.4%
Other
0.5%