diff --git a/src/gateware/analyzer.py b/src/gateware/analyzer.py new file mode 100644 index 00000000..7a8f4d10 --- /dev/null +++ b/src/gateware/analyzer.py @@ -0,0 +1,111 @@ +from migen import * + +from misoc.interconnect.csr import * +from misoc.interconnect import stream +from migen_axi.interconnect import axi + +from artiq.gateware.rtio.analyzer import message_len, MessageEncoder + + +class AXIDMAWriter(Module, AutoCSR): + def __init__(self, membus, max_outstanding_requests): + aw = len(membus.aw.addr) + dw = len(membus.w.data) + assert message_len % dw == 0 + burst_length = message_len//dw + alignment_bits = log2_int(message_len//8) + + self.reset = CSR() # only apply when shut down + # All numbers in bytes + self.base_address = CSRStorage(aw, alignment_bits=alignment_bits) + self.last_address = CSRStorage(aw, alignment_bits=alignment_bits) + self.byte_count = CSRStatus(64) # only read when shut down + + self.make_request = Signal() + self.sink = stream.Endpoint([("data", dw)]) + + # # # + + outstanding_requests = Signal(max=max_outstanding_requests+1) + current_address = Signal(aw - alignment_bits) + self.comb += [ + membus.aw.addr.eq(Cat(C(0, alignment_bits), current_address)), + membus.aw.id.eq(0), # Same ID for all transactions to forbid reordering. + membus.aw.burst.eq(axi.Burst.incr.value), + membus.aw.len.eq(burst_length-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...). + membus.aw.size.eq(log2_int(dw//8)), # Width of burst: 3 = 8 bytes = 64 bits. + membus.aw.cache.eq(0xf), + membus.aw.valid.eq(outstanding_requests != 0), + ] + self.sync += [ + outstanding_requests.eq(outstanding_requests + self.make_request - (membus.aw.valid & membus.aw.ready)), + + If(self.reset.re, + current_address.eq(self.base_address.storage)), + If(membus.aw.valid & membus.aw.ready, + If(current_address == self.last_address.storage, + current_address.eq(self.base_address.storage) + ).Else( + current_address.eq(current_address + 1) + ) + ) + ] + + self.comb += [ + membus.w.valid.eq(self.sink.stb), + self.sink.ack.eq(membus.w.ready), + membus.w.data.eq(self.sink.data) + ] + beat_count = Signal(max=burst_length) + self.sync += [ + If(membus.w.valid & membus.w.ready, + membus.w.last.eq(0), + If(membus.w.last, + beat_count.eq(0) + ).Else( + If(beat_count == burst_length-2, membus.w.last.eq(1)), + beat_count.eq(beat_count + 1) + ) + ) + ] + + message_count = Signal(64 - log2_int(message_len//8)) + self.comb += self.byte_count.status.eq( + message_count << log2_int(message_len//8)) + self.sync += [ + If(self.reset.re, message_count.eq(0)), + If(membus.w.valid & membus.w.ready & membus.w.last, message_count.eq(message_count + 1)) + ] + + self.comb += membus.b.ready.eq(1) + + +class Analyzer(Module, AutoCSR): + def __init__(self, tsc, cri, membus, fifo_depth=128): + # shutdown procedure: set enable to 0, wait until busy=0 + self.enable = CSRStorage() + self.busy = CSRStatus() + + self.submodules.message_encoder = MessageEncoder( + tsc, cri, self.enable.storage) + self.submodules.fifo = stream.SyncFIFO( + [("data", message_len)], fifo_depth, True) + self.submodules.converter = stream.Converter( + message_len, len(membus.w.data), reverse=True) + self.submodules.dma = AXIDMAWriter(membus, max_outstanding_requests=fifo_depth) + + enable_r = Signal() + self.sync += [ + enable_r.eq(self.enable.storage), + If(self.enable.storage & ~enable_r, + self.busy.status.eq(1)), + If(self.dma.sink.stb & self.dma.sink.ack & self.dma.sink.eop, + self.busy.status.eq(0)) + ] + + self.comb += [ + self.message_encoder.source.connect(self.fifo.sink), + self.fifo.source.connect(self.converter.sink), + self.converter.source.connect(self.dma.sink), + self.dma.make_request.eq(self.fifo.sink.stb & self.fifo.sink.ack) + ] diff --git a/src/gateware/zc706.py b/src/gateware/zc706.py index cb94a1ef..18c4ea4f 100755 --- a/src/gateware/zc706.py +++ b/src/gateware/zc706.py @@ -13,8 +13,8 @@ from misoc.integration import cpu_interface from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2 - import dma +import analyzer class RTIOCRG(Module, AutoCSR): @@ -96,6 +96,10 @@ class ZC706(SoCCore): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") + self.submodules.rtio_analyzer = analyzer.Analyzer(self.rtio_tsc, self.rtio_core.cri, + self.ps7.s_axi_hp1) + self.csr_devices.append("rtio_analyzer") + class Simple(ZC706): def __init__(self):