Merge the exi and sync domains into one
bba_top wired ClockSignal("sync") to ClockSignal("exi"), so the two "domains"
were always the same physical clock net. Everything between them -- six
AsyncFIFOs and three PulseSynchronizers -- was pure latency and logic for a
crossing that did not exist.
* the six AsyncFIFOs become plain SyncFIFOs
* the three PulseSynchronizers become wires
* BBARegisterFile and ExiCapture move from m.d.exi to m.d.sync
* the exi ClockDomain is gone; HFOSC drives sync directly
The SPRAM request write port is also combinational now. A registered w_en
costs a 24 MHz cycle, and the protocol's turnaround byte (~296 ns at 27 MHz)
has no cycles to spare.
Passing: bba_register_file, spram_arbiter, rx_frame_assembler, tx_frame_drain,
w5100_parallel_master, uart_shell, status_panel. bba_top at EXI_HALF=1
(27 MHz, the hardware rate) passes device ID, PAR read/write, NWAYS, RWP and
the 34-byte TX frame.
STILL OPEN: the SPRAM/DMA read is one byte late. Removing the CDC was not
enough -- the remaining round trip is the rx crossing (exiclk->sync, a REAL
CDC, ~125 ns) plus FSM decode plus the spram_req FIFO, arbiter, SPRAM access
and spram_rsp FIFO, which still exceeds the turnaround byte. Next step: now
that it is all one domain, drop the two SPRAM FIFOs entirely and give the
register file a direct request/grant port on the arbiter -- that should take
the round trip to ~2-3 cycles and fit.
exi_capture and exi_j4 testbenches still assert removed behaviour (the CS-fall
flush and the old MISO slot timing) and need rewriting for the clocked engine.
Still WIP -- do not flash.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -120,9 +120,9 @@ class ExiCapture(Elaboratable):
|
||||
# (~296 ns at 27 MHz) of slack -- unlike the old design, where
|
||||
# bit-level MISO timing crossed a domain with a 37 ns budget.
|
||||
rx_fifo = AsyncFIFO(width=8, depth=self._rx_depth,
|
||||
w_domain="exififo_w", r_domain="exi")
|
||||
w_domain="exififo_w", r_domain="sync")
|
||||
tx_fifo = AsyncFIFO(width=8, depth=self._tx_depth,
|
||||
w_domain="exi", r_domain="exififo_r")
|
||||
w_domain="sync", r_domain="exififo_r")
|
||||
m.submodules.rx_fifo = rx_fifo
|
||||
m.submodules.tx_fifo = tx_fifo
|
||||
|
||||
@@ -160,9 +160,9 @@ class ExiCapture(Elaboratable):
|
||||
# there is no longer any reason to detect it in a fast domain.
|
||||
cs_n_s = Signal(init=1)
|
||||
m.submodules.cs_sync = FFSynchronizer(self.spi_cs_n, cs_n_s,
|
||||
o_domain="exi", init=1)
|
||||
o_domain="sync", init=1)
|
||||
cs_n_prev = Signal(init=1)
|
||||
m.d.exi += cs_n_prev.eq(cs_n_s)
|
||||
m.d.sync += cs_n_prev.eq(cs_n_s)
|
||||
m.d.comb += self.cs_active.eq(~cs_n_s)
|
||||
|
||||
return m
|
||||
@@ -204,7 +204,7 @@ if __name__ == "__main__":
|
||||
if ctx.get(dut.rx_rdy):
|
||||
into.append(ctx.get(dut.rx_data))
|
||||
ctx.set(dut.rx_en, 1)
|
||||
await ctx.tick("exi").repeat(1)
|
||||
await ctx.tick("sync").repeat(1)
|
||||
ctx.set(dut.rx_en, 0)
|
||||
return True
|
||||
return False
|
||||
@@ -212,7 +212,7 @@ if __name__ == "__main__":
|
||||
async def push_tx(ctx, b):
|
||||
ctx.set(dut.tx_data, b)
|
||||
ctx.set(dut.tx_en, 1)
|
||||
await ctx.tick("exi").repeat(1)
|
||||
await ctx.tick("sync").repeat(1)
|
||||
ctx.set(dut.tx_en, 0)
|
||||
|
||||
async def do_txn(ctx, hdr, responses, n_data, rx_seen):
|
||||
@@ -226,7 +226,7 @@ if __name__ == "__main__":
|
||||
await spi_byte(ctx, h)
|
||||
for _ in range(20): # clock-idle gap
|
||||
await core_drain_rx(ctx, rx_seen)
|
||||
await ctx.tick("exi").repeat(1)
|
||||
await ctx.tick("sync").repeat(1)
|
||||
for r in responses:
|
||||
await push_tx(ctx, r)
|
||||
await ctx.delay(HP * (2))
|
||||
@@ -235,7 +235,7 @@ if __name__ == "__main__":
|
||||
await ctx.delay(HP * (HALF))
|
||||
for _ in range(20): # drain data-phase dummies
|
||||
await core_drain_rx(ctx, rx_seen)
|
||||
await ctx.tick("exi").repeat(1)
|
||||
await ctx.tick("sync").repeat(1)
|
||||
return miso
|
||||
|
||||
async def testbench(ctx):
|
||||
@@ -262,7 +262,7 @@ if __name__ == "__main__":
|
||||
errors.append(f"T2 flush failed — stale byte leaked: {[hex(b) for b in misoB]}")
|
||||
|
||||
sim = Simulator(dut)
|
||||
sim.add_clock(Period(MHz=24), domain="exi")
|
||||
sim.add_clock(Period(MHz=24), domain="sync")
|
||||
sim.add_testbench(testbench)
|
||||
|
||||
with sim.write_vcd("ExiCapture.vcd"):
|
||||
|
||||
Reference in New Issue
Block a user