diff --git a/exi_bba/bba_register_file.py b/exi_bba/bba_register_file.py index d1b2b63..2267901 100644 --- a/exi_bba/bba_register_file.py +++ b/exi_bba/bba_register_file.py @@ -360,13 +360,6 @@ class BBARegisterFile(Elaboratable): spram_req.w_en.eq(1), sp_addr.eq(full + 1), outstanding.eq(1)] - # MISO is driven LIVE from the tx FIFO head, so a byte - # pushed now would show up during the pad slot rather than - # the first data slot. Park a filler byte there -- MISO is - # don't-care for the whole header -- so the real first - # response byte lands one slot later, where it belongs. - with m.If(~is_write & self.tx_rdy): - m.d.comb += [self.tx_data.eq(0x00), self.tx_en.eq(1)] m.next = "RHDR_PAD" with m.State("RHDR_PAD"): @@ -650,10 +643,7 @@ if __name__ == "__main__": await push_rx(ctx, (addr >> 8) & 0xFF) await push_rx(ctx, addr & 0xFF) await push_rx(ctx, 0x00) # turnaround / prefetch window - # The device parks a filler byte in the pad slot (MISO is don't-care - # for the whole header) so the first REAL response byte lands in data - # slot 0. This bench counts pushes rather than wire slots, so drop it. - result = (await collect_tx(ctx, length + 1))[1:] + result = await collect_tx(ctx, length) ctx.set(reg.cs_active, 0) await ctx.tick("exi").repeat(6) return result diff --git a/exi_bba/exi_capture.py b/exi_bba/exi_capture.py index 1d06f13..e038a3d 100644 --- a/exi_bba/exi_capture.py +++ b/exi_bba/exi_capture.py @@ -133,7 +133,7 @@ class ExiCapture(Elaboratable): # completion ≥2 → a data byte finished → pop to advance the head # The first data byte (data0) is served live from the head without a # pop; the pop after it advances the head to data1's response, etc. - txld_cnt = Signal(2) + txld_cnt = Signal(3) # counts header slots; data starts at hdr_slots m.d.comb += spi.tx_byte.eq(tx_fifo.r_data) @@ -165,13 +165,29 @@ class ExiCapture(Elaboratable): m.d.capture += drain.eq(self._tx_depth + 1) with m.Elif(drain != 0): m.d.capture += drain.eq(drain - 1) + # Pops must start at the FIRST DATA SLOT, which depends on the header + # length -- and the real protocol has two header forms (see + # docs/exi_protocol_real.md): + # byte0 bit7 = 1 register space, 4-byte header -> data at slot 4 + # byte0 bit7 = 0 command space, 2-byte header -> data at slot 2 + # This was hard-coded to 2, which is right only for the old invented + # 2-byte header; against a 4-byte header it consumes two bytes before + # the GC clocks any data and every read comes back shifted. + hdr_slots = Signal(3, init=2) + first_byte = Signal(init=1) + with m.If(spi.frame_start): + m.d.capture += first_byte.eq(1) + with m.Elif(spi.rx_valid & first_byte): + m.d.capture += [first_byte.eq(0), + hdr_slots.eq(Mux(spi.rx_byte[7], 4, 2))] + m.d.comb += tx_fifo.r_en.eq( - (spi.tx_load & (txld_cnt >= 2)) | (drain != 0) + (spi.tx_load & (txld_cnt >= hdr_slots)) | (drain != 0) ) with m.If(spi.frame_start): m.d.capture += txld_cnt.eq(0) - with m.Elif(spi.tx_load & (txld_cnt < 3)): + with m.Elif(spi.tx_load & (txld_cnt < 5)): m.d.capture += txld_cnt.eq(txld_cnt + 1) return m