forked from M-Labs/artiq
soc/rtio: input support
This commit is contained in:
parent
6b6b44b924
commit
9e4bc35354
@ -1,111 +1,2 @@
|
||||
from migen.fhdl.std import *
|
||||
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, fine_ts_width, fifo_depth):
|
||||
self.sel = Signal(max=len(channels))
|
||||
self.timestamp = Signal(counter_width+fine_ts_width)
|
||||
self.value = Signal()
|
||||
self.writable = Signal()
|
||||
self.we = Signal()
|
||||
self.underflow = Signal()
|
||||
self.level = Signal(bits_for(fifo_depth))
|
||||
|
||||
###
|
||||
|
||||
counter = Signal(counter_width)
|
||||
self.sync += [
|
||||
counter.eq(counter + 1),
|
||||
If(self.we & self.writable,
|
||||
If(self.timestamp[fine_ts_width:] < counter + 2, self.underflow.eq(1))
|
||||
)
|
||||
]
|
||||
|
||||
fifos = []
|
||||
for n, channel in enumerate(channels):
|
||||
fifo = SyncFIFOBuffered([
|
||||
("timestamp", counter_width+fine_ts_width), ("value", 2)],
|
||||
fifo_depth)
|
||||
self.submodules += fifo
|
||||
fifos.append(fifo)
|
||||
|
||||
# FIFO write
|
||||
self.comb += [
|
||||
fifo.din.timestamp.eq(self.timestamp),
|
||||
fifo.din.value.eq(self.value),
|
||||
fifo.we.eq(self.we & (self.sel == n))
|
||||
]
|
||||
|
||||
# FIFO read
|
||||
self.comb += [
|
||||
channel.hit.eq(fifo.readable &
|
||||
(fifo.dout.timestamp[fine_ts_width:] == counter)),
|
||||
channel.value.eq(fifo.dout.value),
|
||||
fifo.re.eq(channel.hit)
|
||||
]
|
||||
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, 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_chan_sel = CSRStorage(flen(self.bank_o.sel))
|
||||
|
||||
self._r_oe = CSR()
|
||||
|
||||
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
|
||||
oes = []
|
||||
for n, padif in enumerate(phy.interface):
|
||||
if hasattr(padif, "oe"):
|
||||
self.sync += \
|
||||
If(self._r_oe.re & (self._r_chan_sel.storage == n),
|
||||
padif.oe.eq(self._r_oe.r)
|
||||
)
|
||||
oes.append(padif.oe)
|
||||
else:
|
||||
oes.append(1)
|
||||
self.comb += self._r_oe.w.eq(Array(oes)[self._r_chan_sel.storage])
|
||||
|
||||
# Output/Gate
|
||||
self.comb += [
|
||||
self.bank_o.reset.eq(self._r_reset.storage),
|
||||
self.bank_o.sel.eq(self._r_chan_sel.storage),
|
||||
self.bank_o.timestamp.eq(self._r_o_timestamp.storage),
|
||||
self.bank_o.value.eq(self._r_o_value.storage),
|
||||
self._r_o_writable.status.eq(self.bank_o.writable),
|
||||
self.bank_o.we.eq(self._r_o_we.re),
|
||||
self._r_o_underflow.status.eq(self.bank_o.underflow),
|
||||
self._r_o_level.status.eq(self.bank_o.level)
|
||||
]
|
||||
from artiqlib.rtio.core import RTIO
|
||||
|
183
soc/artiqlib/rtio/core.py
Normal file
183
soc/artiqlib/rtio/core.py
Normal file
@ -0,0 +1,183 @@
|
||||
from migen.fhdl.std import *
|
||||
from migen.bank.description import *
|
||||
from migen.genlib.fifo import SyncFIFOBuffered
|
||||
from migen.genlib.cdc import MultiReg
|
||||
|
||||
from artiqlib.rtio.rbus import get_fine_ts_width
|
||||
|
||||
class _RTIOBankO(Module):
|
||||
def __init__(self, rbus, counter_width, fine_ts_width, fifo_depth, counter_init):
|
||||
self.sel = Signal(max=len(rbus))
|
||||
self.timestamp = Signal(counter_width+fine_ts_width)
|
||||
self.value = Signal(2)
|
||||
self.writable = Signal()
|
||||
self.we = Signal()
|
||||
self.underflow = Signal()
|
||||
self.level = Signal(bits_for(fifo_depth))
|
||||
|
||||
###
|
||||
|
||||
counter = Signal(counter_width, reset=counter_init)
|
||||
self.sync += [
|
||||
counter.eq(counter + 1),
|
||||
If(self.we & self.writable,
|
||||
If(self.timestamp[fine_ts_width:] < counter + 2, self.underflow.eq(1))
|
||||
)
|
||||
]
|
||||
|
||||
fifos = []
|
||||
for n, chif in enumerate(rbus):
|
||||
fifo = SyncFIFOBuffered([
|
||||
("timestamp", counter_width+fine_ts_width), ("value", 2)],
|
||||
fifo_depth)
|
||||
self.submodules += fifo
|
||||
fifos.append(fifo)
|
||||
|
||||
# FIFO write
|
||||
self.comb += [
|
||||
fifo.din.timestamp.eq(self.timestamp),
|
||||
fifo.din.value.eq(self.value),
|
||||
fifo.we.eq(self.we & (self.sel == n))
|
||||
]
|
||||
|
||||
# FIFO read
|
||||
self.comb += [
|
||||
chif.o_stb.eq(fifo.readable &
|
||||
(fifo.dout.timestamp[fine_ts_width:] == counter)),
|
||||
chif.o_value.eq(fifo.dout.value),
|
||||
fifo.re.eq(chif.o_stb)
|
||||
]
|
||||
if fine_ts_width:
|
||||
self.comb += chif.o_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 _RTIOBankI(Module):
|
||||
def __init__(self, rbus, counter_width, fine_ts_width, fifo_depth):
|
||||
self.sel = Signal(max=len(rbus))
|
||||
self.timestamp = Signal(counter_width+fine_ts_width)
|
||||
self.value = Signal()
|
||||
self.readable = Signal()
|
||||
self.re = Signal()
|
||||
self.overflow = Signal()
|
||||
|
||||
###
|
||||
|
||||
counter = Signal(counter_width)
|
||||
self.sync += counter.eq(counter + 1)
|
||||
|
||||
timestamps = []
|
||||
values = []
|
||||
readables = []
|
||||
overflows = []
|
||||
for n, chif in enumerate(rbus):
|
||||
if hasattr(chif, "oe"):
|
||||
sensitivity = Signal(2)
|
||||
self.sync += If(~chif.oe & chif.o_stb,
|
||||
sensitivity.eq(chif.o_value))
|
||||
|
||||
fifo = SyncFIFOBuffered([
|
||||
("timestamp", counter_width+fine_ts_width), ("value", 1)],
|
||||
fifo_depth)
|
||||
self.submodules += fifo
|
||||
|
||||
# FIFO write
|
||||
if fine_ts_width:
|
||||
full_ts = Cat(chif.i_fine_ts, counter)
|
||||
else:
|
||||
full_ts = counter
|
||||
self.comb += [
|
||||
fifo.din.timestamp.eq(full_ts),
|
||||
fifo.din.value.eq(chif.i_value),
|
||||
fifo.we.eq(~chif.oe & chif.i_stb &
|
||||
((chif.i_value & sensitivity[0]) | (~chif.i_value & sensitivity[1])))
|
||||
]
|
||||
|
||||
# FIFO read
|
||||
timestamps.append(fifo.dout.timestamp)
|
||||
values.append(fifo.dout.value)
|
||||
readables.append(fifo.readable)
|
||||
self.comb += fifo.re.eq(self.re & (self.sel == n))
|
||||
|
||||
overflow = Signal()
|
||||
self.sync += If(fifo.we & ~fifo.writable, overflow.eq(1))
|
||||
overflows.append(overflow)
|
||||
else:
|
||||
timestamps.append(0)
|
||||
values.append(0)
|
||||
readables.append(0)
|
||||
overflows.append(0)
|
||||
|
||||
self.comb += [
|
||||
self.timestamp.eq(Array(timestamps)[self.sel]),
|
||||
self.value.eq(Array(values)[self.sel]),
|
||||
self.readable.eq(Array(readables)[self.sel]),
|
||||
self.overflow.eq(Array(overflows)[self.sel])
|
||||
]
|
||||
|
||||
class RTIO(Module, AutoCSR):
|
||||
def __init__(self, phy, counter_width=32, ofifo_depth=8, ififo_depth=8):
|
||||
fine_ts_width = get_fine_ts_width(phy.rbus)
|
||||
|
||||
# Submodules
|
||||
self.submodules.bank_o = InsertReset(_RTIOBankO(phy.rbus,
|
||||
counter_width, fine_ts_width, ofifo_depth,
|
||||
phy.loopback_latency))
|
||||
self.submodules.bank_i = InsertReset(_RTIOBankI(phy.rbus,
|
||||
counter_width, fine_ts_width, ofifo_depth))
|
||||
|
||||
# CSRs
|
||||
self._r_reset = CSRStorage(reset=1)
|
||||
self._r_chan_sel = CSRStorage(flen(self.bank_o.sel))
|
||||
|
||||
self._r_oe = CSR()
|
||||
|
||||
self._r_o_timestamp = CSRStorage(counter_width+fine_ts_width)
|
||||
self._r_o_value = CSRStorage(2)
|
||||
self._r_o_writable = CSRStatus()
|
||||
self._r_o_we = CSR()
|
||||
self._r_o_underflow = CSRStatus()
|
||||
self._r_o_level = CSRStatus(bits_for(ofifo_depth))
|
||||
|
||||
self._r_i_timestamp = CSRStatus(counter_width+fine_ts_width)
|
||||
self._r_i_value = CSRStatus()
|
||||
self._r_i_readable = CSRStatus()
|
||||
self._r_i_re = CSR()
|
||||
self._r_i_overflow = CSRStatus()
|
||||
|
||||
# OE
|
||||
oes = []
|
||||
for n, chif in enumerate(phy.rbus):
|
||||
if hasattr(chif, "oe"):
|
||||
self.sync += \
|
||||
If(self._r_oe.re & (self._r_chan_sel.storage == n),
|
||||
chif.oe.eq(self._r_oe.r)
|
||||
)
|
||||
oes.append(chif.oe)
|
||||
else:
|
||||
oes.append(1)
|
||||
self.comb += self._r_oe.w.eq(Array(oes)[self._r_chan_sel.storage])
|
||||
|
||||
# Output/Gate
|
||||
self.comb += [
|
||||
self.bank_o.reset.eq(self._r_reset.storage),
|
||||
self.bank_o.sel.eq(self._r_chan_sel.storage),
|
||||
self.bank_o.timestamp.eq(self._r_o_timestamp.storage),
|
||||
self.bank_o.value.eq(self._r_o_value.storage),
|
||||
self._r_o_writable.status.eq(self.bank_o.writable),
|
||||
self.bank_o.we.eq(self._r_o_we.re),
|
||||
self._r_o_underflow.status.eq(self.bank_o.underflow),
|
||||
self._r_o_level.status.eq(self.bank_o.level)
|
||||
]
|
||||
|
||||
# Input
|
||||
self.comb += [
|
||||
self.bank_i.reset.eq(self._r_reset.storage),
|
||||
self.bank_i.sel.eq(self._r_chan_sel.storage),
|
||||
self._r_i_timestamp.status.eq(self.bank_i.timestamp),
|
||||
self._r_i_value.status.eq(self.bank_i.value),
|
||||
self._r_i_readable.status.eq(self.bank_i.readable),
|
||||
self.bank_i.re.eq(self._r_i_re.re),
|
||||
self._r_i_overflow.status.eq(self.bank_i.overflow)
|
||||
]
|
@ -1,50 +1,29 @@
|
||||
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))
|
||||
from artiqlib.rtio.rbus import create_rbus
|
||||
|
||||
class SimplePHY(PHYBase):
|
||||
class SimplePHY(Module):
|
||||
def __init__(self, pads, output_only_pads=set()):
|
||||
PHYBase.__init__(self, 0, pads, output_only_pads)
|
||||
self.rbus = create_rbus(0, pads, output_only_pads)
|
||||
self.loopback_latency = 3
|
||||
|
||||
for pad, padif in zip(pads, self.interface):
|
||||
o_pad_d1 = Signal()
|
||||
###
|
||||
|
||||
for pad, chif in zip(pads, self.rbus):
|
||||
o_pad = Signal()
|
||||
self.sync += [
|
||||
If(padif.o_set_value, o_pad_d1.eq(padif.o_value)),
|
||||
o_pad.eq(o_pad_d1)
|
||||
]
|
||||
self.sync += If(chif.o_stb, o_pad.eq(chif.o_value))
|
||||
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.sync += ts.oe.eq(chif.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)
|
||||
self.comb += chif.i_stb.eq(i_pad ^ i_pad_d), \
|
||||
chif.i_value.eq(i_pad)
|
||||
|
28
soc/artiqlib/rtio/rbus.py
Normal file
28
soc/artiqlib/rtio/rbus.py
Normal file
@ -0,0 +1,28 @@
|
||||
from migen.fhdl.std import *
|
||||
from migen.genlib.record import Record
|
||||
|
||||
def create_rbus(fine_ts_bits, pads, output_only_pads):
|
||||
rbus = []
|
||||
for pad in pads:
|
||||
layout = [
|
||||
("o_stb", 1),
|
||||
("o_value", 2)
|
||||
]
|
||||
if fine_ts_bits:
|
||||
layout.append(("o_fine_ts", fine_ts_bits))
|
||||
if pad not in output_only_pads:
|
||||
layout += [
|
||||
("oe", 1),
|
||||
("i_stb", 1),
|
||||
("i_value", 1)
|
||||
]
|
||||
if fine_ts_bits:
|
||||
layout.append(("i_fine_ts", fine_ts_bits))
|
||||
rbus.append(Record(layout))
|
||||
return rbus
|
||||
|
||||
def get_fine_ts_width(rbus):
|
||||
if hasattr(rbus[0], "o_fine_ts"):
|
||||
return flen(rbus[0].o_fine_ts)
|
||||
else:
|
||||
return 0
|
Loading…
Reference in New Issue
Block a user