soc/rtio: input support

This commit is contained in:
Sebastien Bourdeauducq 2014-07-25 16:23:35 -06:00
parent 6b6b44b924
commit 9e4bc35354
4 changed files with 223 additions and 142 deletions

View File

@ -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
View 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)
]

View File

@ -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 = []
from artiqlib.rtio.rbus import create_rbus
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):
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
View 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