mirror of https://github.com/m-labs/artiq.git
rtio: refactor, use rtlink
This commit is contained in:
parent
c0f1708c20
commit
4c10182c9f
|
@ -21,17 +21,17 @@ class LLRTIOOut(AutoDB):
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def _set_oe(self):
|
def _set_oe(self):
|
||||||
syscall("rtio_oe", self.channel, True)
|
syscall("rtio_set_oe", time_to_cycles(now()), self.channel, True)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_value(self, t, value):
|
def set_o(self, t, value):
|
||||||
"""Sets the value of the RTIO channel.
|
"""Sets the output value of the RTIO channel.
|
||||||
|
|
||||||
:param t: timestamp in RTIO cycles (64-bit integer).
|
:param t: timestamp in RTIO cycles (64-bit integer).
|
||||||
:param value: value to set at the output.
|
:param value: value to set at the output.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
syscall("rtio_set", t, self.channel, value)
|
syscall("rtio_set_o", t, self.channel, value)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def on(self, t):
|
def on(self, t):
|
||||||
|
@ -40,7 +40,7 @@ class LLRTIOOut(AutoDB):
|
||||||
:param t: timestamp in RTIO cycles (64-bit integer).
|
:param t: timestamp in RTIO cycles (64-bit integer).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.set_value(t, 1)
|
self.set_o(t, 1)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def off(self, t):
|
def off(self, t):
|
||||||
|
@ -49,28 +49,10 @@ class LLRTIOOut(AutoDB):
|
||||||
:param t: timestamp in RTIO cycles (64-bit integer).
|
:param t: timestamp in RTIO cycles (64-bit integer).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.set_value(t, 0)
|
self.set_o(t, 0)
|
||||||
|
|
||||||
|
|
||||||
class _RTIOBase(AutoDB):
|
class RTIOOut(AutoDB):
|
||||||
class DBKeys:
|
|
||||||
core = Device()
|
|
||||||
channel = Argument()
|
|
||||||
|
|
||||||
def build(self):
|
|
||||||
self.previous_timestamp = int64(0) # in RTIO cycles
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def _set_oe(self, oe):
|
|
||||||
syscall("rtio_oe", self.channel, oe)
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def _set_value(self, value):
|
|
||||||
syscall("rtio_set", time_to_cycles(now()), self.channel, value)
|
|
||||||
self.previous_timestamp = time_to_cycles(now())
|
|
||||||
|
|
||||||
|
|
||||||
class RTIOOut(_RTIOBase):
|
|
||||||
"""RTIO output driver.
|
"""RTIO output driver.
|
||||||
|
|
||||||
Configures the corresponding RTIO channel as output on the core device and
|
Configures the corresponding RTIO channel as output on the core device and
|
||||||
|
@ -85,9 +67,22 @@ class RTIOOut(_RTIOBase):
|
||||||
:param channel: channel number
|
:param channel: channel number
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
class DBKeys:
|
||||||
|
core = Device()
|
||||||
|
channel = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
_RTIOBase.build(self)
|
self.previous_timestamp = int64(0) # in RTIO cycles
|
||||||
self._set_oe(True)
|
self._set_oe()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _set_oe(self):
|
||||||
|
syscall("rtio_set_oe", time_to_cycles(now()), self.channel, True)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _set_o(self, value):
|
||||||
|
syscall("rtio_set_o", time_to_cycles(now()), self.channel, value)
|
||||||
|
self.previous_timestamp = time_to_cycles(now())
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def sync(self):
|
def sync(self):
|
||||||
|
@ -96,24 +91,19 @@ class RTIOOut(_RTIOBase):
|
||||||
This function is useful to synchronize CPU-controlled devices (such as
|
This function is useful to synchronize CPU-controlled devices (such as
|
||||||
the AD9858 DDS bus) with related RTIO controls (such as RF switches at
|
the AD9858 DDS bus) with related RTIO controls (such as RF switches at
|
||||||
the output of the DDS).
|
the output of the DDS).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
while syscall("rtio_get_counter") < self.previous_timestamp:
|
while syscall("rtio_get_counter") < self.previous_timestamp:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def on(self):
|
def on(self):
|
||||||
"""Sets the output to a logic high state.
|
"""Sets the output to a logic high state."""
|
||||||
|
self._set_o(1)
|
||||||
"""
|
|
||||||
self._set_value(1)
|
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def off(self):
|
def off(self):
|
||||||
"""Sets the output to a logic low state.
|
"""Sets the output to a logic low state."""
|
||||||
|
self._set_o(0)
|
||||||
"""
|
|
||||||
self._set_value(0)
|
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse(self, duration):
|
def pulse(self, duration):
|
||||||
|
@ -125,7 +115,7 @@ class RTIOOut(_RTIOBase):
|
||||||
self.off()
|
self.off()
|
||||||
|
|
||||||
|
|
||||||
class RTIOIn(_RTIOBase):
|
class RTIOIn(AutoDB):
|
||||||
"""RTIO input driver.
|
"""RTIO input driver.
|
||||||
|
|
||||||
Configures the corresponding RTIO channel as input on the core device and
|
Configures the corresponding RTIO channel as input on the core device and
|
||||||
|
@ -134,29 +124,41 @@ class RTIOIn(_RTIOBase):
|
||||||
|
|
||||||
:param core: core device
|
:param core: core device
|
||||||
:param channel: channel number
|
:param channel: channel number
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
class DBKeys:
|
||||||
|
core = Device()
|
||||||
|
channel = Argument()
|
||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
_RTIOBase.build(self)
|
self.previous_timestamp = int64(0) # in RTIO cycles
|
||||||
self._set_oe(False)
|
self._set_oe()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _set_oe(self):
|
||||||
|
syscall("rtio_set_oe", time_to_cycles(now()), self.channel, False)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def _set_sensitivity(self, value):
|
||||||
|
syscall("rtio_set_sensitivity", time_to_cycles(now()), self.channel, value)
|
||||||
|
self.previous_timestamp = time_to_cycles(now())
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_rising(self, duration):
|
def gate_rising(self, duration):
|
||||||
"""Register rising edge events for the specified duration.
|
"""Register rising edge events for the specified duration.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._set_value(1)
|
self._set_sensitivity(1)
|
||||||
delay(duration)
|
delay(duration)
|
||||||
self._set_value(0)
|
self._set_sensitivity(0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_falling(self, duration):
|
def gate_falling(self, duration):
|
||||||
"""Register falling edge events for the specified duration.
|
"""Register falling edge events for the specified duration.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._set_value(2)
|
self._set_sensitivity(2)
|
||||||
delay(duration)
|
delay(duration)
|
||||||
self._set_value(0)
|
self._set_sensitivity(0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_both(self, duration):
|
def gate_both(self, duration):
|
||||||
|
@ -164,18 +166,9 @@ class RTIOIn(_RTIOBase):
|
||||||
duration.
|
duration.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._set_value(3)
|
self._set_sensitivity(3)
|
||||||
delay(duration)
|
delay(duration)
|
||||||
self._set_value(0)
|
self._set_sensitivity(0)
|
||||||
|
|
||||||
@kernel
|
|
||||||
def pileup_count(self):
|
|
||||||
"""Returns the number of pileup events (a system clock cycle with too
|
|
||||||
many input transitions) since the last call to this function for this
|
|
||||||
channel (or since the last RTIO reset).
|
|
||||||
|
|
||||||
"""
|
|
||||||
return syscall("rtio_pileup_count", self.channel)
|
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def count(self):
|
def count(self):
|
||||||
|
|
|
@ -12,11 +12,11 @@ llvm.initialize_all_targets()
|
||||||
llvm.initialize_all_asmprinters()
|
llvm.initialize_all_asmprinters()
|
||||||
|
|
||||||
_syscalls = {
|
_syscalls = {
|
||||||
"rtio_oe": "ib:n",
|
"rtio_set_o": "Iii:n",
|
||||||
"rtio_set": "Iii:n",
|
"rtio_set_oe": "Iib:n",
|
||||||
|
"rtio_set_sensitivity": "Iii:n",
|
||||||
"rtio_get_counter": "n:I",
|
"rtio_get_counter": "n:I",
|
||||||
"rtio_get": "iI:I",
|
"rtio_get": "iI:I",
|
||||||
"rtio_pileup_count": "i:i",
|
|
||||||
"dds_phase_clear_en": "ib:n",
|
"dds_phase_clear_en": "ib:n",
|
||||||
"dds_program": "Iiiiibb:n",
|
"dds_program": "Iiiiibb:n",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
from artiq.gateware.rtio import phy
|
from artiq.gateware.rtio.core import Channel, RTIO
|
||||||
from artiq.gateware.rtio.core import RTIO
|
|
||||||
|
|
|
@ -2,12 +2,13 @@ from fractions import Fraction
|
||||||
|
|
||||||
from migen.fhdl.std import *
|
from migen.fhdl.std import *
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
|
from migen.genlib.misc import optree
|
||||||
from migen.genlib.record import Record
|
from migen.genlib.record import Record
|
||||||
from migen.genlib.cdc import *
|
from migen.genlib.cdc import *
|
||||||
from migen.genlib.fifo import AsyncFIFO
|
from migen.genlib.fifo import AsyncFIFO
|
||||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
|
||||||
from artiq.gateware.rtio.rbus import get_fine_ts_width
|
from artiq.gateware.rtio import rtlink
|
||||||
|
|
||||||
|
|
||||||
class _GrayCodeTransfer(Module):
|
class _GrayCodeTransfer(Module):
|
||||||
|
@ -35,26 +36,20 @@ class _GrayCodeTransfer(Module):
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCounter(Module):
|
class _RTIOCounter(Module):
|
||||||
def __init__(self, width, loopback_latency):
|
def __init__(self, width):
|
||||||
self.width = width
|
self.width = width
|
||||||
# Timestamp counter in RTIO domain for outputs
|
# Timestamp counter in RTIO domain
|
||||||
self.o_value_rio = Signal(width)
|
self.value_rio = Signal(width)
|
||||||
# Timestamp counter resynchronized to sys domain
|
# Timestamp counter resynchronized to sys domain
|
||||||
# Lags behind o_value_rio, monotonic and glitch-free
|
# Lags behind value_rio, monotonic and glitch-free
|
||||||
self.o_value_sys = Signal(width)
|
self.value_sys = Signal(width)
|
||||||
# Timestamp counter in RTIO domain for inputs,
|
|
||||||
# compensated for PHY loopback latency
|
|
||||||
self.i_value_rio = Signal(width, reset=2**width-loopback_latency)
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.sync.rio += [
|
self.sync.rio += self.value_rio.eq(self.value_rio + 1),
|
||||||
self.o_value_rio.eq(self.o_value_rio + 1),
|
|
||||||
self.i_value_rio.eq(self.i_value_rio + 1)
|
|
||||||
]
|
|
||||||
gt = _GrayCodeTransfer(width)
|
gt = _GrayCodeTransfer(width)
|
||||||
self.submodules += gt
|
self.submodules += gt
|
||||||
self.comb += gt.i.eq(self.o_value_rio), self.o_value_sys.eq(gt.o)
|
self.comb += gt.i.eq(self.value_rio), self.value_sys.eq(gt.o)
|
||||||
|
|
||||||
|
|
||||||
# CHOOSING A GUARD TIME
|
# CHOOSING A GUARD TIME
|
||||||
|
@ -78,263 +73,235 @@ class _RTIOCounter(Module):
|
||||||
# timestamp*Tio > (fifo_depth-1)*Tio + time
|
# timestamp*Tio > (fifo_depth-1)*Tio + time
|
||||||
# We also have (guard time reached):
|
# We also have (guard time reached):
|
||||||
# timestamp*Tio < time + guard_io_cycles*Tio
|
# timestamp*Tio < time + guard_io_cycles*Tio
|
||||||
# [NB: time > counter.o_value_sys*Tio]
|
# [NB: time > counter.value_sys*Tio]
|
||||||
# Thus we must have:
|
# Thus we must have:
|
||||||
# guard_io_cycles > fifo_depth-1
|
# guard_io_cycles > fifo_depth-1
|
||||||
#
|
#
|
||||||
# We can prevent overflows by choosing instead:
|
# We can prevent overflows by choosing instead:
|
||||||
# guard_io_cycles < fifo_depth-1
|
# guard_io_cycles < fifo_depth-1
|
||||||
|
|
||||||
class _RTIOBankO(Module):
|
class _OutputManager(Module):
|
||||||
def __init__(self, rbus, counter, fine_ts_width, fifo_depth, guard_io_cycles):
|
def __init__(self, interface, counter, fifo_depth, guard_io_cycles):
|
||||||
self.sel = Signal(max=len(rbus))
|
data_width = rtlink.get_data_width(interface)
|
||||||
# timestamp and value must be valid 1 cycle before we
|
address_width = rtlink.get_address_width(interface)
|
||||||
self.timestamp = Signal(counter.width + fine_ts_width)
|
fine_ts_width = rtlink.get_fine_ts_width(interface)
|
||||||
self.value = Signal(2)
|
|
||||||
|
ev_layout = []
|
||||||
|
if data_width:
|
||||||
|
ev_layout.append(("data", data_width))
|
||||||
|
if address_width:
|
||||||
|
ev_layout.append(("address", address_width))
|
||||||
|
ev_layout.append(("timestamp", counter.width + fine_ts_width))
|
||||||
|
# ev must be valid 1 cycle before we to account for the latency in
|
||||||
|
# generating replace, sequence_error and nop
|
||||||
|
self.ev = Record(ev_layout)
|
||||||
|
|
||||||
self.writable = Signal()
|
self.writable = Signal()
|
||||||
self.we = Signal() # maximum throughput 1/2
|
self.we = Signal() # maximum throughput 1/2
|
||||||
self.underflow = Signal() # valid 2 cycles after we
|
|
||||||
self.underflow_reset = Signal()
|
self.underflow = Signal() # valid 1 cycle after we, pulsed
|
||||||
self.sequence_error = Signal()
|
self.sequence_error = Signal()
|
||||||
self.sequence_error_reset = Signal()
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
signal_underflow = Signal()
|
# FIFO
|
||||||
signal_sequence_error = Signal()
|
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
|
||||||
fifos = []
|
{"write": "rsys", "read": "rio"})
|
||||||
ev_layout = [("timestamp", counter.width + fine_ts_width),
|
self.submodules += fifo
|
||||||
("value", 2)]
|
|
||||||
for n, chif in enumerate(rbus):
|
|
||||||
# FIFO
|
|
||||||
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
|
|
||||||
{"write": "rsys", "read": "rio"})
|
|
||||||
self.submodules += fifo
|
|
||||||
fifos.append(fifo)
|
|
||||||
|
|
||||||
# Buffer
|
# Buffer
|
||||||
buf_pending = Signal()
|
buf_pending = Signal()
|
||||||
buf = Record(ev_layout)
|
buf = Record(ev_layout)
|
||||||
buf_just_written = Signal()
|
buf_just_written = Signal()
|
||||||
|
|
||||||
# Special cases
|
# Special cases
|
||||||
replace = Signal()
|
replace = Signal()
|
||||||
sequence_error = Signal()
|
sequence_error = Signal()
|
||||||
nop = Signal()
|
nop = Signal()
|
||||||
self.sync.rsys += [
|
|
||||||
replace.eq(self.timestamp == buf.timestamp[fine_ts_width:]),
|
|
||||||
sequence_error.eq(self.timestamp < buf.timestamp[fine_ts_width:]),
|
|
||||||
nop.eq(self.value == buf.value)
|
|
||||||
]
|
|
||||||
self.comb += If(self.we & (self.sel == n) & sequence_error,
|
|
||||||
signal_sequence_error.eq(1))
|
|
||||||
|
|
||||||
# Buffer read and FIFO write
|
|
||||||
self.comb += fifo.din.eq(buf)
|
|
||||||
in_guard_time = Signal()
|
|
||||||
self.comb += in_guard_time.eq(
|
|
||||||
buf.timestamp[fine_ts_width:] < counter.o_value_sys + guard_io_cycles)
|
|
||||||
self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
|
|
||||||
self.comb += \
|
|
||||||
If(buf_pending,
|
|
||||||
If(in_guard_time,
|
|
||||||
If(buf_just_written,
|
|
||||||
signal_underflow.eq(1)
|
|
||||||
).Else(
|
|
||||||
fifo.we.eq(1)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
If((self.we & (self.sel == n)
|
|
||||||
& ~replace & ~nop & ~sequence_error),
|
|
||||||
fifo.we.eq(1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Buffer write
|
|
||||||
# Must come after read to handle concurrent read+write properly
|
|
||||||
self.sync.rsys += [
|
|
||||||
buf_just_written.eq(0),
|
|
||||||
If(self.we & (self.sel == n) & ~nop & ~sequence_error,
|
|
||||||
buf_just_written.eq(1),
|
|
||||||
buf_pending.eq(1),
|
|
||||||
buf.timestamp.eq(self.timestamp),
|
|
||||||
buf.value.eq(self.value)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Buffer output of FIFO to improve timing
|
|
||||||
dout_stb = Signal()
|
|
||||||
dout_ack = Signal()
|
|
||||||
dout = Record(ev_layout)
|
|
||||||
self.sync.rio += \
|
|
||||||
If(fifo.re,
|
|
||||||
dout_stb.eq(1),
|
|
||||||
dout.eq(fifo.dout)
|
|
||||||
).Elif(dout_ack,
|
|
||||||
dout_stb.eq(0)
|
|
||||||
)
|
|
||||||
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
|
|
||||||
|
|
||||||
# FIFO read through buffer
|
|
||||||
self.comb += [
|
|
||||||
dout_ack.eq(
|
|
||||||
dout.timestamp[fine_ts_width:] == counter.o_value_rio),
|
|
||||||
chif.o_stb.eq(dout_stb & dout_ack),
|
|
||||||
chif.o_value.eq(dout.value)
|
|
||||||
]
|
|
||||||
if fine_ts_width:
|
|
||||||
self.comb += chif.o_fine_ts.eq(
|
|
||||||
dout.timestamp[:fine_ts_width])
|
|
||||||
|
|
||||||
self.comb += \
|
|
||||||
self.writable.eq(Array(fifo.writable for fifo in fifos)[self.sel])
|
|
||||||
self.sync.rsys += [
|
self.sync.rsys += [
|
||||||
If(self.underflow_reset, self.underflow.eq(0)),
|
replace.eq(self.ev.timestamp == buf.timestamp[fine_ts_width:]),
|
||||||
If(self.sequence_error_reset, self.sequence_error.eq(0)),
|
sequence_error.eq(self.ev.timestamp < buf.timestamp[fine_ts_width:])
|
||||||
If(signal_underflow, self.underflow.eq(1)),
|
|
||||||
If(signal_sequence_error, self.sequence_error.eq(1))
|
|
||||||
]
|
]
|
||||||
|
if interface.suppress_nop:
|
||||||
|
self.sync.rsys += nop.eq(
|
||||||
|
optree("&",
|
||||||
|
[getattr(self.ev, a) == getattr(buf, a)
|
||||||
|
for a in ("data", "address")
|
||||||
|
if hasattr(self.ev, a)],
|
||||||
|
default=0))
|
||||||
|
self.comb += self.sequence_error.eq(self.we & sequence_error)
|
||||||
|
|
||||||
|
# Buffer read and FIFO write
|
||||||
|
self.comb += fifo.din.eq(buf)
|
||||||
|
in_guard_time = Signal()
|
||||||
|
self.comb += in_guard_time.eq(
|
||||||
|
buf.timestamp[fine_ts_width:]
|
||||||
|
< counter.value_sys + guard_io_cycles)
|
||||||
|
self.sync.rsys += If(in_guard_time, buf_pending.eq(0))
|
||||||
|
self.comb += \
|
||||||
|
If(buf_pending,
|
||||||
|
If(in_guard_time,
|
||||||
|
If(buf_just_written,
|
||||||
|
self.underflow.eq(1)
|
||||||
|
).Else(
|
||||||
|
fifo.we.eq(1)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
If(self.we & ~replace & ~nop & ~sequence_error,
|
||||||
|
fifo.we.eq(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Buffer write
|
||||||
|
# Must come after read to handle concurrent read+write properly
|
||||||
|
self.sync.rsys += [
|
||||||
|
buf_just_written.eq(0),
|
||||||
|
If(self.we & ~nop & ~sequence_error,
|
||||||
|
buf_just_written.eq(1),
|
||||||
|
buf_pending.eq(1),
|
||||||
|
buf.eq(self.ev)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
self.comb += self.writable.eq(fifo.writable)
|
||||||
|
|
||||||
|
# Buffer output of FIFO to improve timing
|
||||||
|
dout_stb = Signal()
|
||||||
|
dout_ack = Signal()
|
||||||
|
dout = Record(ev_layout)
|
||||||
|
self.sync.rio += \
|
||||||
|
If(fifo.re,
|
||||||
|
dout_stb.eq(1),
|
||||||
|
dout.eq(fifo.dout)
|
||||||
|
).Elif(dout_ack,
|
||||||
|
dout_stb.eq(0)
|
||||||
|
)
|
||||||
|
self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack))
|
||||||
|
|
||||||
|
# FIFO read through buffer
|
||||||
|
# TODO: report error on stb & busy
|
||||||
|
self.comb += [
|
||||||
|
dout_ack.eq(
|
||||||
|
dout.timestamp[fine_ts_width:] == counter.value_rio),
|
||||||
|
interface.stb.eq(dout_stb & dout_ack)
|
||||||
|
]
|
||||||
|
if data_width:
|
||||||
|
self.comb += interface.data.eq(dout.data)
|
||||||
|
if address_width:
|
||||||
|
self.comb += interface.address.eq(dout.address)
|
||||||
|
if fine_ts_width:
|
||||||
|
self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width])
|
||||||
|
|
||||||
|
|
||||||
class _RTIOBankI(Module):
|
class _InputManager(Module):
|
||||||
def __init__(self, rbus, counter, fine_ts_width, fifo_depth):
|
def __init__(self, interface, counter, fifo_depth):
|
||||||
self.sel = Signal(max=len(rbus))
|
data_width = rtlink.get_data_width(interface)
|
||||||
self.timestamp = Signal(counter.width + fine_ts_width)
|
fine_ts_width = rtlink.get_fine_ts_width(interface)
|
||||||
self.value = Signal()
|
|
||||||
|
ev_layout = []
|
||||||
|
if data_width:
|
||||||
|
ev_layout.append(("data", data_width))
|
||||||
|
if interface.timestamped:
|
||||||
|
ev_layout.append(("timestamp", counter.width + fine_ts_width))
|
||||||
|
self.ev = Record(ev_layout)
|
||||||
|
|
||||||
self.readable = Signal()
|
self.readable = Signal()
|
||||||
self.re = Signal()
|
self.re = Signal()
|
||||||
self.overflow = Signal()
|
|
||||||
self.overflow_reset = Signal()
|
self.overflow = Signal() # pulsed
|
||||||
self.pileup_count = Signal(16)
|
|
||||||
self.pileup_reset = Signal()
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
timestamps = []
|
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
|
||||||
values = []
|
{"read": "rsys", "write": "rio"})
|
||||||
readables = []
|
self.submodules += fifo
|
||||||
overflows = []
|
|
||||||
pileup_counts = []
|
|
||||||
ev_layout = [("timestamp", counter.width+fine_ts_width),
|
|
||||||
("value", 1)]
|
|
||||||
for n, chif in enumerate(rbus):
|
|
||||||
if hasattr(chif, "oe"):
|
|
||||||
sensitivity = Signal(2)
|
|
||||||
self.sync.rio += If(~chif.oe & chif.o_stb,
|
|
||||||
sensitivity.eq(chif.o_value))
|
|
||||||
|
|
||||||
fifo = RenameClockDomains(AsyncFIFO(ev_layout, fifo_depth),
|
# FIFO write
|
||||||
{"read": "rsys", "write": "rio"})
|
if data_width:
|
||||||
self.submodules += fifo
|
self.comb += fifo.din.data.eq(interface.data)
|
||||||
|
if interface.timestamped:
|
||||||
# FIFO write
|
if fine_ts_width:
|
||||||
if fine_ts_width:
|
full_ts = Cat(interface.fine_ts, counter.value_rio)
|
||||||
full_ts = Cat(chif.i_fine_ts, counter.i_value_rio)
|
|
||||||
else:
|
|
||||||
full_ts = counter.i_value_rio
|
|
||||||
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()
|
|
||||||
overflow_reset_sync = PulseSynchronizer("rsys", "rio")
|
|
||||||
self.submodules += overflow_reset_sync
|
|
||||||
self.comb += overflow_reset_sync.i.eq(
|
|
||||||
self.overflow_reset & (self.sel == n))
|
|
||||||
self.sync.rio += [
|
|
||||||
If(overflow_reset_sync.o, overflow.eq(0)),
|
|
||||||
If(fifo.we & ~fifo.writable, overflow.eq(1))
|
|
||||||
]
|
|
||||||
overflow_sys = Signal()
|
|
||||||
self.specials += MultiReg(overflow, overflow_sys, "rsys")
|
|
||||||
overflows.append(overflow_sys)
|
|
||||||
|
|
||||||
pileup_count = Signal(16)
|
|
||||||
pileup_count_reset_sync = PulseSynchronizer("rsys", "rio")
|
|
||||||
self.submodules += pileup_count_reset_sync
|
|
||||||
self.comb += pileup_count_reset_sync.i.eq(
|
|
||||||
self.pileup_reset & (self.sel == n))
|
|
||||||
self.sync.rio += \
|
|
||||||
If(pileup_count_reset_sync.o,
|
|
||||||
pileup_count.eq(0)
|
|
||||||
).Elif(chif.i_pileup,
|
|
||||||
If(pileup_count != 2**16 - 1, # saturate
|
|
||||||
pileup_count.eq(pileup_count + 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
pileup_count_sync = _GrayCodeTransfer(16)
|
|
||||||
self.submodules += pileup_count_sync
|
|
||||||
self.comb += pileup_count_sync.i.eq(pileup_count)
|
|
||||||
pileup_counts.append(pileup_count_sync.o)
|
|
||||||
else:
|
else:
|
||||||
timestamps.append(0)
|
full_ts = counter.value_rio
|
||||||
values.append(0)
|
self.comb += fifo.din.timestamp.eq(full_ts)
|
||||||
readables.append(0)
|
self.comb += fifo.we.eq(interface.stb)
|
||||||
overflows.append(0)
|
|
||||||
pileup_counts.append(0)
|
|
||||||
|
|
||||||
|
# FIFO read
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.timestamp.eq(Array(timestamps)[self.sel]),
|
self.ev.eq(fifo.dout),
|
||||||
self.value.eq(Array(values)[self.sel]),
|
self.readable.eq(fifo.readable),
|
||||||
self.readable.eq(Array(readables)[self.sel]),
|
fifo.re.eq(self.re)
|
||||||
self.overflow.eq(Array(overflows)[self.sel]),
|
]
|
||||||
self.pileup_count.eq(Array(pileup_counts)[self.sel])
|
|
||||||
|
overflow_sync = PulseSynchronizer("rio", "rsys")
|
||||||
|
overflow_ack_sync = PulseSynchronizer("rsys", "rio")
|
||||||
|
self.submodules += overflow_sync, overflow_ack_sync
|
||||||
|
overflow_blind = Signal()
|
||||||
|
self.comb += overflow_sync.i.eq(fifo.we & ~fifo.writable & ~overflow_blind)
|
||||||
|
self.sync.rio += [
|
||||||
|
If(fifo.we & ~fifo.writable, overflow_blind.eq(1)),
|
||||||
|
If(overflow_ack_sync.o, overflow_blind.eq(0))
|
||||||
|
]
|
||||||
|
self.comb += [
|
||||||
|
overflow_ack_sync.i.eq(overflow_sync.o),
|
||||||
|
self.overflow.eq(overflow_sync.o)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class RTIO(Module, AutoCSR):
|
class Channel:
|
||||||
def __init__(self, phy, clk_freq, counter_width=63,
|
def __init__(self, interface, ofifo_depth=64, ififo_depth=64):
|
||||||
ofifo_depth=64, ififo_depth=64,
|
self.interface = interface
|
||||||
guard_io_cycles=20):
|
self.ofifo_depth = ofifo_depth
|
||||||
fine_ts_width = get_fine_ts_width(phy.rbus)
|
self.ififo_depth = ififo_depth
|
||||||
|
|
||||||
# Submodules
|
|
||||||
self.submodules.counter = _RTIOCounter(
|
class _CSRs(AutoCSR):
|
||||||
counter_width, phy.loopback_latency)
|
def __init__(self):
|
||||||
self.submodules.bank_o = _RTIOBankO(
|
self.frequency_i = CSRStatus(32)
|
||||||
phy.rbus, self.counter, fine_ts_width, ofifo_depth, guard_io_cycles)
|
self.frequency_fn = CSRStatus(8)
|
||||||
self.submodules.bank_i = _RTIOBankI(
|
self.frequency_fd = CSRStatus(8)
|
||||||
phy.rbus, self.counter, fine_ts_width, ififo_depth)
|
|
||||||
|
|
||||||
|
class _KernelCSRs(AutoCSR):
|
||||||
|
def __init__(self, chan_sel_width,
|
||||||
|
data_width, address_width, full_ts_width):
|
||||||
|
self.reset = CSRStorage(reset=1)
|
||||||
|
self.chan_sel = CSRStorage(chan_sel_width)
|
||||||
|
|
||||||
|
self.o_data = CSRStorage(data_width)
|
||||||
|
self.o_address = CSRStorage(address_width)
|
||||||
|
self.o_timestamp = CSRStorage(full_ts_width)
|
||||||
|
self.o_we = CSR()
|
||||||
|
self.o_status = CSRStatus(3)
|
||||||
|
self.o_underflow_reset = CSR()
|
||||||
|
self.o_sequence_error_reset = CSR()
|
||||||
|
|
||||||
|
self.i_data = CSRStatus(data_width)
|
||||||
|
self.i_timestamp = CSRStatus(full_ts_width)
|
||||||
|
self.i_re = CSR()
|
||||||
|
self.i_status = CSRStatus(2)
|
||||||
|
self.i_overflow_reset = CSR()
|
||||||
|
|
||||||
|
self.counter = CSRStatus(full_ts_width)
|
||||||
|
self.counter_update = CSR()
|
||||||
|
|
||||||
|
|
||||||
|
class RTIO(Module):
|
||||||
|
def __init__(self, channels, clk_freq, counter_width=63,
|
||||||
|
guard_io_cycles=20):
|
||||||
|
data_width = max(rtlink.get_data_width(c.interface)
|
||||||
|
for c in channels)
|
||||||
|
address_width = max(rtlink.get_address_width(c.interface)
|
||||||
|
for c in channels)
|
||||||
|
fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
|
||||||
|
for c in channels)
|
||||||
|
|
||||||
# CSRs
|
# CSRs
|
||||||
self._reset = CSRStorage(reset=1)
|
self.csrs = _CSRs()
|
||||||
self._chan_sel = CSRStorage(flen(self.bank_o.sel))
|
self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
|
||||||
|
max(data_width, 1),
|
||||||
self._oe = CSR()
|
max(address_width, 1),
|
||||||
|
counter_width + fine_ts_width)
|
||||||
self._o_timestamp = CSRStorage(counter_width + fine_ts_width)
|
|
||||||
self._o_value = CSRStorage(2)
|
|
||||||
self._o_we = CSR()
|
|
||||||
self._o_status = CSRStatus(3)
|
|
||||||
self._o_underflow_reset = CSR()
|
|
||||||
self._o_sequence_error_reset = CSR()
|
|
||||||
|
|
||||||
self._i_timestamp = CSRStatus(counter_width + fine_ts_width)
|
|
||||||
self._i_value = CSRStatus()
|
|
||||||
self._i_re = CSR()
|
|
||||||
self._i_status = CSRStatus(2)
|
|
||||||
self._i_overflow_reset = CSR()
|
|
||||||
self._i_pileup_count = CSRStatus(16)
|
|
||||||
self._i_pileup_reset = CSR()
|
|
||||||
|
|
||||||
self._counter = CSRStatus(counter_width + fine_ts_width)
|
|
||||||
self._counter_update = CSR()
|
|
||||||
|
|
||||||
self._frequency_i = CSRStatus(32)
|
|
||||||
self._frequency_fn = CSRStatus(8)
|
|
||||||
self._frequency_fd = CSRStatus(8)
|
|
||||||
|
|
||||||
|
|
||||||
# Clocking/Reset
|
# Clocking/Reset
|
||||||
# Create rsys and rio domains based on sys and rio
|
# Create rsys and rio domains based on sys and rio
|
||||||
|
@ -343,63 +310,113 @@ class RTIO(Module, AutoCSR):
|
||||||
self.clock_domains.cd_rio = ClockDomain()
|
self.clock_domains.cd_rio = ClockDomain()
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.cd_rsys.clk.eq(ClockSignal()),
|
self.cd_rsys.clk.eq(ClockSignal()),
|
||||||
self.cd_rsys.rst.eq(self._reset.storage)
|
self.cd_rsys.rst.eq(self.kcsrs.reset.storage)
|
||||||
]
|
]
|
||||||
self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
|
self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
|
||||||
self.specials += AsyncResetSynchronizer(
|
self.specials += AsyncResetSynchronizer(self.cd_rio,
|
||||||
self.cd_rio, self._reset.storage)
|
self.kcsrs.reset.storage)
|
||||||
|
|
||||||
|
# Latency compensation
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
# Managers
|
||||||
|
self.submodules.counter = _RTIOCounter(counter_width)
|
||||||
|
|
||||||
|
i_datas, i_timestamps = [], []
|
||||||
|
o_statuses, i_statuses = [], []
|
||||||
|
sel = self.kcsrs.chan_sel.storage
|
||||||
|
for n, channel in enumerate(channels):
|
||||||
|
selected = Signal()
|
||||||
|
self.comb += selected.eq(sel == n)
|
||||||
|
|
||||||
|
o_manager = _OutputManager(channel.interface.o, self.counter,
|
||||||
|
channel.ofifo_depth, guard_io_cycles)
|
||||||
|
self.submodules += o_manager
|
||||||
|
|
||||||
|
if hasattr(o_manager.ev, "data"):
|
||||||
|
self.comb += o_manager.ev.data.eq(
|
||||||
|
self.kcsrs.o_data.storage)
|
||||||
|
if hasattr(o_manager.ev, "address"):
|
||||||
|
self.comb += o_manager.ev.address.eq(
|
||||||
|
self.kcsrs.o_address.storage)
|
||||||
|
ts_shift = (flen(self.kcsrs.o_timestamp.storage)
|
||||||
|
- flen(o_manager.ev.timestamp))
|
||||||
|
self.comb += o_manager.ev.timestamp.eq(
|
||||||
|
self.kcsrs.o_timestamp.storage[ts_shift:])
|
||||||
|
|
||||||
|
self.comb += o_manager.we.eq(selected & self.kcsrs.o_we.re)
|
||||||
|
|
||||||
|
underflow = Signal()
|
||||||
|
sequence_error = Signal()
|
||||||
|
self.sync.rsys += [
|
||||||
|
If(selected & self.kcsrs.o_underflow_reset.re,
|
||||||
|
underflow.eq(0)),
|
||||||
|
If(selected & self.kcsrs.o_sequence_error_reset.re,
|
||||||
|
sequence_error.eq(0)),
|
||||||
|
If(o_manager.underflow, underflow.eq(1)),
|
||||||
|
If(o_manager.sequence_error, sequence_error.eq(1))
|
||||||
|
]
|
||||||
|
o_statuses.append(Cat(~o_manager.writable,
|
||||||
|
underflow,
|
||||||
|
sequence_error))
|
||||||
|
|
||||||
|
if channel.interface.i is not None:
|
||||||
|
i_manager = _InputManager(channel.interface.i, self.counter,
|
||||||
|
channel.ififo_depth)
|
||||||
|
self.submodules += i_manager
|
||||||
|
|
||||||
|
if hasattr(i_manager.ev, "data"):
|
||||||
|
i_datas.append(i_manager.ev.data)
|
||||||
|
else:
|
||||||
|
i_datas.append(0)
|
||||||
|
if channel.interface.i.timestamped:
|
||||||
|
ts_shift = (flen(self.kcsrs.i_timestamp.status)
|
||||||
|
- flen(i_manager.ev.timestamp))
|
||||||
|
i_timestamps.append(i_manager.ev.timestamp << ts_shift)
|
||||||
|
else:
|
||||||
|
i_timestamps.append(0)
|
||||||
|
|
||||||
|
self.comb += i_manager.re.eq(selected & self.kcsrs.i_re.re)
|
||||||
|
|
||||||
|
overflow = Signal()
|
||||||
|
self.sync.rsys += [
|
||||||
|
If(selected & self.kcsrs.i_overflow_reset.re,
|
||||||
|
overflow.eq(0)),
|
||||||
|
If(i_manager.overflow,
|
||||||
|
overflow.eq(1))
|
||||||
|
]
|
||||||
|
i_statuses.append(Cat(~i_manager.readable, overflow))
|
||||||
|
|
||||||
# OE
|
|
||||||
oes = []
|
|
||||||
for n, chif in enumerate(phy.rbus):
|
|
||||||
if hasattr(chif, "oe"):
|
|
||||||
self.sync += \
|
|
||||||
If(self._oe.re & (self._chan_sel.storage == n),
|
|
||||||
chif.oe.eq(self._oe.r)
|
|
||||||
)
|
|
||||||
oes.append(chif.oe)
|
|
||||||
else:
|
else:
|
||||||
oes.append(1)
|
i_datas.append(0)
|
||||||
self.comb += self._oe.w.eq(Array(oes)[self._chan_sel.storage])
|
i_timestamps.append(0)
|
||||||
|
i_statuses.append(0)
|
||||||
# Output/Gate
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.bank_o.sel.eq(self._chan_sel.storage),
|
self.kcsrs.i_data.status.eq(Array(i_datas)[sel]),
|
||||||
self.bank_o.timestamp.eq(self._o_timestamp.storage),
|
self.kcsrs.i_timestamp.status.eq(Array(i_timestamps)[sel]),
|
||||||
self.bank_o.value.eq(self._o_value.storage),
|
self.kcsrs.o_status.status.eq(Array(o_statuses)[sel]),
|
||||||
self.bank_o.we.eq(self._o_we.re),
|
self.kcsrs.i_status.status.eq(Array(i_statuses)[sel])
|
||||||
self._o_status.status.eq(Cat(~self.bank_o.writable,
|
|
||||||
self.bank_o.underflow,
|
|
||||||
self.bank_o.sequence_error)),
|
|
||||||
self.bank_o.underflow_reset.eq(self._o_underflow_reset.re),
|
|
||||||
self.bank_o.sequence_error_reset.eq(self._o_sequence_error_reset.re)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Input
|
|
||||||
self.comb += [
|
|
||||||
self.bank_i.sel.eq(self._chan_sel.storage),
|
|
||||||
self._i_timestamp.status.eq(self.bank_i.timestamp),
|
|
||||||
self._i_value.status.eq(self.bank_i.value),
|
|
||||||
self.bank_i.re.eq(self._i_re.re),
|
|
||||||
self._i_status.status.eq(Cat(~self.bank_i.readable, self.bank_i.overflow)),
|
|
||||||
self.bank_i.overflow_reset.eq(self._i_overflow_reset.re),
|
|
||||||
self._i_pileup_count.status.eq(self.bank_i.pileup_count),
|
|
||||||
self.bank_i.pileup_reset.eq(self._i_pileup_reset.re)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Counter access
|
# Counter access
|
||||||
self.sync += \
|
self.sync += \
|
||||||
If(self._counter_update.re,
|
If(self.kcsrs.counter_update.re,
|
||||||
self._counter.status.eq(Cat(Replicate(0, fine_ts_width),
|
self.kcsrs.counter.status.eq(self.counter.value_sys
|
||||||
self.counter.o_value_sys))
|
<< fine_ts_width)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Frequency
|
# Frequency CSRs
|
||||||
clk_freq = Fraction(clk_freq).limit_denominator(255)
|
clk_freq = Fraction(clk_freq).limit_denominator(255)
|
||||||
clk_freq_i = int(clk_freq)
|
clk_freq_i = int(clk_freq)
|
||||||
clk_freq_f = clk_freq - clk_freq_i
|
clk_freq_f = clk_freq - clk_freq_i
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self._frequency_i.status.eq(clk_freq_i),
|
self.csrs.frequency_i.status.eq(clk_freq_i),
|
||||||
self._frequency_fn.status.eq(clk_freq_f.numerator),
|
self.csrs.frequency_fn.status.eq(clk_freq_f.numerator),
|
||||||
self._frequency_fd.status.eq(clk_freq_f.denominator)
|
self.csrs.frequency_fd.status.eq(clk_freq_f.denominator)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_csrs(self):
|
||||||
|
return self.csrs.get_csrs()
|
||||||
|
|
||||||
|
def get_kernel_csrs(self):
|
||||||
|
return self.kcsrs.get_csrs()
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
from migen.fhdl.std import *
|
|
||||||
from migen.genlib.cdc import MultiReg
|
|
||||||
|
|
||||||
from artiq.gateware.rtio.rbus import create_rbus
|
|
||||||
|
|
||||||
|
|
||||||
class SimplePHY(Module):
|
|
||||||
def __init__(self, pads, output_only_pads=set()):
|
|
||||||
self.rbus = create_rbus(0, pads, output_only_pads)
|
|
||||||
self.loopback_latency = 3
|
|
||||||
|
|
||||||
# # #
|
|
||||||
|
|
||||||
for pad, chif in zip(pads, self.rbus):
|
|
||||||
o_pad = Signal()
|
|
||||||
self.sync.rio += If(chif.o_stb, o_pad.eq(chif.o_value))
|
|
||||||
if hasattr(chif, "oe"):
|
|
||||||
ts = TSTriple()
|
|
||||||
i_pad = Signal()
|
|
||||||
self.sync.rio += ts.oe.eq(chif.oe)
|
|
||||||
self.comb += ts.o.eq(o_pad)
|
|
||||||
self.specials += MultiReg(ts.i, i_pad, "rio"), \
|
|
||||||
ts.get_tristate(pad)
|
|
||||||
|
|
||||||
i_pad_d = Signal()
|
|
||||||
self.sync.rio += i_pad_d.eq(i_pad)
|
|
||||||
self.comb += chif.i_stb.eq(i_pad ^ i_pad_d), \
|
|
||||||
chif.i_value.eq(i_pad)
|
|
||||||
else:
|
|
||||||
self.comb += pad.eq(o_pad)
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.genlib.cdc import MultiReg
|
||||||
|
|
||||||
|
from artiq.gateware.rtio import rtlink
|
||||||
|
|
||||||
|
|
||||||
|
class Output(Module):
|
||||||
|
def __init__(self, pad):
|
||||||
|
self.rtlink = rtlink.Interface(rtlink.OInterface(1))
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
self.sync.rio += If(self.rtlink.o.stb, pad.eq(self.rtlink.o.data))
|
||||||
|
|
||||||
|
|
||||||
|
class Inout(Module):
|
||||||
|
def __init__(self, pad):
|
||||||
|
self.rtlink = rtlink.Interface(
|
||||||
|
rtlink.OInterface(2, 2),
|
||||||
|
rtlink.IInterface(1))
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
ts = TSTriple()
|
||||||
|
self.specials += ts.get_tristate(pad)
|
||||||
|
sensitivity = Signal(2)
|
||||||
|
|
||||||
|
self.sync.rio += If(self.rtlink.o.stb,
|
||||||
|
Case(self.rtlink.o.address, {
|
||||||
|
0: ts.o.eq(self.rtlink.o.data[0]),
|
||||||
|
1: ts.oe.eq(self.rtlink.o.data[0]),
|
||||||
|
2: sensitivity.eq(self.rtlink.o.data)
|
||||||
|
}).makedefault()
|
||||||
|
)
|
||||||
|
|
||||||
|
i = Signal()
|
||||||
|
i_d = Signal()
|
||||||
|
self.specials += MultiReg(ts.i, i, "rio")
|
||||||
|
self.sync.rio += i_d.eq(i)
|
||||||
|
self.comb += [
|
||||||
|
self.rtlink.i.stb.eq(
|
||||||
|
(sensitivity[0] & ( i & ~i_d)) |
|
||||||
|
(sensitivity[1] & (~i & i_d))
|
||||||
|
),
|
||||||
|
self.rtlink.i.data.eq(i)
|
||||||
|
]
|
|
@ -1,31 +0,0 @@
|
||||||
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),
|
|
||||||
("i_pileup", 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
|
|
|
@ -54,7 +54,7 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
|
||||||
ksupport_data.o: ksupport.bin
|
ksupport_data.o: ksupport.bin
|
||||||
$(LD) -r -b binary -o $@ $<
|
$(LD) -r -b binary -o $@ $<
|
||||||
|
|
||||||
service_table.h: $(SERVICE_TABLE_INPUT)
|
service_table.h: $(SERVICE_TABLE_INPUT) gen_service_table.py
|
||||||
@echo " GEN " $@ && ./gen_service_table.py $(SERVICE_TABLE_INPUT) > $@
|
@echo " GEN " $@ && ./gen_service_table.py $(SERVICE_TABLE_INPUT) > $@
|
||||||
|
|
||||||
services.c: service_table.h
|
services.c: service_table.h
|
||||||
|
|
|
@ -6,11 +6,11 @@ import sys
|
||||||
services = [
|
services = [
|
||||||
("syscalls", [
|
("syscalls", [
|
||||||
("rpc", "comm_rpc"),
|
("rpc", "comm_rpc"),
|
||||||
("rtio_oe", "rtio_oe"),
|
("rtio_set_o", "rtio_set_o"),
|
||||||
("rtio_set", "rtio_set"),
|
("rtio_set_oe", "rtio_set_oe"),
|
||||||
|
("rtio_set_sensitivity", "rtio_set_sensitivity"),
|
||||||
("rtio_get_counter", "rtio_get_counter"),
|
("rtio_get_counter", "rtio_get_counter"),
|
||||||
("rtio_get", "rtio_get"),
|
("rtio_get", "rtio_get"),
|
||||||
("rtio_pileup_count", "rtio_pileup_count"),
|
|
||||||
("dds_phase_clear_en", "dds_phase_clear_en"),
|
("dds_phase_clear_en", "dds_phase_clear_en"),
|
||||||
("dds_program", "dds_program"),
|
("dds_program", "dds_program"),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -18,19 +18,10 @@ void rtio_init(void)
|
||||||
rtio_reset_write(0);
|
rtio_reset_write(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rtio_oe(int channel, int oe)
|
static void write_and_process_status(long long int timestamp, int channel)
|
||||||
{
|
|
||||||
rtio_chan_sel_write(channel);
|
|
||||||
rtio_oe_write(oe);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtio_set(long long int timestamp, int channel, int value)
|
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
rtio_chan_sel_write(channel);
|
|
||||||
rtio_o_timestamp_write(timestamp);
|
|
||||||
rtio_o_value_write(value);
|
|
||||||
rtio_o_we_write(1);
|
rtio_o_we_write(1);
|
||||||
status = rtio_o_status_read();
|
status = rtio_o_status_read();
|
||||||
if(status) {
|
if(status) {
|
||||||
|
@ -49,6 +40,33 @@ void rtio_set(long long int timestamp, int channel, int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rtio_set_o(long long int timestamp, int channel, int value)
|
||||||
|
{
|
||||||
|
rtio_chan_sel_write(channel);
|
||||||
|
rtio_o_timestamp_write(timestamp);
|
||||||
|
rtio_o_address_write(0);
|
||||||
|
rtio_o_data_write(value);
|
||||||
|
write_and_process_status(timestamp, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtio_set_oe(long long int timestamp, int channel, int oe)
|
||||||
|
{
|
||||||
|
rtio_chan_sel_write(channel);
|
||||||
|
rtio_o_timestamp_write(timestamp);
|
||||||
|
rtio_o_address_write(1);
|
||||||
|
rtio_o_data_write(oe);
|
||||||
|
write_and_process_status(timestamp, channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity)
|
||||||
|
{
|
||||||
|
rtio_chan_sel_write(channel);
|
||||||
|
rtio_o_timestamp_write(timestamp);
|
||||||
|
rtio_o_address_write(2);
|
||||||
|
rtio_o_data_write(sensitivity);
|
||||||
|
write_and_process_status(timestamp, channel);
|
||||||
|
}
|
||||||
|
|
||||||
long long int rtio_get_counter(void)
|
long long int rtio_get_counter(void)
|
||||||
{
|
{
|
||||||
rtio_counter_update_write(1);
|
rtio_counter_update_write(1);
|
||||||
|
@ -81,16 +99,6 @@ long long int rtio_get(int channel, long long int time_limit)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtio_pileup_count(int channel)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
rtio_chan_sel_write(channel);
|
|
||||||
r = rtio_i_pileup_count_read();
|
|
||||||
rtio_i_pileup_reset_write(1);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rtio_fud_sync(void)
|
void rtio_fud_sync(void)
|
||||||
{
|
{
|
||||||
while(rtio_get_counter() < previous_fud_end_time);
|
while(rtio_get_counter() < previous_fud_end_time);
|
||||||
|
@ -102,14 +110,15 @@ void rtio_fud(long long int fud_time)
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
|
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
|
||||||
|
rtio_o_address_write(0);
|
||||||
fud_end_time = fud_time + 3*8;
|
fud_end_time = fud_time + 3*8;
|
||||||
previous_fud_end_time = fud_end_time;
|
previous_fud_end_time = fud_end_time;
|
||||||
|
|
||||||
rtio_o_timestamp_write(fud_time);
|
rtio_o_timestamp_write(fud_time);
|
||||||
rtio_o_value_write(1);
|
rtio_o_data_write(1);
|
||||||
rtio_o_we_write(1);
|
rtio_o_we_write(1);
|
||||||
rtio_o_timestamp_write(fud_end_time);
|
rtio_o_timestamp_write(fud_end_time);
|
||||||
rtio_o_value_write(0);
|
rtio_o_data_write(0);
|
||||||
rtio_o_we_write(1);
|
rtio_o_we_write(1);
|
||||||
status = rtio_o_status_read();
|
status = rtio_o_status_read();
|
||||||
if(status) {
|
if(status) {
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
#define __RTIO_H
|
#define __RTIO_H
|
||||||
|
|
||||||
void rtio_init(void);
|
void rtio_init(void);
|
||||||
void rtio_oe(int channel, int oe);
|
void rtio_set_o(long long int timestamp, int channel, int value);
|
||||||
void rtio_set(long long int timestamp, int channel, int value);
|
void rtio_set_oe(long long int timestamp, int channel, int oe);
|
||||||
|
void rtio_set_sensitivity(long long int timestamp, int channel, int sensitivity);
|
||||||
long long int rtio_get_counter(void);
|
long long int rtio_get_counter(void);
|
||||||
long long int rtio_get(int channel, long long int time_limit);
|
long long int rtio_get(int channel, long long int time_limit);
|
||||||
int rtio_pileup_count(int channel);
|
|
||||||
|
|
||||||
void rtio_fud_sync(void);
|
void rtio_fud_sync(void);
|
||||||
void rtio_fud(long long int fud_time);
|
void rtio_fud(long long int fud_time);
|
||||||
|
|
|
@ -82,8 +82,8 @@ static void ttlout(char *n, char *value)
|
||||||
}
|
}
|
||||||
|
|
||||||
rtio_init();
|
rtio_init();
|
||||||
rtio_oe(n2, 1);
|
rtio_set_oe(rtio_get_counter() + 8000, n2, 1);
|
||||||
rtio_set(rtio_get_counter() + 8000, n2, value2);
|
rtio_set_o(rtio_get_counter() + 8000, n2, value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ddssel(char *n)
|
static void ddssel(char *n)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from misoclib.soc import mem_decoder
|
||||||
from targets.kc705 import MiniSoC
|
from targets.kc705 import MiniSoC
|
||||||
|
|
||||||
from artiq.gateware import amp, rtio, ad9858, nist_qc1
|
from artiq.gateware import amp, rtio, ad9858, nist_qc1
|
||||||
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCRG(Module, AutoCSR):
|
class _RTIOCRG(Module, AutoCSR):
|
||||||
|
@ -50,24 +51,36 @@ class _Peripherals(MiniSoC):
|
||||||
platform.request("user_led", 0),
|
platform.request("user_led", 0),
|
||||||
platform.request("user_led", 1)))
|
platform.request("user_led", 1)))
|
||||||
|
|
||||||
fud = Signal()
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
platform.request("ttl_l_tx_en").eq(1),
|
platform.request("ttl_l_tx_en").eq(1),
|
||||||
platform.request("ttl_h_tx_en").eq(1)
|
platform.request("ttl_h_tx_en").eq(1)
|
||||||
]
|
]
|
||||||
rtio_ins = [platform.request("pmt") for i in range(2)]
|
|
||||||
rtio_outs = [platform.request("ttl", i) for i in range(16)]
|
|
||||||
rtio_outs.append(platform.request("user_led", 2))
|
|
||||||
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_ins) + len(rtio_outs))
|
|
||||||
rtio_outs.append(fud)
|
|
||||||
|
|
||||||
|
# RTIO channels
|
||||||
|
rtio_channels = []
|
||||||
|
for i in range(2):
|
||||||
|
phy = ttl_simple.Inout(platform.request("pmt", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=512))
|
||||||
|
for i in range(16):
|
||||||
|
phy = ttl_simple.Output(platform.request("ttl", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
phy = ttl_simple.Output(platform.request("user_led", 2))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
fud = Signal()
|
||||||
|
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
|
||||||
|
phy = ttl_simple.Output(fud)
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
# RTIO core
|
||||||
self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
|
self.submodules.rtiocrg = _RTIOCRG(platform, self.crg.pll_sys)
|
||||||
self.submodules.rtiophy = rtio.phy.SimplePHY(
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
rtio_ins + rtio_outs,
|
clk_freq=125000000)
|
||||||
output_only_pads=set(rtio_outs))
|
|
||||||
self.submodules.rtio = rtio.RTIO(self.rtiophy,
|
|
||||||
clk_freq=125000000,
|
|
||||||
ififo_depth=512)
|
|
||||||
|
|
||||||
dds_pads = platform.request("dds")
|
dds_pads = platform.request("dds")
|
||||||
self.submodules.dds = ad9858.AD9858(dds_pads)
|
self.submodules.dds = ad9858.AD9858(dds_pads)
|
||||||
|
@ -85,7 +98,7 @@ class UP(_Peripherals):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
_Peripherals.__init__(self, *args, **kwargs)
|
_Peripherals.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
rtio_csrs = self.rtio.get_csrs()
|
rtio_csrs = self.rtio.get_csrs() + self.rtio.get_kernel_csrs()
|
||||||
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
||||||
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
|
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
|
||||||
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
|
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
|
||||||
|
@ -93,6 +106,7 @@ class UP(_Peripherals):
|
||||||
self.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus)
|
self.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus)
|
||||||
self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
|
self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
|
||||||
|
|
||||||
|
|
||||||
class AMP(_Peripherals):
|
class AMP(_Peripherals):
|
||||||
csr_map = {
|
csr_map = {
|
||||||
"kernel_cpu": 14
|
"kernel_cpu": 14
|
||||||
|
@ -112,7 +126,7 @@ class AMP(_Peripherals):
|
||||||
self.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i1)
|
self.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i1)
|
||||||
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i2)
|
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["mailbox"]), self.mailbox.i2)
|
||||||
|
|
||||||
rtio_csrs = self.rtio.get_csrs()
|
rtio_csrs = self.rtio.get_kernel_csrs()
|
||||||
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
||||||
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
|
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
|
||||||
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
|
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
|
||||||
|
@ -120,4 +134,5 @@ class AMP(_Peripherals):
|
||||||
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus)
|
self.kernel_cpu.add_wb_slave(mem_decoder(self.mem_map["dds"]), self.dds.bus)
|
||||||
self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
|
self.add_memory_region("dds", self.mem_map["dds"] + 0x80000000, 64*4)
|
||||||
|
|
||||||
|
|
||||||
default_subtarget = AMP
|
default_subtarget = AMP
|
||||||
|
|
|
@ -7,6 +7,7 @@ from misoclib.soc import mem_decoder
|
||||||
from targets.pipistrello import BaseSoC
|
from targets.pipistrello import BaseSoC
|
||||||
|
|
||||||
from artiq.gateware import amp, rtio, ad9858, nist_qc1
|
from artiq.gateware import amp, rtio, ad9858, nist_qc1
|
||||||
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
|
||||||
|
|
||||||
class _RTIOCRG(Module, AutoCSR):
|
class _RTIOCRG(Module, AutoCSR):
|
||||||
|
@ -66,26 +67,46 @@ class _Peripherals(BaseSoC):
|
||||||
platform.request("user_led", 1),
|
platform.request("user_led", 1),
|
||||||
))
|
))
|
||||||
|
|
||||||
fud = Signal()
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
platform.request("ttl_l_tx_en").eq(1),
|
platform.request("ttl_l_tx_en").eq(1),
|
||||||
platform.request("ttl_h_tx_en").eq(1)
|
platform.request("ttl_h_tx_en").eq(1)
|
||||||
]
|
]
|
||||||
rtio_ins = [platform.request("pmt", i) for i in range(2)]
|
|
||||||
rtio_ins += [platform.request("xtrig", 0)]
|
|
||||||
rtio_outs = [platform.request("ttl", i) for i in range(16)]
|
|
||||||
rtio_outs += [platform.request("ext_led", 0)]
|
|
||||||
rtio_outs += [platform.request("user_led", i) for i in range(2, 5)]
|
|
||||||
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_ins) + len(rtio_outs))
|
|
||||||
rtio_outs.append(fud)
|
|
||||||
|
|
||||||
|
# RTIO channels
|
||||||
|
rtio_channels = []
|
||||||
|
for i in range(2):
|
||||||
|
phy = ttl_simple.Inout(platform.request("pmt", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink, ififo_depth=512))
|
||||||
|
|
||||||
|
phy = ttl_simple.Inout(platform.request("xtrig", 0))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
for i in range(16):
|
||||||
|
phy = ttl_simple.Output(platform.request("ttl", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
phy = ttl_simple.Output(platform.request("ext_led", 0))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
for i in range(2, 5):
|
||||||
|
phy = ttl_simple.Output(platform.request("user_led", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
fud = Signal()
|
||||||
|
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
|
||||||
|
phy = ttl_simple.Output(fud)
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
# RTIO core
|
||||||
self.submodules.rtiocrg = _RTIOCRG(platform)
|
self.submodules.rtiocrg = _RTIOCRG(platform)
|
||||||
self.submodules.rtiophy = rtio.phy.SimplePHY(
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
rtio_ins + rtio_outs,
|
clk_freq=125000000)
|
||||||
output_only_pads=set(rtio_outs))
|
|
||||||
self.submodules.rtio = rtio.RTIO(self.rtiophy,
|
|
||||||
clk_freq=125000000,
|
|
||||||
ififo_depth=512)
|
|
||||||
|
|
||||||
dds_pads = platform.request("dds")
|
dds_pads = platform.request("dds")
|
||||||
self.submodules.dds = ad9858.AD9858(dds_pads)
|
self.submodules.dds = ad9858.AD9858(dds_pads)
|
||||||
|
|
|
@ -9,6 +9,7 @@ from misoclib.mem.sdram.core.minicon import MiniconSettings
|
||||||
from targets.ppro import BaseSoC
|
from targets.ppro import BaseSoC
|
||||||
|
|
||||||
from artiq.gateware import rtio, ad9858, nist_qc1
|
from artiq.gateware import rtio, ad9858, nist_qc1
|
||||||
|
from artiq.gateware.rtio.phy import ttl_simple
|
||||||
|
|
||||||
|
|
||||||
class _TestGen(Module):
|
class _TestGen(Module):
|
||||||
|
@ -78,29 +79,39 @@ class UP(BaseSoC):
|
||||||
platform.request("user_led", 0),
|
platform.request("user_led", 0),
|
||||||
platform.request("ext_led", 0)))
|
platform.request("ext_led", 0)))
|
||||||
|
|
||||||
fud = Signal()
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
platform.request("ttl_l_tx_en").eq(1),
|
platform.request("ttl_l_tx_en").eq(1),
|
||||||
platform.request("ttl_h_tx_en").eq(1)
|
platform.request("ttl_h_tx_en").eq(1)
|
||||||
]
|
]
|
||||||
rtio_ins = [platform.request("pmt") for i in range(2)]
|
|
||||||
rtio_outs = [platform.request("ttl", i) for i in range(5)]
|
|
||||||
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_ins) + len(rtio_outs))
|
|
||||||
rtio_outs.append(fud)
|
|
||||||
|
|
||||||
|
# RTIO channels
|
||||||
|
rtio_channels = []
|
||||||
|
for i in range(2):
|
||||||
|
phy = ttl_simple.Inout(platform.request("pmt", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
for i in range(5):
|
||||||
|
phy = ttl_simple.Output(platform.request("ttl", i))
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
fud = Signal()
|
||||||
|
self.add_constant("RTIO_FUD_CHANNEL", len(rtio_channels))
|
||||||
|
phy = ttl_simple.Output(fud)
|
||||||
|
self.submodules += phy
|
||||||
|
rtio_channels.append(rtio.Channel(phy.rtlink))
|
||||||
|
|
||||||
|
# RTIO core
|
||||||
self.submodules.rtiocrg = _RTIOMiniCRG(platform)
|
self.submodules.rtiocrg = _RTIOMiniCRG(platform)
|
||||||
self.submodules.rtiophy = rtio.phy.SimplePHY(
|
self.submodules.rtio = rtio.RTIO(rtio_channels,
|
||||||
rtio_ins + rtio_outs,
|
|
||||||
output_only_pads=set(rtio_outs))
|
|
||||||
self.submodules.rtio = rtio.RTIO(self.rtiophy,
|
|
||||||
clk_freq=125000000,
|
clk_freq=125000000,
|
||||||
counter_width=32,
|
counter_width=32)
|
||||||
ififo_depth=512)
|
|
||||||
|
|
||||||
rtio_csrs = self.rtio.get_csrs()
|
rtio_csrs = self.rtio.get_csrs() + self.rtio.get_kernel_csrs()
|
||||||
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
self.submodules.rtiowb = wbgen.Bank(rtio_csrs)
|
||||||
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
|
self.add_wb_slave(mem_decoder(self.mem_map["rtio"]), self.rtiowb.bus)
|
||||||
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000, 32, rtio_csrs)
|
self.add_csr_region("rtio", self.mem_map["rtio"] + 0x80000000,
|
||||||
|
32, rtio_csrs)
|
||||||
|
|
||||||
if with_test_gen:
|
if with_test_gen:
|
||||||
self.submodules.test_gen = _TestGen(platform.request("ttl", 8))
|
self.submodules.test_gen = _TestGen(platform.request("ttl", 8))
|
||||||
|
|
Loading…
Reference in New Issue