2016-10-14 00:34:59 +08:00
|
|
|
from types import SimpleNamespace
|
|
|
|
|
2016-10-10 23:12:12 +08:00
|
|
|
from migen import *
|
2018-02-20 17:26:01 +08:00
|
|
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
2018-06-21 17:00:32 +08:00
|
|
|
from migen.genlib.cdc import PulseSynchronizer
|
2018-02-18 22:29:30 +08:00
|
|
|
from misoc.interconnect.csr import *
|
2016-10-10 23:12:12 +08:00
|
|
|
|
2018-09-03 09:48:12 +08:00
|
|
|
from artiq.gateware.rtio import cri, rtlink
|
2017-09-24 12:23:47 +08:00
|
|
|
from artiq.gateware.rtio.sed.core import *
|
|
|
|
from artiq.gateware.rtio.input_collector import *
|
2018-09-05 17:56:56 +08:00
|
|
|
from artiq.gateware.drtio import (link_layer,
|
2017-09-24 12:49:21 +08:00
|
|
|
rt_packet_satellite, rt_errors_satellite,
|
2018-09-05 16:08:40 +08:00
|
|
|
rt_packet_master, rt_controller_master,
|
2018-09-09 14:11:21 +08:00
|
|
|
rt_packet_repeater, rt_controller_repeater)
|
2018-02-22 15:21:23 +08:00
|
|
|
from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer
|
2016-10-10 23:12:12 +08:00
|
|
|
|
|
|
|
|
2018-08-30 12:41:09 +08:00
|
|
|
__all__ = ["ChannelInterface", "TransceiverInterface",
|
|
|
|
"SyncRTIO",
|
2018-09-01 21:07:55 +08:00
|
|
|
"DRTIOSatellite", "DRTIOMaster", "DRTIORepeater"]
|
2018-08-30 12:41:09 +08:00
|
|
|
|
|
|
|
|
2017-07-18 13:27:33 +08:00
|
|
|
class ChannelInterface:
|
|
|
|
def __init__(self, encoder, decoders):
|
|
|
|
self.rx_ready = Signal()
|
|
|
|
self.encoder = encoder
|
|
|
|
self.decoders = decoders
|
|
|
|
|
|
|
|
|
2018-02-18 22:29:30 +08:00
|
|
|
class TransceiverInterface(AutoCSR):
|
2017-07-18 13:27:33 +08:00
|
|
|
def __init__(self, channel_interfaces):
|
2018-02-18 22:29:30 +08:00
|
|
|
self.stable_clkin = CSRStorage()
|
2017-07-18 13:27:33 +08:00
|
|
|
self.clock_domains.cd_rtio = ClockDomain()
|
|
|
|
for i in range(len(channel_interfaces)):
|
|
|
|
name = "rtio_rx" + str(i)
|
|
|
|
setattr(self.clock_domains, "cd_"+name, ClockDomain(name=name))
|
|
|
|
self.channels = channel_interfaces
|
|
|
|
|
|
|
|
|
2018-08-30 12:41:09 +08:00
|
|
|
async_errors_layout = [
|
|
|
|
("sequence_error", 1),
|
|
|
|
("sequence_error_channel", 16),
|
|
|
|
("collision", 1),
|
|
|
|
("collision_channel", 16),
|
|
|
|
("busy", 1),
|
|
|
|
("busy_channel", 16)
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class SyncRTIO(Module):
|
2018-09-03 09:48:12 +08:00
|
|
|
def __init__(self, tsc, channels, lane_count=8, fifo_depth=128):
|
2018-08-30 12:41:09 +08:00
|
|
|
self.cri = cri.Interface()
|
|
|
|
self.async_errors = Record(async_errors_layout)
|
|
|
|
|
2018-09-03 09:48:12 +08:00
|
|
|
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
|
2018-08-30 12:41:09 +08:00
|
|
|
|
|
|
|
self.submodules.outputs = ClockDomainsRenamer("rio")(
|
2018-09-03 09:48:12 +08:00
|
|
|
SED(channels, tsc.glbl_fine_ts_width, "sync",
|
2018-08-30 12:41:09 +08:00
|
|
|
lane_count=lane_count, fifo_depth=fifo_depth,
|
|
|
|
enable_spread=False, report_buffer_space=True,
|
|
|
|
interface=self.cri))
|
2018-09-03 09:48:12 +08:00
|
|
|
self.comb += self.outputs.coarse_timestamp.eq(tsc.coarse_ts)
|
|
|
|
self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16)
|
2018-08-30 12:41:09 +08:00
|
|
|
|
|
|
|
self.submodules.inputs = ClockDomainsRenamer("rio")(
|
2018-09-03 09:48:12 +08:00
|
|
|
InputCollector(tsc, channels, "sync", interface=self.cri))
|
2018-08-30 12:41:09 +08:00
|
|
|
|
|
|
|
for attr, _ in async_errors_layout:
|
|
|
|
self.comb += getattr(self.async_errors, attr).eq(getattr(self.outputs, attr))
|
|
|
|
|
|
|
|
|
2016-10-10 23:12:12 +08:00
|
|
|
class DRTIOSatellite(Module):
|
2018-09-03 09:48:12 +08:00
|
|
|
def __init__(self, tsc, chanif, rx_synchronizer=None):
|
2018-02-20 17:26:01 +08:00
|
|
|
self.reset = CSRStorage(reset=1)
|
|
|
|
self.reset_phy = CSRStorage(reset=1)
|
2018-06-21 17:00:32 +08:00
|
|
|
self.tsc_loaded = CSR()
|
2018-08-30 12:41:09 +08:00
|
|
|
# master interface in the rtio domain
|
|
|
|
self.cri = cri.Interface()
|
|
|
|
self.async_errors = Record(async_errors_layout)
|
2018-02-20 17:26:01 +08:00
|
|
|
|
|
|
|
self.clock_domains.cd_rio = ClockDomain()
|
|
|
|
self.clock_domains.cd_rio_phy = ClockDomain()
|
|
|
|
self.comb += [
|
|
|
|
self.cd_rio.clk.eq(ClockSignal("rtio")),
|
|
|
|
self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
|
|
|
|
]
|
|
|
|
reset = Signal()
|
|
|
|
reset_phy = Signal()
|
|
|
|
reset.attr.add("no_retiming")
|
|
|
|
reset_phy.attr.add("no_retiming")
|
|
|
|
self.sync += [
|
|
|
|
reset.eq(self.reset.storage),
|
|
|
|
reset_phy.eq(self.reset_phy.storage)
|
|
|
|
]
|
|
|
|
self.specials += [
|
|
|
|
AsyncResetSynchronizer(self.cd_rio, reset),
|
|
|
|
AsyncResetSynchronizer(self.cd_rio_phy, reset_phy)
|
|
|
|
]
|
2017-01-16 03:44:43 +08:00
|
|
|
|
2016-10-10 23:12:12 +08:00
|
|
|
self.submodules.link_layer = link_layer.LinkLayer(
|
2017-07-18 13:27:33 +08:00
|
|
|
chanif.encoder, chanif.decoders)
|
|
|
|
self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready)
|
2016-10-15 18:36:27 +08:00
|
|
|
|
2018-02-20 17:26:01 +08:00
|
|
|
if rx_synchronizer is None:
|
|
|
|
rx_synchronizer = GenericRXSynchronizer()
|
|
|
|
self.submodules += rx_synchronizer
|
|
|
|
|
2016-10-14 00:34:59 +08:00
|
|
|
link_layer_sync = SimpleNamespace(
|
2016-10-17 19:23:08 +08:00
|
|
|
tx_aux_frame=self.link_layer.tx_aux_frame,
|
2016-10-14 00:34:59 +08:00
|
|
|
tx_aux_data=self.link_layer.tx_aux_data,
|
|
|
|
tx_aux_ack=self.link_layer.tx_aux_ack,
|
|
|
|
tx_rt_frame=self.link_layer.tx_rt_frame,
|
|
|
|
tx_rt_data=self.link_layer.tx_rt_data,
|
|
|
|
|
2016-10-17 19:23:08 +08:00
|
|
|
rx_aux_stb=rx_synchronizer.resync(self.link_layer.rx_aux_stb),
|
|
|
|
rx_aux_frame=rx_synchronizer.resync(self.link_layer.rx_aux_frame),
|
2016-12-07 23:03:14 +08:00
|
|
|
rx_aux_frame_perm=rx_synchronizer.resync(self.link_layer.rx_aux_frame_perm),
|
2016-10-17 19:23:08 +08:00
|
|
|
rx_aux_data=rx_synchronizer.resync(self.link_layer.rx_aux_data),
|
|
|
|
rx_rt_frame=rx_synchronizer.resync(self.link_layer.rx_rt_frame),
|
2016-12-07 23:03:14 +08:00
|
|
|
rx_rt_frame_perm=rx_synchronizer.resync(self.link_layer.rx_rt_frame_perm),
|
2016-10-17 19:23:08 +08:00
|
|
|
rx_rt_data=rx_synchronizer.resync(self.link_layer.rx_rt_data)
|
2016-10-14 00:34:59 +08:00
|
|
|
)
|
2016-12-07 23:03:14 +08:00
|
|
|
self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio")
|
2017-03-07 00:46:59 +08:00
|
|
|
self.submodules.rt_packet = ClockDomainsRenamer("rtio")(
|
2018-08-30 12:41:09 +08:00
|
|
|
rt_packet_satellite.RTPacketSatellite(link_layer_sync, interface=self.cri))
|
2018-02-20 17:26:01 +08:00
|
|
|
self.comb += self.rt_packet.reset.eq(self.cd_rio.rst)
|
2016-10-15 18:36:27 +08:00
|
|
|
|
2018-09-03 09:48:12 +08:00
|
|
|
self.comb += [
|
|
|
|
tsc.load.eq(self.rt_packet.tsc_load),
|
|
|
|
tsc.load_value.eq(self.rt_packet.tsc_load_value)
|
|
|
|
]
|
2017-09-24 12:23:47 +08:00
|
|
|
|
2018-06-21 17:00:32 +08:00
|
|
|
ps_tsc_load = PulseSynchronizer("rtio", "sys")
|
|
|
|
self.submodules += ps_tsc_load
|
|
|
|
self.comb += ps_tsc_load.i.eq(self.rt_packet.tsc_load)
|
|
|
|
self.sync += [
|
|
|
|
If(self.tsc_loaded.re, self.tsc_loaded.w.eq(0)),
|
|
|
|
If(ps_tsc_load.o, self.tsc_loaded.w.eq(1))
|
|
|
|
]
|
|
|
|
|
2017-04-01 12:18:00 +08:00
|
|
|
self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite(
|
2018-09-12 15:44:34 +08:00
|
|
|
self.rt_packet, tsc, self.async_errors)
|
2017-04-01 12:18:00 +08:00
|
|
|
|
2016-11-14 17:20:47 +08:00
|
|
|
def get_csrs(self):
|
2018-06-21 17:00:32 +08:00
|
|
|
return ([self.reset, self.reset_phy, self.tsc_loaded] +
|
2018-02-20 17:26:01 +08:00
|
|
|
self.link_layer.get_csrs() + self.link_stats.get_csrs() +
|
2018-09-05 17:56:56 +08:00
|
|
|
self.rt_errors.get_csrs())
|
2016-11-14 17:20:47 +08:00
|
|
|
|
2016-10-10 23:12:12 +08:00
|
|
|
|
|
|
|
class DRTIOMaster(Module):
|
2018-09-03 09:48:12 +08:00
|
|
|
def __init__(self, tsc, chanif):
|
2016-10-21 22:46:14 +08:00
|
|
|
self.submodules.link_layer = link_layer.LinkLayer(
|
2017-07-18 13:27:33 +08:00
|
|
|
chanif.encoder, chanif.decoders)
|
|
|
|
self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready)
|
2016-11-19 10:46:56 +08:00
|
|
|
|
2016-12-07 23:03:14 +08:00
|
|
|
self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx")
|
2017-03-07 00:46:59 +08:00
|
|
|
self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer)
|
|
|
|
self.submodules.rt_controller = rt_controller_master.RTController(
|
2018-09-03 09:48:12 +08:00
|
|
|
tsc, self.rt_packet)
|
2016-10-24 19:50:13 +08:00
|
|
|
|
|
|
|
def get_csrs(self):
|
2016-11-04 19:38:24 +08:00
|
|
|
return (self.link_layer.get_csrs() +
|
2016-12-07 23:03:14 +08:00
|
|
|
self.link_stats.get_csrs() +
|
2018-09-12 13:01:27 +08:00
|
|
|
self.rt_controller.get_csrs())
|
2018-08-30 15:15:32 +08:00
|
|
|
|
|
|
|
@property
|
|
|
|
def cri(self):
|
|
|
|
return self.rt_controller.cri
|
2018-09-01 21:07:55 +08:00
|
|
|
|
|
|
|
|
|
|
|
class DRTIORepeater(Module):
|
2018-09-05 15:55:20 +08:00
|
|
|
def __init__(self, tsc, chanif):
|
2018-09-01 21:07:55 +08:00
|
|
|
self.submodules.link_layer = link_layer.LinkLayer(
|
|
|
|
chanif.encoder, chanif.decoders)
|
|
|
|
self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready)
|
|
|
|
|
|
|
|
self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx")
|
2018-09-05 15:55:20 +08:00
|
|
|
self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer)
|
2018-09-05 16:08:40 +08:00
|
|
|
self.submodules.rt_controller = rt_controller_repeater.RTController(self.rt_packet)
|
2018-09-01 21:07:55 +08:00
|
|
|
|
|
|
|
def get_csrs(self):
|
|
|
|
return (self.link_layer.get_csrs() +
|
|
|
|
self.link_stats.get_csrs() +
|
2018-09-05 17:56:56 +08:00
|
|
|
self.rt_controller.get_csrs())
|
2018-09-01 21:07:55 +08:00
|
|
|
|
|
|
|
@property
|
|
|
|
def cri(self):
|
|
|
|
return self.rt_packet.cri
|