forked from M-Labs/artiq
245 lines
8.4 KiB
Python
245 lines
8.4 KiB
Python
from fractions import Fraction
|
|
|
|
from migen.fhdl.std import *
|
|
from migen.bank.description import *
|
|
from migen.genlib.fifo import SyncFIFO
|
|
|
|
from artiqlib.rtio.rbus import get_fine_ts_width
|
|
|
|
|
|
class _RTIOBankO(Module):
|
|
def __init__(self, rbus, counter, fine_ts_width, fifo_depth):
|
|
counter_width = flen(counter)
|
|
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.replace = Signal()
|
|
self.underflow = Signal()
|
|
self.level = Signal(bits_for(fifo_depth))
|
|
|
|
# # #
|
|
|
|
# detect underflows
|
|
self.sync += \
|
|
If((self.we & self.writable) | self.replace,
|
|
If(self.timestamp[fine_ts_width:] < counter + 2,
|
|
self.underflow.eq(1))
|
|
)
|
|
|
|
fifos = []
|
|
for n, chif in enumerate(rbus):
|
|
fifo = SyncFIFO([
|
|
("timestamp", counter_width+fine_ts_width), ("value", 2)],
|
|
2 if chif.mini else fifo_depth)
|
|
self.submodules += fifo
|
|
fifos.append(fifo)
|
|
|
|
# FIFO replace/write
|
|
self.comb += [
|
|
fifo.din.timestamp.eq(self.timestamp),
|
|
fifo.din.value.eq(self.value),
|
|
fifo.we.eq((self.we | self.replace) & (self.sel == n)),
|
|
fifo.replace.eq(self.replace)
|
|
]
|
|
|
|
# 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, fine_ts_width, fifo_depth):
|
|
counter_width = flen(counter)
|
|
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()
|
|
self.pileup = Signal()
|
|
|
|
# # #
|
|
|
|
timestamps = []
|
|
values = []
|
|
readables = []
|
|
overflows = []
|
|
pileups = []
|
|
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 = SyncFIFO([
|
|
("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)
|
|
|
|
pileup = Signal()
|
|
self.sync += If(chif.i_pileup, pileup.eq(1))
|
|
pileups.append(pileup)
|
|
else:
|
|
timestamps.append(0)
|
|
values.append(0)
|
|
readables.append(0)
|
|
overflows.append(0)
|
|
pileups.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]),
|
|
self.pileup.eq(Array(pileups)[self.sel])
|
|
]
|
|
|
|
|
|
class RTIO(Module, AutoCSR):
|
|
def __init__(self, phy, clk_freq, counter_width=32, ofifo_depth=64, ififo_depth=64):
|
|
fine_ts_width = get_fine_ts_width(phy.rbus)
|
|
|
|
# Counters
|
|
reset_counter = Signal()
|
|
o_counter = Signal(counter_width, reset=phy.loopback_latency)
|
|
i_counter = Signal(counter_width)
|
|
self.sync += \
|
|
If(reset_counter,
|
|
o_counter.eq(o_counter.reset),
|
|
i_counter.eq(i_counter.reset)
|
|
).Else(
|
|
o_counter.eq(o_counter + 1),
|
|
i_counter.eq(i_counter + 1)
|
|
)
|
|
|
|
# Submodules
|
|
self.submodules.bank_o = InsertReset(_RTIOBankO(
|
|
phy.rbus,
|
|
o_counter, fine_ts_width, ofifo_depth))
|
|
self.submodules.bank_i = InsertReset(_RTIOBankI(
|
|
phy.rbus,
|
|
i_counter, fine_ts_width, ofifo_depth))
|
|
|
|
# CSRs
|
|
self._r_reset_logic = CSRStorage(reset=1)
|
|
self._r_reset_counter = 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_replace = CSR()
|
|
self._r_o_error = 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_error = CSRStatus(2)
|
|
|
|
self._r_counter = CSRStatus(counter_width+fine_ts_width)
|
|
self._r_counter_update = CSR()
|
|
|
|
self._r_frequency_i = CSRStatus(32)
|
|
self._r_frequency_fn = CSRStatus(8)
|
|
self._r_frequency_fd = CSRStatus(8)
|
|
|
|
# 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_logic.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.bank_o.replace.eq(self._r_o_replace.re),
|
|
self._r_o_error.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_logic.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_error.status.eq(
|
|
Cat(self.bank_i.overflow, self.bank_i.pileup))
|
|
]
|
|
|
|
# Counter access
|
|
self.comb += reset_counter.eq(self._r_reset_counter.storage)
|
|
self.sync += \
|
|
If(self._r_counter_update.re,
|
|
self._r_counter.status.eq(Cat(Replicate(0, fine_ts_width),
|
|
o_counter))
|
|
)
|
|
|
|
# Frequency
|
|
clk_freq = Fraction(clk_freq).limit_denominator(255)
|
|
clk_freq_i = int(clk_freq)
|
|
clk_freq_f = clk_freq - clk_freq_i
|
|
self.comb += [
|
|
self._r_frequency_i.status.eq(clk_freq_i),
|
|
self._r_frequency_fn.status.eq(clk_freq_f.numerator),
|
|
self._r_frequency_fd.status.eq(clk_freq_f.denominator)
|
|
]
|