artiq/artiq/gateware/rtio/core.py

116 lines
4.4 KiB
Python

from functools import reduce
from operator import and_
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.cdc import BlindTransfer
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.sed.core import *
from artiq.gateware.rtio.input_collector import *
class Core(Module, AutoCSR):
def __init__(self, tsc, channels, lane_count=8, fifo_depth=128):
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 rio and rio_phy domains based on sys
# 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)
]
self.clock_domains.cd_rio = ClockDomain()
self.clock_domains.cd_rio_phy = ClockDomain()
self.comb += [
self.cd_rio.clk.eq(ClockSignal()),
self.cd_rio.rst.eq(cmd_reset),
self.cd_rio_phy.clk.eq(ClockSignal()),
self.cd_rio_phy.rst.eq(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))
assert tsc.glbl_fine_ts_width >= chan_fine_ts_width
# Outputs/Inputs
quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)]
outputs = SED(channels, tsc.glbl_fine_ts_width,
quash_channels=quash_channels,
lane_count=lane_count, fifo_depth=fifo_depth,
interface=self.cri)
self.submodules += outputs
self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts)
self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16)
inputs = InputCollector(tsc, channels,
quash_channels=quash_channels,
interface=self.cri)
self.submodules += inputs
# Asychronous output errors
o_collision_sync = BlindTransfer("rio", "sys", data_width=16)
o_busy_sync = BlindTransfer("rio", "sys", 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)
]