artiq/artiq/gateware/rtio/core.py

135 lines
5.3 KiB
Python

from functools import reduce
from operator import and_
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from misoc.interconnect.csr import *
from artiq.gateware.rtio import cri
from artiq.gateware.rtio import rtlink
from artiq.gateware.rtio.channel import *
from artiq.gateware.rtio.cdc import *
from artiq.gateware.rtio.sed.core import *
from artiq.gateware.rtio.input_collector import *
class Core(Module, AutoCSR):
def __init__(self, channels, lane_count=8, fifo_depth=128,
glbl_fine_ts_width=None):
self.cri = cri.Interface()
self.reset = CSR()
self.reset_phy = CSR()
self.async_error = CSR(3)
self.collision_channel = CSRStatus(16)
self.busy_channel = CSRStatus(16)
self.sequence_error_channel = CSRStatus(16)
# Clocking/Reset
# Create rsys, rio and rio_phy domains based on sys and rtio
# with reset controlled by CSR.
#
# The `rio` CD contains logic that is reset with `core.reset()`.
# That's state that could unduly affect subsequent experiments,
# i.e. input overflows caused by input gates left open, FIFO events far
# in the future blocking the experiment, pending RTIO or
# wishbone bus transactions, etc.
# The `rio_phy` CD contains state that is maintained across
# `core.reset()`, i.e. TTL output state, OE, DDS state.
cmd_reset = Signal(reset=1)
cmd_reset_phy = Signal(reset=1)
self.sync += [
cmd_reset.eq(self.reset.re),
cmd_reset_phy.eq(self.reset_phy.re)
]
cmd_reset.attr.add("no_retiming")
cmd_reset_phy.attr.add("no_retiming")
self.clock_domains.cd_rsys = ClockDomain()
self.clock_domains.cd_rio = ClockDomain()
self.clock_domains.cd_rio_phy = ClockDomain()
self.comb += [
self.cd_rsys.clk.eq(ClockSignal()),
self.cd_rsys.rst.eq(cmd_reset),
self.cd_rio.clk.eq(ClockSignal("rtio")),
self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
]
self.specials += AsyncResetSynchronizer(self.cd_rio, cmd_reset)
self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy)
# TSC
chan_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o)
for channel in channels),
max(rtlink.get_fine_ts_width(channel.interface.i)
for channel in channels))
if glbl_fine_ts_width is None:
glbl_fine_ts_width = chan_fine_ts_width
assert glbl_fine_ts_width >= chan_fine_ts_width
coarse_ts = Signal(64-glbl_fine_ts_width)
self.sync.rtio += coarse_ts.eq(coarse_ts + 1)
coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) # from rtio to sys
self.submodules += coarse_ts_cdc
self.comb += [
coarse_ts_cdc.i.eq(coarse_ts),
self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width)
]
self.coarse_ts = coarse_ts
# Outputs/Inputs
quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)]
outputs = SED(channels, glbl_fine_ts_width, "async",
quash_channels=quash_channels,
lane_count=lane_count, fifo_depth=fifo_depth,
interface=self.cri)
self.submodules += outputs
self.comb += outputs.coarse_timestamp.eq(coarse_ts)
self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts_cdc.o + 16)
inputs = InputCollector(channels, glbl_fine_ts_width, "async",
quash_channels=quash_channels,
interface=self.cri)
self.submodules += inputs
self.comb += inputs.coarse_timestamp.eq(coarse_ts)
# Asychronous output errors
o_collision_sync = BlindTransfer(data_width=16)
o_busy_sync = BlindTransfer(data_width=16)
self.submodules += o_collision_sync, o_busy_sync
o_collision = Signal()
o_busy = Signal()
o_sequence_error = Signal()
self.sync += [
If(self.async_error.re,
If(self.async_error.r[0], o_collision.eq(0)),
If(self.async_error.r[1], o_busy.eq(0)),
If(self.async_error.r[2], o_sequence_error.eq(0)),
),
If(o_collision_sync.o,
o_collision.eq(1),
If(~o_collision,
self.collision_channel.status.eq(o_collision_sync.data_o)
)
),
If(o_busy_sync.o,
o_busy.eq(1),
If(~o_busy,
self.busy_channel.status.eq(o_busy_sync.data_o)
)
),
If(outputs.sequence_error,
o_sequence_error.eq(1),
If(~o_sequence_error,
self.sequence_error_channel.status.eq(outputs.sequence_error_channel)
)
)
]
self.comb += self.async_error.w.eq(Cat(o_collision, o_busy, o_sequence_error))
self.comb += [
o_collision_sync.i.eq(outputs.collision),
o_collision_sync.data_i.eq(outputs.collision_channel),
o_busy_sync.i.eq(outputs.busy),
o_busy_sync.data_i.eq(outputs.busy_channel)
]