forked from M-Labs/artiq
soc/rtio: separate PHY, add OE and fine timestamp in FIFO
This commit is contained in:
parent
f390e9a7d1
commit
f03ae5e5b0
|
@ -3,10 +3,14 @@ from migen.bank.description import *
|
||||||
from migen.genlib.fifo import SyncFIFOBuffered
|
from migen.genlib.fifo import SyncFIFOBuffered
|
||||||
from migen.genlib.cdc import MultiReg
|
from migen.genlib.cdc import MultiReg
|
||||||
|
|
||||||
|
from types import SimpleNamespace
|
||||||
|
|
||||||
|
from artiqlib.rtio import phy
|
||||||
|
|
||||||
class RTIOBankO(Module):
|
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.sel = Signal(max=len(channels))
|
||||||
self.timestamp = Signal(counter_width)
|
self.timestamp = Signal(counter_width+fine_ts_width)
|
||||||
self.value = Signal()
|
self.value = Signal()
|
||||||
self.writable = Signal()
|
self.writable = Signal()
|
||||||
self.we = Signal()
|
self.we = Signal()
|
||||||
|
@ -19,14 +23,14 @@ class RTIOBankO(Module):
|
||||||
self.sync += [
|
self.sync += [
|
||||||
counter.eq(counter + 1),
|
counter.eq(counter + 1),
|
||||||
If(self.we & self.writable,
|
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 = []
|
fifos = []
|
||||||
for n, channel in enumerate(channels):
|
for n, channel in enumerate(channels):
|
||||||
fifo = SyncFIFOBuffered([
|
fifo = SyncFIFOBuffered([
|
||||||
("timestamp", counter_width), ("value", 1)],
|
("timestamp", counter_width+fine_ts_width), ("value", 2)],
|
||||||
fifo_depth)
|
fifo_depth)
|
||||||
self.submodules += fifo
|
self.submodules += fifo
|
||||||
fifos.append(fifo)
|
fifos.append(fifo)
|
||||||
|
@ -39,30 +43,50 @@ class RTIOBankO(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
# FIFO read
|
# FIFO read
|
||||||
time_hit = Signal()
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
time_hit.eq(fifo.readable &
|
channel.hit.eq(fifo.readable &
|
||||||
(fifo.dout.timestamp == counter)),
|
(fifo.dout.timestamp[fine_ts_width:] == counter)),
|
||||||
fifo.re.eq(time_hit)
|
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]
|
selfifo = Array(fifos)[self.sel]
|
||||||
self.comb += self.writable.eq(selfifo.writable), self.level.eq(selfifo.level)
|
self.comb += self.writable.eq(selfifo.writable), self.level.eq(selfifo.level)
|
||||||
|
|
||||||
class RTIO(Module, AutoCSR):
|
class RTIO(Module, AutoCSR):
|
||||||
def __init__(self, channels, counter_width=32, ofifo_depth=8, ififo_depth=8):
|
def __init__(self, phy, counter_width=32, ofifo_depth=8, ififo_depth=8):
|
||||||
self.submodules.bank_o = InsertReset(RTIOBankO(channels, counter_width, ofifo_depth))
|
# 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_reset = CSRStorage(reset=1)
|
||||||
|
self._r_oe = CSRStorage(len(oes))
|
||||||
self._r_chan_sel = CSRStorage(flen(self.bank_o.sel))
|
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_value = CSRStorage()
|
||||||
self._r_o_writable = CSRStatus()
|
self._r_o_writable = CSRStatus()
|
||||||
self._r_o_we = CSR()
|
self._r_o_we = CSR()
|
||||||
self._r_o_underflow = CSRStatus()
|
self._r_o_underflow = CSRStatus()
|
||||||
self._r_o_level = CSRStatus(bits_for(ofifo_depth))
|
self._r_o_level = CSRStatus(bits_for(ofifo_depth))
|
||||||
|
|
||||||
|
# OE
|
||||||
|
self.comb += Cat(*oes).eq(self._r_oe.storage)
|
||||||
|
|
||||||
|
# Output/Gate
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.bank_o.reset.eq(self._r_reset.storage),
|
self.bank_o.reset.eq(self._r_reset.storage),
|
||||||
self.bank_o.sel.eq(self._r_chan_sel.storage),
|
self.bank_o.sel.eq(self._r_chan_sel.storage),
|
||||||
|
|
|
@ -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)
|
|
@ -122,8 +122,13 @@ class ARTIQSoC(SDRAMSoC):
|
||||||
|
|
||||||
self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", 0),
|
self.submodules.leds = gpio.GPIOOut(Cat(platform.request("user_led", 0),
|
||||||
platform.request("user_led", 1)))
|
platform.request("user_led", 1)))
|
||||||
|
|
||||||
self.comb += platform.request("ttl_tx_en").eq(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.submodules.dds = ad9858.AD9858(platform.request("dds"))
|
||||||
self.add_wb_slave(lambda a: a[26:29] == 3, self.dds.bus)
|
self.add_wb_slave(lambda a: a[26:29] == 3, self.dds.bus)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue