From 39509f01d63fe9e8dd2cac626b3b002e8cdd8e33 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Fri, 13 Aug 2021 13:06:10 +0200 Subject: [PATCH] aux_controller: sram ported to axi, first attempt --- src/gateware/aux_controller.py | 198 ++++++++++++++++++++++++++++++++- 1 file changed, 192 insertions(+), 6 deletions(-) diff --git a/src/gateware/aux_controller.py b/src/gateware/aux_controller.py index 777f35da..cf06968f 100644 --- a/src/gateware/aux_controller.py +++ b/src/gateware/aux_controller.py @@ -9,18 +9,204 @@ from artiq.gateware.drtio.aux_controller import Transmitter, Receiver max_packet = 1024 +OUT_BURST_LEN = 10 +IN_BURST_LEN = 4 + +class SRAM(Module): + def __init__(self, mem_or_size, read_only=False, init=None, bus=None): + + # SRAM initialisation + + if bus is None: + bus = axi.Interface() + self.bus = bus + bus_data_width = len(self.bus.r.data) + bus_addr_width = len(self.bus.ar.addr) + if isinstance(mem_or_size, Memory): + assert(mem_or_size.width <= bus_data_width) + self.mem = mem_or_size + else: + self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init) + + # memory + port = self.mem.get_port(write_capable=not read_only, we_granularity=8) + self.specials += self.mem, port + + ### + + # probably will get removed + self.addr_base = CSRStorage(32) + self.trig_count = CSRStatus(32) + self.write_count = CSRStatus(32) + + self.trigger_stb = Signal() + + # Dout : Data received from CPU, output by SRAM <- port.dat_r + # Din : Data driven into SRAM, written into CPU <- port.dat_w + # When stb assert, index shows word being read/written, dout/din holds <- will be removed + # data + # + # Cycle: + # trigger_stb pulsed at start + # Then out_burst_len words are strobed out of dout + # Then, when din_ready is high, in_burst_len words are strobed in to din + self.dout_stb = Signal() # there's no strobe signal for SRAM + self.din_stb = Signal() + self.dout_index = Signal(bus_addr_width) # is this legal? + self.din_index = Signal(bus_addr_width) + self.din_ready = Signal() + self.dout = Signal(64) + self.din = Signal(64) + + # probably not correct here + self.sync += If(self.trigger_stb, self.trig_count.status.eq(self.trig_count.status+1)) + + ar, aw, w, r, b = attrgetter("ar", "aw", "w", "r", "b")(bus) + + ### Read + self.comb += [ + ar.addr.eq(port.adr), # shouldn't it be the other way around? + port.dat_r.eq(r.data), + r.ready.eq(1), + ar.burst.eq(axi.Burst.incr.value), + ar.len.eq(OUT_BURST_LEN-1), # Number of transfers in burst (0->1 transfer, 1->2 transfers...) + ar.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits + ar.cache.eq(0xf), + ] + + # read control + self.submodules.read_fsm = read_fsm = FSM(reset_state="IDLE") + read_fsm.act("IDLE", + If(self.trigger_stb, + ar.valid.eq(1), + If(ar.ready, + NextState("READ") + ).Else( + NextState("READ_START") + ) + ) + ) + read_fsm.act("READ_START", + ar.valid.eq(1), + If(ar.ready, + NextState("READ"), + ) + ) + read_fsm.act("READ", + ar.valid.eq(0), + If(r.last & r.valid, + NextState("IDLE") + ) + ) + + self.sync += [ + If(read_fsm.ongoing("IDLE"), + self.dout_index.eq(0) + ).Else(If(r.valid & read_fsm.ongoing("READ"), + self.dout_index.eq(self.dout_index+1), + port.adr.eq(port.adr + self.dout_index) # update address in the port + ) + ) + ] + + # possibly unnecessary too + self.comb += self.dout_stb.eq(r.valid & r.ready) + + ### Write + self.comb += [ + w.data.eq(port.dat_w), + aw.addr.eq(port.addr), # shouldn't it be the other way around? + w.strb.eq(0xff), + aw.burst.eq(axi.Burst.incr.value), + aw.len.eq(IN_BURST_LEN-1), # Number of transfers in burst minus 1 + aw.size.eq(3), # Width of burst: 3 = 8 bytes = 64 bits + aw.cache.eq(0xf), + b.ready.eq(1), + ] + + self.submodules.write_fsm = write_fsm = FSM(reset_state="IDLE") + write_fsm.act("IDLE", + w.valid.eq(0), + aw.valid.eq(0), + If(self.trigger_stb, + aw.valid.eq(1), + If(aw.ready, # assumes aw.ready is not randomly deasserted + NextState("DATA_WAIT") + ).Else( + NextState("AW_READY_WAIT") + ) + ) + ) + write_fsm.act("AW_READY_WAIT", + aw.valid.eq(1), + If(aw.ready, + NextState("DATA_WAIT"), + ) + ) + write_fsm.act("DATA_WAIT", + aw.valid.eq(0), + If(self.din_ready, # probably unnecessary? + w.valid.eq(1), + NextState("WRITE") + ) + ) + write_fsm.act("WRITE", + w.valid.eq(1), + If(w.ready & w.last, + NextState("IDLE") + ) + ) + + # refer to port.we instead + self.sync += If(w.ready & w.valid, port.we.eq(1)) + + self.sync += [ + If(write_fsm.ongoing("IDLE"), + self.din_index.eq(0) # replace with address? + ), # but need to synchronise the address too + If(w.ready & w.valid, self.din_index.eq(self.din_index+1), port.adr.eq(port.addr+self.din_index)) + ] + + self.comb += [ + w.last.eq(0), + If(self.din_index==aw.len, w.last.eq(1)) + ] + + # check if necessary + self.comb += self.din_stb.eq(w.valid & w.ready) + + + # # generate write enable signal + # if not read_only: + # # replace with? stb -> w.strb we->w.ready? sel[i]-> r.valid + # self.comb += [port.we[i].eq(self.bus.cyc & self.bus.w.strb & self.bus.w.ready & self.bus.r.valid) + # for i in range(4)] + # # address and data + # self.comb += [ + # self.bus.r.ready.eq(self.bus.r.valid), # AXI handshake? + # port.adr.eq(self.bus.ar.addr[:len(port.adr)]), + # self.bus.r.data.eq(port.dat_r) + # ] + # if not read_only: + # self.comb += port.dat_w.eq(self.bus.w.data), + # # generate ack + # self.sync += [ + # self.bus.ack.eq(0), + # If(self.bus.cyc & self.bus.stb & ~self.bus.ack, self.bus.ack.eq(1)) + # ] + # TODO: FullMemoryWE should be applied by migen.build @FullMemoryWE() class DRTIOAuxController(Module): def __init__(self, link_layer): self.bus = axi.Interface() - self.submodules.transmitter = Transmitter(link_layer, len(self.bus.data_width)) - self.submodules.receiver = Receiver(link_layer, len(self.bus.data_width)) + self.submodules.transmitter = Transmitter(link_layer, len(self.bus.w.data)) + self.submodules.receiver = Receiver(link_layer, len(self.bus.w.data)) - # probably will need to make axi.SDRAM based on wb code - tx_sdram_if = wishbone.SRAM(self.transmitter.mem, read_only=False) - rx_sdram_if = wishbone.SRAM(self.receiver.mem, read_only=True) - wsb = log2_int(len(self.bus.data_width)//8) + # probably will need to make axi.SRAM based on wb code + tx_sdram_if = SRAM(self.transmitter.mem, read_only=False) + rx_sdram_if = SRAM(self.receiver.mem, read_only=True) + wsb = log2_int(len(self.w.data)//8) decoder = axi.AddressDecoder(self.bus, [(lambda a: a[log2_int(max_packet)-wsb] == 0, tx_sdram_if.bus), (lambda a: a[log2_int(max_packet)-wsb] == 1, rx_sdram_if.bus)],