diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index ea390bd2c..5ad5f6591 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -2,8 +2,6 @@ from functools import reduce from operator import and_ from migen import * -from migen.genlib.record import Record -from migen.genlib.fifo import AsyncFIFO from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * @@ -13,141 +11,7 @@ from artiq.gateware.rtio import rtlink from artiq.gateware.rtio.channel import * from artiq.gateware.rtio.cdc import * from artiq.gateware.rtio.sed.core import * - - -class _InputManager(Module): - def __init__(self, interface, coarse_ts, fifo_depth): - data_width = rtlink.get_data_width(interface) - fine_ts_width = rtlink.get_fine_ts_width(interface) - - ev_layout = [] - if data_width: - ev_layout.append(("data", data_width)) - if interface.timestamped: - ev_layout.append(("timestamp", len(coarse_ts) + fine_ts_width)) - self.ev = Record(ev_layout) - - self.readable = Signal() - self.re = Signal() - - self.overflow = Signal() # pulsed - - # # # - - fifo = ClockDomainsRenamer({"read": "rsys", "write": "rio"})( - AsyncFIFO(layout_len(ev_layout), fifo_depth)) - self.submodules += fifo - fifo_in = Record(ev_layout) - fifo_out = Record(ev_layout) - self.comb += [ - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout) - ] - - # latency compensation - if interface.delay: - counter_rtio = Signal.like(coarse_ts, reset_less=True) - self.sync.rtio += counter_rtio.eq(coarse_ts - - (interface.delay + 1)) - else: - counter_rtio = coarse_ts - - # FIFO write - if data_width: - self.comb += fifo_in.data.eq(interface.data) - if interface.timestamped: - if fine_ts_width: - full_ts = Cat(interface.fine_ts, counter_rtio) - else: - full_ts = counter_rtio - self.comb += fifo_in.timestamp.eq(full_ts) - self.comb += fifo.we.eq(interface.stb) - - # FIFO read - self.comb += [ - self.ev.eq(fifo_out), - self.readable.eq(fifo.readable), - fifo.re.eq(self.re) - ] - - overflow_transfer = BlindTransfer() - self.submodules += overflow_transfer - self.comb += [ - overflow_transfer.i.eq(fifo.we & ~fifo.writable), - self.overflow.eq(overflow_transfer.o), - ] - - -class _Inputs(Module): - def __init__(self, interface, coarse_ts, channels): - self.cri = interface - - # Inputs - i_statuses = [] - i_datas, i_timestamps = [], [] - i_ack = Signal() - sel = self.cri.chan_sel[:16] - for n, channel in enumerate(channels): - if isinstance(channel, LogChannel): - i_datas.append(0) - i_timestamps.append(0) - i_statuses.append(0) - continue - - if channel.interface.i is not None: - selected = Signal() - self.comb += selected.eq(sel == n) - - i_manager = _InputManager(channel.interface.i, coarse_ts, - channel.ififo_depth) - self.submodules += i_manager - - if hasattr(i_manager.ev, "data"): - i_datas.append(i_manager.ev.data) - else: - i_datas.append(0) - if channel.interface.i.timestamped: - ts_shift = (len(self.cri.i_timestamp) - len(i_manager.ev.timestamp)) - i_timestamps.append(i_manager.ev.timestamp << ts_shift) - else: - i_timestamps.append(0) - - overflow = Signal() - self.sync.rsys += [ - If(selected & i_ack, - overflow.eq(0)), - If(i_manager.overflow, - overflow.eq(1)) - ] - self.comb += i_manager.re.eq(selected & i_ack & ~overflow) - i_statuses.append(Cat(i_manager.readable & ~overflow, overflow)) - - else: - i_datas.append(0) - i_timestamps.append(0) - i_statuses.append(0) - - i_status_raw = Signal(2) - self.comb += i_status_raw.eq(Array(i_statuses)[sel]) - input_timeout = Signal.like(self.cri.timestamp) - input_pending = Signal() - self.sync.rsys += [ - i_ack.eq(0), - If(i_ack, - self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), - self.cri.i_data.eq(Array(i_datas)[sel]), - self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), - ), - If((self.cri.counter >= input_timeout) | (i_status_raw != 0), - If(input_pending, i_ack.eq(1)), - input_pending.eq(0) - ), - If(self.cri.cmd == cri.commands["read"], - input_timeout.eq(self.cri.timestamp), - input_pending.eq(1), - self.cri.i_status.eq(0b100) - ) - ] +from artiq.gateware.rtio.input_collector import * class Core(Module, AutoCSR): @@ -190,17 +54,17 @@ class Core(Module, AutoCSR): self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy) # TSC - fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) - for channel in channels), - max(rtlink.get_fine_ts_width(channel.interface.i) - for channel in channels)) - coarse_ts = Signal(64-fine_ts_width) + glbl_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) + for channel in channels), + max(rtlink.get_fine_ts_width(channel.interface.i) + for channel in channels)) + coarse_ts = Signal(64-glbl_fine_ts_width) self.sync.rtio += coarse_ts.eq(coarse_ts + 1) coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) self.submodules += coarse_ts_cdc self.comb += [ coarse_ts_cdc.i.eq(coarse_ts), - self.cri.counter.eq(coarse_ts_cdc.o << fine_ts_width) + self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width) ] # Asychronous output errors @@ -219,13 +83,12 @@ class Core(Module, AutoCSR): ] self.comb += self.async_error.w.eq(Cat(o_collision, o_busy)) - # Inputs - inputs = _Inputs(self.cri, coarse_ts, channels) - self.submodules += inputs - # Outputs - outputs = SED(channels, "async", - quash_channels=[n for n, c in enumerate(channels) if isinstance(c, LogChannel)], + # Outputs/Inputs + quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] + + outputs = SED(channels, glbl_fine_ts_width, "async", + quash_channels=quash_channels, interface=self.cri) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) @@ -234,3 +97,8 @@ class Core(Module, AutoCSR): o_collision_sync.i.eq(outputs.collision), o_busy_sync.i.eq(outputs.busy) ] + + inputs = InputCollector(channels, glbl_fine_ts_width, "async", + quash_channels=quash_channels, + interface=self.cri) + self.submodules += inputs