forked from M-Labs/artiq-zynq
122 lines
4.6 KiB
Python
122 lines
4.6 KiB
Python
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
|
|
|
|
import endianness
|
|
|
|
|
|
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(32) # only read when shut down
|
|
self.bus_error = CSRStatus()
|
|
|
|
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.id.eq(0),
|
|
membus.w.valid.eq(self.sink.stb),
|
|
self.sink.ack.eq(membus.w.ready),
|
|
membus.w.data.eq(endianness.convert_signal(self.sink.data)),
|
|
membus.w.strb.eq(2**(dw//8)-1),
|
|
]
|
|
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(32 - 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)
|
|
self.sync += [
|
|
If(self.reset.re, self.bus_error.status.eq(0)),
|
|
If(membus.b.valid & membus.b.ready & (membus.b.resp != axi.Response.okay),
|
|
self.bus_error.status.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)
|
|
]
|