diff --git a/soc/artiqlib/rtio/__init__.py b/soc/artiqlib/rtio/__init__.py index 5a73a6e20..f8e4aae70 100644 --- a/soc/artiqlib/rtio/__init__.py +++ b/soc/artiqlib/rtio/__init__.py @@ -3,10 +3,14 @@ from migen.bank.description import * from migen.genlib.fifo import SyncFIFOBuffered from migen.genlib.cdc import MultiReg +from types import SimpleNamespace + +from artiqlib.rtio import phy + class RTIOBankO(Module): - def __init__(self, channels, counter_width, fifo_depth): + def __init__(self, channels, counter_width, fine_ts_width, fifo_depth): self.sel = Signal(max=len(channels)) - self.timestamp = Signal(counter_width) + self.timestamp = Signal(counter_width+fine_ts_width) self.value = Signal() self.writable = Signal() self.we = Signal() @@ -19,14 +23,14 @@ class RTIOBankO(Module): self.sync += [ counter.eq(counter + 1), If(self.we & self.writable, - If(self.timestamp < counter + 2, self.underflow.eq(1)) + If(self.timestamp[fine_ts_width:] < counter + 2, self.underflow.eq(1)) ) ] fifos = [] for n, channel in enumerate(channels): fifo = SyncFIFOBuffered([ - ("timestamp", counter_width), ("value", 1)], + ("timestamp", counter_width+fine_ts_width), ("value", 2)], fifo_depth) self.submodules += fifo fifos.append(fifo) @@ -39,30 +43,50 @@ class RTIOBankO(Module): ] # FIFO read - time_hit = Signal() self.comb += [ - time_hit.eq(fifo.readable & - (fifo.dout.timestamp == counter)), - fifo.re.eq(time_hit) + channel.hit.eq(fifo.readable & + (fifo.dout.timestamp[fine_ts_width:] == counter)), + channel.value.eq(fifo.dout.value), + fifo.re.eq(channel.hit) ] - self.sync += If(time_hit, channel.eq(fifo.dout.value)) + if fine_ts_width: + self.comb += channel.fine_ts.eq(fifo.dout.timestamp[:fine_ts_width]) selfifo = Array(fifos)[self.sel] self.comb += self.writable.eq(selfifo.writable), self.level.eq(selfifo.level) class RTIO(Module, AutoCSR): - def __init__(self, channels, counter_width=32, ofifo_depth=8, ififo_depth=8): - self.submodules.bank_o = InsertReset(RTIOBankO(channels, counter_width, ofifo_depth)) + def __init__(self, phy, counter_width=32, ofifo_depth=8, ififo_depth=8): + # Extract info from PHY + if hasattr(phy.interface[0], "o_fine_ts"): + fine_ts_width = flen(channels[0].o_fine_ts) + else: + fine_ts_width = 0 + oes = [padif.oe for padif in phy.interface if hasattr(padif, "oe")] + # Submodules + self.submodules.bank_o = InsertReset(RTIOBankO( + [SimpleNamespace(hit=padif.o_set_value, + value=padif.o_value, + fine_ts=getattr(padif, "o_fine_ts", None)) + for padif in phy.interface], + counter_width, fine_ts_width, ofifo_depth)) + + # CSRs self._r_reset = CSRStorage(reset=1) + self._r_oe = CSRStorage(len(oes)) self._r_chan_sel = CSRStorage(flen(self.bank_o.sel)) - self._r_o_timestamp = CSRStorage(counter_width) + self._r_o_timestamp = CSRStorage(counter_width+fine_ts_width) self._r_o_value = CSRStorage() self._r_o_writable = CSRStatus() self._r_o_we = CSR() self._r_o_underflow = CSRStatus() self._r_o_level = CSRStatus(bits_for(ofifo_depth)) + # OE + self.comb += Cat(*oes).eq(self._r_oe.storage) + + # Output/Gate self.comb += [ self.bank_o.reset.eq(self._r_reset.storage), self.bank_o.sel.eq(self._r_chan_sel.storage), diff --git a/soc/artiqlib/rtio/phy.py b/soc/artiqlib/rtio/phy.py new file mode 100644 index 000000000..4e7f1de78 --- /dev/null +++ b/soc/artiqlib/rtio/phy.py @@ -0,0 +1,50 @@ +from migen.fhdl.std import * +from migen.genlib.cdc import MultiReg +from migen.genlib.record import Record + +class PHYBase(Module): + def __init__(self, fine_ts_bits, pads, output_only_pads): + self.interface = [] + + for pad in pads: + layout = [ + ("o_set_value", 1), + ("o_value", 1) + ] + if fine_ts_bits: + layout.append(("o_fine_ts", fine_ts_bits)) + if pad not in output_only_pads: + layout += [ + ("oe", 1), + ("i_detect", 1), + ("i_value", 1) + ] + if fine_ts_bits: + layout.append(("i_fine_ts", fine_ts_bits)) + self.interface.append(Record(layout)) + +class SimplePHY(PHYBase): + def __init__(self, pads, output_only_pads=set()): + PHYBase.__init__(self, 0, pads, output_only_pads) + + for pad, padif in zip(pads, self.interface): + o_pad_d1 = Signal() + o_pad = Signal() + self.sync += [ + If(padif.o_set_value, o_pad_d1.eq(padif.o_value)), + o_pad.eq(o_pad_d1) + ] + if pad in output_only_pads: + self.comb += pad.eq(o_pad) + else: + ts = TSTriple() + i_pad = Signal() + self.sync += ts.oe.eq(padif.oe) + self.comb += ts.o.eq(o_pad) + self.specials += MultiReg(ts.i, i_pad), \ + ts.get_tristate(pad) + + i_pad_d = Signal() + self.sync += i_pad_d.eq(i_pad) + self.comb += padif.i_detect.eq(i_pad ^ i_pad_d), \ + padif.i_value.eq(i_pad) diff --git a/soc/targets/artiq.py b/soc/targets/artiq.py index ad91d6902..e15d3cb7f 100644 --- a/soc/targets/artiq.py +++ b/soc/targets/artiq.py @@ -122,8 +122,13 @@ class ARTIQSoC(SDRAMSoC): self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", 0), platform.request("user_led", 1))) + self.comb += platform.request("ttl_tx_en").eq(1) - self.submodules.rtio = rtio.RTIO([platform.request("ttl", i) for i in range(4)]) + rtio_pads = [platform.request("ttl", i) for i in range(4)] + self.submodules.rtiophy = rtio.phy.SimplePHY(rtio_pads, + {rtio_pads[1], rtio_pads[2], rtio_pads[3]}) + self.submodules.rtio = rtio.RTIO(self.rtiophy) + self.submodules.dds = ad9858.AD9858(platform.request("dds")) self.add_wb_slave(lambda a: a[26:29] == 3, self.dds.bus)