From aa64e6c1c6ad2b43988b2988649daadc36de42ed Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 29 Aug 2018 15:16:43 +0800 Subject: [PATCH 01/92] cri: add buffer space request protocol --- artiq/gateware/drtio/rt_packet_satellite.py | 14 ++++++++++---- artiq/gateware/rtio/cri.py | 13 +++++++++---- artiq/gateware/rtio/sed/core.py | 5 ++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 02a5a98b1..ef0de8335 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -113,7 +113,7 @@ class RTPacketSatellite(Module): rx_plm.types["echo_request"]: echo_req.eq(1), rx_plm.types["set_time"]: NextState("SET_TIME"), rx_plm.types["write"]: NextState("WRITE"), - rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"), + rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE_REQUEST"), rx_plm.types["read_request"]: NextState("READ_REQUEST"), "default": self.unknown_packet_type.eq(1) }) @@ -142,10 +142,16 @@ class RTPacketSatellite(Module): ) ) ) + rx_fsm.act("BUFFER_SPACE_REQUEST", + self.cri.cmd.eq(cri.commands["get_buffer_space"]), + NextState("BUFFER_SPACE") + ) rx_fsm.act("BUFFER_SPACE", - buffer_space_set.eq(1), - buffer_space_update.eq(1), - NextState("INPUT") + If(self.cri.o_buffer_space_valid, + buffer_space_set.eq(1), + buffer_space_update.eq(1), + NextState("INPUT") + ) ) rx_fsm.act("READ_REQUEST", diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 2a871f736..4a889bc27 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -13,11 +13,13 @@ from misoc.interconnect.csr import * commands = { "nop": 0, - "write": 1, # i_status should have the "wait for status" bit set until # an event is available, or timestamp is reached. - "read": 2 + "read": 2, + # targets must assert o_buffer_space_valid in response + # to this command + "get_buffer_space": 3 } @@ -32,8 +34,11 @@ layout = [ # o_status bits: # <0:wait> <1:underflow> <2:link error> ("o_status", 3, DIR_S_TO_M), - # targets may optionally report a pessimistic estimate of the number - # of outputs events that can be written without waiting. + + # pessimistic estimate of the number of outputs events that can be + # written without waiting. + # this feature may be omitted on systems without DRTIO. + ("o_buffer_space_valid", 1, DIR_S_TO_M), ("o_buffer_space", 16, DIR_S_TO_M), ("i_data", 32, DIR_S_TO_M), diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index ca757e976..7d0b0de4e 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -55,7 +55,10 @@ class SED(Module): self.comb += i.eq(o) if report_buffer_space: - self.comb += self.cri.o_buffer_space.eq(self.fifos.buffer_space) + self.comb += [ + self.cri.o_buffer_space_valid.eq(1), + self.cri.o_buffer_space.eq(self.fifos.buffer_space) + ] @property def cri(self): From ce6e390d5f1fefc0bcf5db88fd1dc0f24f6dc53f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Aug 2018 12:41:09 +0800 Subject: [PATCH 02/92] drtio: expose internal satellite CRI --- artiq/gateware/drtio/__init__.py | 2 +- artiq/gateware/drtio/core.py | 72 ++++++++++++++------ artiq/gateware/drtio/rt_errors_satellite.py | 24 +++---- artiq/gateware/drtio/rt_packet_satellite.py | 6 +- artiq/gateware/test/drtio/test_full_stack.py | 10 ++- 5 files changed, 75 insertions(+), 39 deletions(-) diff --git a/artiq/gateware/drtio/__init__.py b/artiq/gateware/drtio/__init__.py index 7e3143e30..7b83c1934 100644 --- a/artiq/gateware/drtio/__init__.py +++ b/artiq/gateware/drtio/__init__.py @@ -1,2 +1,2 @@ -from artiq.gateware.drtio.core import DRTIOSatellite, DRTIOMaster +from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 38c6d8a2a..a60e30b81 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -5,6 +5,7 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * +from artiq.gateware.rtio import cri from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, @@ -13,6 +14,11 @@ from artiq.gateware.drtio import (link_layer, aux_controller, from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer +__all__ = ["ChannelInterface", "TransceiverInterface", + "SyncRTIO", + "DRTIOSatellite", "DRTIOMaster"] + + class ChannelInterface: def __init__(self, encoder, decoders): self.rx_ready = Signal() @@ -30,12 +36,49 @@ class TransceiverInterface(AutoCSR): self.channels = channel_interfaces +async_errors_layout = [ + ("sequence_error", 1), + ("sequence_error_channel", 16), + ("collision", 1), + ("collision_channel", 16), + ("busy", 1), + ("busy_channel", 16) +] + + +class SyncRTIO(Module): + def __init__(self, channels, fine_ts_width=3, lane_count=8, fifo_depth=128): + self.cri = cri.Interface() + self.async_errors = Record(async_errors_layout) + self.coarse_ts = Signal(64 - fine_ts_width) + + self.comb += self.cri.counter.eq(self.coarse_ts << fine_ts_width) + + self.submodules.outputs = ClockDomainsRenamer("rio")( + SED(channels, fine_ts_width, "sync", + lane_count=lane_count, fifo_depth=fifo_depth, + enable_spread=False, report_buffer_space=True, + interface=self.cri)) + self.comb += self.outputs.coarse_timestamp.eq(self.coarse_ts) + self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(self.coarse_ts + 16) + + self.submodules.inputs = ClockDomainsRenamer("rio")( + InputCollector(channels, fine_ts_width, "sync", + interface=self.cri)) + self.comb += self.inputs.coarse_timestamp.eq(self.coarse_ts) + + for attr, _ in async_errors_layout: + self.comb += getattr(self.async_errors, attr).eq(getattr(self.outputs, attr)) + + class DRTIOSatellite(Module): - def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, - lane_count=8, fifo_depth=128): + def __init__(self, chanif, rx_synchronizer=None, fine_ts_width=3): self.reset = CSRStorage(reset=1) self.reset_phy = CSRStorage(reset=1) self.tsc_loaded = CSR() + # master interface in the rtio domain + self.cri = cri.Interface() + self.async_errors = Record(async_errors_layout) self.clock_domains.cd_rio = ClockDomain() self.clock_domains.cd_rio_phy = ClockDomain() @@ -81,18 +124,16 @@ class DRTIOSatellite(Module): ) self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio") self.submodules.rt_packet = ClockDomainsRenamer("rtio")( - rt_packet_satellite.RTPacketSatellite(link_layer_sync)) + rt_packet_satellite.RTPacketSatellite(link_layer_sync, interface=self.cri)) self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) - coarse_ts = Signal(64 - fine_ts_width) + self.coarse_ts = Signal(64 - fine_ts_width) self.sync.rtio += \ If(self.rt_packet.tsc_load, - coarse_ts.eq(self.rt_packet.tsc_load_value) + self.coarse_ts.eq(self.rt_packet.tsc_load_value) ).Else( - coarse_ts.eq(coarse_ts + 1) + self.coarse_ts.eq(self.coarse_ts + 1) ) - self.comb += self.rt_packet.cri.counter.eq(coarse_ts << fine_ts_width) - self.coarse_ts = coarse_ts ps_tsc_load = PulseSynchronizer("rtio", "sys") self.submodules += ps_tsc_load @@ -102,21 +143,8 @@ class DRTIOSatellite(Module): If(ps_tsc_load.o, self.tsc_loaded.w.eq(1)) ] - self.submodules.outputs = ClockDomainsRenamer("rio")( - SED(channels, fine_ts_width, "sync", - lane_count=lane_count, fifo_depth=fifo_depth, - enable_spread=False, report_buffer_space=True, - interface=self.rt_packet.cri)) - self.comb += self.outputs.coarse_timestamp.eq(coarse_ts) - self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) - - self.submodules.inputs = ClockDomainsRenamer("rio")( - InputCollector(channels, fine_ts_width, "sync", - interface=self.rt_packet.cri)) - self.comb += self.inputs.coarse_timestamp.eq(coarse_ts) - self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, self.outputs) + self.rt_packet, self.cri, self.async_errors) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 8d563a3dc..50f0b53af 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,7 +7,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, outputs): + def __init__(self, rt_packet, cri, async_errors): self.protocol_error = CSR(4) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) @@ -56,11 +56,11 @@ class RTErrorsSatellite(Module, AutoCSR): underflow_error_cri = Signal(16+64+64) underflow_error_csr = Signal(16+64+64) self.comb += [ - underflow.eq(outputs.cri.o_status[1]), - overflow.eq(outputs.cri.o_status[0]), - underflow_error_cri.eq(Cat(outputs.cri.chan_sel[:16], - outputs.cri.timestamp, - outputs.cri.counter)), + underflow.eq(cri.o_status[1]), + overflow.eq(cri.o_status[0]), + underflow_error_cri.eq(Cat(cri.chan_sel[:16], + cri.timestamp, + cri.counter)), Cat(self.underflow_channel.status, self.underflow_timestamp_event.status, self.underflow_timestamp_counter.status).eq(underflow_error_csr) @@ -73,10 +73,10 @@ class RTErrorsSatellite(Module, AutoCSR): ) error_csr(self.rtio_error, - (outputs.sequence_error, False, - outputs.sequence_error_channel, self.sequence_error_channel.status), - (outputs.collision, False, - outputs.collision_channel, self.collision_channel.status), - (outputs.busy, False, - outputs.busy_channel, self.busy_channel.status) + (async_errors.sequence_error, False, + async_errors.sequence_error_channel, self.sequence_error_channel.status), + (async_errors.collision, False, + async_errors.collision_channel, self.collision_channel.status), + (async_errors.busy, False, + async_errors.busy_channel, self.busy_channel.status) ) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index ef0de8335..c5266e33b 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -8,7 +8,7 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketSatellite(Module): - def __init__(self, link_layer): + def __init__(self, link_layer, interface=None): self.reset = Signal() self.unknown_packet_type = Signal() @@ -17,7 +17,9 @@ class RTPacketSatellite(Module): self.tsc_load = Signal() self.tsc_load_value = Signal(64) - self.cri = cri.Interface() + if interface is None: + interface = cri.Interface() + self.cri = interface # # # diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index feade41d4..4abfe9e3c 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -67,12 +67,18 @@ class DUT(Module): rtio.Channel.from_phy(self.phy2), ] self.submodules.satellite = DRTIOSatellite( - self.transceivers.bob, rtio_channels, rx_synchronizer, - lane_count=4, fifo_depth=8, fine_ts_width=0) + self.transceivers.bob, rx_synchronizer, fine_ts_width=0) self.satellite.reset.storage.reset = 0 self.satellite.reset.storage_full.reset = 0 self.satellite.reset_phy.storage.reset = 0 self.satellite.reset_phy.storage_full.reset = 0 + self.submodules.satellite_rtio = SyncRTIO( + rtio_channels, fine_ts_width=0, lane_count=4, fifo_depth=8) + self.comb += [ + self.satellite_rtio.coarse_ts.eq(self.satellite.coarse_ts), + self.satellite.cri.connect(self.satellite_rtio.cri), + self.satellite.async_errors.eq(self.satellite_rtio.async_errors), + ] class OutputsTestbench: From 4f963e1e11491ba51842e3b67459643ef85f59fb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Aug 2018 15:15:32 +0800 Subject: [PATCH 03/92] drtio: minor cleanup --- artiq/gateware/drtio/core.py | 9 ++++++--- artiq/gateware/drtio/rt_controller_master.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index a60e30b81..e4f69d1e5 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -156,7 +156,7 @@ class DRTIOSatellite(Module): class DRTIOMaster(Module): - def __init__(self, chanif, channel_count=1024, fine_ts_width=3): + def __init__(self, chanif, fine_ts_width=3): self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) @@ -164,9 +164,8 @@ class DRTIOMaster(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( - self.rt_packet, channel_count, fine_ts_width) + self.rt_packet, fine_ts_width) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) - self.cri = self.rt_controller.cri self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -177,3 +176,7 @@ class DRTIOMaster(Module): self.rt_controller.get_csrs() + self.rt_manager.get_csrs() + self.aux_controller.get_csrs()) + + @property + def cri(self): + return self.rt_controller.cri diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 786e2aa97..c3ef0214b 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -45,7 +45,7 @@ class RTIOCounter(Module): class RTController(Module): - def __init__(self, rt_packet, channel_count, fine_ts_width): + def __init__(self, rt_packet, fine_ts_width): self.csrs = _CSRs() self.cri = cri.Interface() From 6057cb797cfe27cc5cde18a6795ffab6b028fad8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 31 Aug 2018 16:28:33 +0800 Subject: [PATCH 04/92] drtio: reorganize tests --- artiq/gateware/test/drtio/test_cdc.py | 94 +++++++++++++++++++ ..._packet.py => test_rt_packet_satellite.py} | 91 ------------------ 2 files changed, 94 insertions(+), 91 deletions(-) create mode 100644 artiq/gateware/test/drtio/test_cdc.py rename artiq/gateware/test/drtio/{test_rt_packet.py => test_rt_packet_satellite.py} (56%) diff --git a/artiq/gateware/test/drtio/test_cdc.py b/artiq/gateware/test/drtio/test_cdc.py new file mode 100644 index 000000000..689df6221 --- /dev/null +++ b/artiq/gateware/test/drtio/test_cdc.py @@ -0,0 +1,94 @@ +import unittest +import random + +from migen import * + +from artiq.gateware.drtio.rt_packet_master import (_CrossDomainRequest, + _CrossDomainNotification) + +class TestCDC(unittest.TestCase): + def test_cross_domain_request(self): + prng = random.Random(1) + for sys_freq in 3, 6, 11: + for srv_freq in 3, 6, 11: + req_stb = Signal() + req_ack = Signal() + req_data = Signal(8) + srv_stb = Signal() + srv_ack = Signal() + srv_data = Signal(8) + test_seq = [93, 92, 19, 39, 91, 30, 12, 91, 38, 42] + received_seq = [] + + def requester(): + for data in test_seq: + yield req_data.eq(data) + yield req_stb.eq(1) + yield + while not (yield req_ack): + yield + yield req_stb.eq(0) + for j in range(prng.randrange(0, 10)): + yield + + def server(): + for i in range(len(test_seq)): + while not (yield srv_stb): + yield + received_seq.append((yield srv_data)) + for j in range(prng.randrange(0, 10)): + yield + yield srv_ack.eq(1) + yield + yield srv_ack.eq(0) + yield + + dut = _CrossDomainRequest("srv", + req_stb, req_ack, req_data, + srv_stb, srv_ack, srv_data) + run_simulation(dut, + {"sys": requester(), "srv": server()}, + {"sys": sys_freq, "srv": srv_freq}) + self.assertEqual(test_seq, received_seq) + + def test_cross_domain_notification(self): + prng = random.Random(1) + + emi_stb = Signal() + emi_data = Signal(8) + rec_stb = Signal() + rec_ack = Signal() + rec_data = Signal(8) + + test_seq = [23, 12, 8, 3, 28] + received_seq = [] + + def emitter(): + for data in test_seq: + yield emi_stb.eq(1) + yield emi_data.eq(data) + yield + yield emi_stb.eq(0) + yield + for j in range(prng.randrange(0, 3)): + yield + + def receiver(): + for i in range(len(test_seq)): + while not (yield rec_stb): + yield + received_seq.append((yield rec_data)) + yield rec_ack.eq(1) + yield + yield rec_ack.eq(0) + yield + for j in range(prng.randrange(0, 3)): + yield + + dut = _CrossDomainNotification("emi", + emi_stb, emi_data, + rec_stb, rec_ack, rec_data) + run_simulation(dut, + {"emi": emitter(), "sys": receiver()}, + {"emi": 13, "sys": 3}) + self.assertEqual(test_seq, received_seq) diff --git a/artiq/gateware/test/drtio/test_rt_packet.py b/artiq/gateware/test/drtio/test_rt_packet_satellite.py similarity index 56% rename from artiq/gateware/test/drtio/test_rt_packet.py rename to artiq/gateware/test/drtio/test_rt_packet_satellite.py index 05d80aa4d..5bbdb44f7 100644 --- a/artiq/gateware/test/drtio/test_rt_packet.py +++ b/artiq/gateware/test/drtio/test_rt_packet_satellite.py @@ -1,13 +1,10 @@ import unittest from types import SimpleNamespace -import random from migen import * from artiq.gateware.drtio.rt_serializer import * from artiq.gateware.drtio.rt_packet_satellite import RTPacketSatellite -from artiq.gateware.drtio.rt_packet_master import (_CrossDomainRequest, - _CrossDomainNotification) class PacketInterface: @@ -123,91 +120,3 @@ class TestSatellite(unittest.TestCase): yield run_simulation(dut, [send(), receive()]) self.assertEqual(tx_times, rx_times) - - -class TestCDC(unittest.TestCase): - def test_cross_domain_request(self): - prng = random.Random(1) - for sys_freq in 3, 6, 11: - for srv_freq in 3, 6, 11: - req_stb = Signal() - req_ack = Signal() - req_data = Signal(8) - srv_stb = Signal() - srv_ack = Signal() - srv_data = Signal(8) - test_seq = [93, 92, 19, 39, 91, 30, 12, 91, 38, 42] - received_seq = [] - - def requester(): - for data in test_seq: - yield req_data.eq(data) - yield req_stb.eq(1) - yield - while not (yield req_ack): - yield - yield req_stb.eq(0) - for j in range(prng.randrange(0, 10)): - yield - - def server(): - for i in range(len(test_seq)): - while not (yield srv_stb): - yield - received_seq.append((yield srv_data)) - for j in range(prng.randrange(0, 10)): - yield - yield srv_ack.eq(1) - yield - yield srv_ack.eq(0) - yield - - dut = _CrossDomainRequest("srv", - req_stb, req_ack, req_data, - srv_stb, srv_ack, srv_data) - run_simulation(dut, - {"sys": requester(), "srv": server()}, - {"sys": sys_freq, "srv": srv_freq}) - self.assertEqual(test_seq, received_seq) - - def test_cross_domain_notification(self): - prng = random.Random(1) - - emi_stb = Signal() - emi_data = Signal(8) - rec_stb = Signal() - rec_ack = Signal() - rec_data = Signal(8) - - test_seq = [23, 12, 8, 3, 28] - received_seq = [] - - def emitter(): - for data in test_seq: - yield emi_stb.eq(1) - yield emi_data.eq(data) - yield - yield emi_stb.eq(0) - yield - for j in range(prng.randrange(0, 3)): - yield - - def receiver(): - for i in range(len(test_seq)): - while not (yield rec_stb): - yield - received_seq.append((yield rec_data)) - yield rec_ack.eq(1) - yield - yield rec_ack.eq(0) - yield - for j in range(prng.randrange(0, 3)): - yield - - dut = _CrossDomainNotification("emi", - emi_stb, emi_data, - rec_stb, rec_ack, rec_data) - run_simulation(dut, - {"emi": emitter(), "sys": receiver()}, - {"emi": 13, "sys": 3}) - self.assertEqual(test_seq, received_seq) From 078c862618d2c13fb25dca1203e140de4276cb8d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 1 Sep 2018 21:07:55 +0800 Subject: [PATCH 05/92] drtio: add repeater (WIP, write only) --- artiq/gateware/drtio/__init__.py | 2 +- artiq/gateware/drtio/core.py | 24 ++++- artiq/gateware/drtio/rt_packet_repeater.py | 92 +++++++++++++++++++ artiq/gateware/test/drtio/packet_interface.py | 72 +++++++++++++++ .../test/drtio/test_rt_packet_repeater.py | 62 +++++++++++++ .../test/drtio/test_rt_packet_satellite.py | 88 ++---------------- 6 files changed, 260 insertions(+), 80 deletions(-) create mode 100644 artiq/gateware/drtio/rt_packet_repeater.py create mode 100644 artiq/gateware/test/drtio/packet_interface.py create mode 100644 artiq/gateware/test/drtio/test_rt_packet_repeater.py diff --git a/artiq/gateware/drtio/__init__.py b/artiq/gateware/drtio/__init__.py index 7b83c1934..76cb979c7 100644 --- a/artiq/gateware/drtio/__init__.py +++ b/artiq/gateware/drtio/__init__.py @@ -1,2 +1,2 @@ -from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster +from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster, DRTIORepeater diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index e4f69d1e5..209a3b58d 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -16,7 +16,7 @@ from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer __all__ = ["ChannelInterface", "TransceiverInterface", "SyncRTIO", - "DRTIOSatellite", "DRTIOMaster"] + "DRTIOSatellite", "DRTIOMaster", "DRTIORepeater"] class ChannelInterface: @@ -180,3 +180,25 @@ class DRTIOMaster(Module): @property def cri(self): return self.rt_controller.cri + + +class DRTIORepeater(Module): + def __init__(self, chanif): + 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") + self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(self.link_layer) + + self.submodules.aux_controller = aux_controller.AuxController( + self.link_layer) + + def get_csrs(self): + return (self.link_layer.get_csrs() + + self.link_stats.get_csrs() + + self.aux_controller.get_csrs()) + + @property + def cri(self): + return self.rt_packet.cri diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py new file mode 100644 index 000000000..0eb9edfb3 --- /dev/null +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -0,0 +1,92 @@ +from migen import * +from migen.genlib.fsm import * + +from artiq.gateware.rtio import cri +from artiq.gateware.drtio.rt_serializer import * + + +class RTPacketRepeater(Module): + def __init__(self, link_layer): + self.cri = cri.Interface() + + # RX/TX datapath + assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) + assert len(link_layer.tx_rt_data) % 8 == 0 + ws = len(link_layer.tx_rt_data) + tx_plm = get_m2s_layouts(ws) + tx_dp = ClockDomainsRenamer("rtio")(TransmitDatapath( + link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm)) + self.submodules += tx_dp + rx_plm = get_s2m_layouts(ws) + rx_dp = ClockDomainsRenamer("rtio_rx")(ReceiveDatapath( + link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm)) + self.submodules += rx_dp + + # Write buffer and extra data count + wb_timestamp = Signal(64) + wb_channel = Signal(16) + wb_address = Signal(16) + wb_data = Signal(512) + self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + wb_timestamp.eq(self.cri.timestamp), + wb_channel.eq(self.cri.chan_sel), + wb_address.eq(self.cri.o_address), + wb_data.eq(self.cri.o_data)) + + wb_extra_data_cnt = Signal(8) + short_data_len = tx_plm.field_length("write", "short_data") + wb_extra_data_a = Signal(512) + self.comb += wb_extra_data_a.eq(self.cri.o_data[short_data_len:]) + for i in range(512//ws): + self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + If(wb_extra_data_a[ws*i:ws*(i+1)] != 0, wb_extra_data_cnt.eq(i+1))) + + wb_extra_data = Signal(512) + self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + wb_extra_data.eq(wb_extra_data_a)) + + extra_data_ce = Signal() + extra_data_last = Signal() + extra_data_counter = Signal(max=512//ws+1) + self.comb += [ + Case(extra_data_counter, + {i+1: tx_dp.raw_data.eq(wb_extra_data[i*ws:(i+1)*ws]) + for i in range(512//ws)}), + extra_data_last.eq(extra_data_counter == wb_extra_data_cnt) + ] + self.sync.rtio += \ + If(extra_data_ce, + extra_data_counter.eq(extra_data_counter + 1), + ).Else( + extra_data_counter.eq(1) + ) + + # TX FSM + tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) + self.submodules += tx_fsm + + tx_fsm.act("IDLE", + If(self.cri.cmd == cri.commands["write"], NextState("WRITE")) + ) + tx_fsm.act("WRITE", + tx_dp.send("write", + timestamp=wb_timestamp, + channel=wb_channel, + address=wb_address, + extra_data_cnt=wb_extra_data_cnt, + short_data=wb_data[:short_data_len]), + If(tx_dp.packet_last, + If(wb_extra_data_cnt == 0, + NextState("IDLE") + ).Else( + NextState("WRITE_EXTRA") + ) + ) + ) + tx_fsm.act("WRITE_EXTRA", + tx_dp.raw_stb.eq(1), + extra_data_ce.eq(1), + If(extra_data_last, + NextState("IDLE") + ) + ) diff --git a/artiq/gateware/test/drtio/packet_interface.py b/artiq/gateware/test/drtio/packet_interface.py new file mode 100644 index 000000000..c6d2979a2 --- /dev/null +++ b/artiq/gateware/test/drtio/packet_interface.py @@ -0,0 +1,72 @@ +from migen import * + +from artiq.gateware.drtio.rt_serializer import * + + +class PacketInterface: + def __init__(self, direction, ws): + if direction == "m2s": + self.plm = get_m2s_layouts(ws) + elif direction == "s2m": + self.plm = get_s2m_layouts(ws) + else: + raise ValueError + self.frame = Signal() + self.data = Signal(ws) + + def send(self, ty, **kwargs): + idx = 8 + value = self.plm.types[ty] + for field_name, field_size in self.plm.layouts[ty][1:]: + try: + fvalue = kwargs[field_name] + del kwargs[field_name] + except KeyError: + fvalue = 0 + value = value | (fvalue << idx) + idx += field_size + if kwargs: + raise ValueError + + ws = len(self.data) + yield self.frame.eq(1) + for i in range(idx//ws): + yield self.data.eq(value) + value >>= ws + yield + yield self.frame.eq(0) + yield + + @passive + def receive(self, callback): + previous_frame = 0 + frame_words = [] + while True: + frame = yield self.frame + if frame: + frame_words.append((yield self.data)) + if previous_frame and not frame: + packet_type = self.plm.type_names[frame_words[0] & 0xff] + packet_nwords = layout_len(self.plm.layouts[packet_type]) \ + //len(self.data) + packet, trailer = frame_words[:packet_nwords], \ + frame_words[packet_nwords:] + + n = 0 + packet_int = 0 + for w in packet: + packet_int |= (w << n) + n += len(self.data) + + field_dict = dict() + idx = 0 + for field_name, field_size in self.plm.layouts[packet_type]: + v = (packet_int >> idx) & (2**field_size - 1) + field_dict[field_name] = v + idx += field_size + + callback(packet_type, field_dict, trailer) + + frame_words = [] + previous_frame = frame + yield diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py new file mode 100644 index 000000000..760a7a9ac --- /dev/null +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -0,0 +1,62 @@ +import unittest +from types import SimpleNamespace + +from migen import * + +from artiq.gateware.rtio import cri +from artiq.gateware.test.drtio.packet_interface import PacketInterface +from artiq.gateware.drtio.rt_packet_repeater import RTPacketRepeater + + +def create_dut(nwords): + pt = PacketInterface("s2m", nwords*8) + pr = PacketInterface("m2s", nwords*8) + dut = ClockDomainsRenamer({"rtio": "sys", "rtio_rx": "sys"})( + RTPacketRepeater(SimpleNamespace( + rx_rt_frame=pt.frame, rx_rt_data=pt.data, + tx_rt_frame=pr.frame, tx_rt_data=pr.data))) + return pt, pr, dut + + +class TestRepeater(unittest.TestCase): + def test_output(self): + test_writes = [ + (1, 10, 21, 0x42), + (2, 11, 34, 0x2342), + (3, 12, 83, 0x2345566633), + (4, 13, 25, 0x98da14959a19498ae1), + (5, 14, 75, 0x3998a1883ae14f828ae24958ea2479) + ] + + for nwords in range(1, 8): + pt, pr, dut = create_dut(nwords) + + def send(): + for channel, timestamp, address, data in test_writes: + yield dut.cri.chan_sel.eq(channel) + yield dut.cri.timestamp.eq(timestamp) + yield dut.cri.o_address.eq(address) + yield dut.cri.o_data.eq(data) + yield dut.cri.cmd.eq(cri.commands["write"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + for i in range(30): + yield + for i in range(50): + yield + + short_data_len = pr.plm.field_length("write", "short_data") + + received = [] + def receive(packet_type, field_dict, trailer): + self.assertEqual(packet_type, "write") + self.assertEqual(len(trailer), field_dict["extra_data_cnt"]) + data = field_dict["short_data"] + for n, te in enumerate(trailer): + data |= te << (n*nwords*8 + short_data_len) + received.append((field_dict["channel"], field_dict["timestamp"], + field_dict["address"], data)) + + run_simulation(dut, [send(), pr.receive(receive)]) + self.assertEqual(test_writes, received) diff --git a/artiq/gateware/test/drtio/test_rt_packet_satellite.py b/artiq/gateware/test/drtio/test_rt_packet_satellite.py index 5bbdb44f7..1d934b8df 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_satellite.py +++ b/artiq/gateware/test/drtio/test_rt_packet_satellite.py @@ -3,91 +3,23 @@ from types import SimpleNamespace from migen import * -from artiq.gateware.drtio.rt_serializer import * +from artiq.gateware.test.drtio.packet_interface import PacketInterface from artiq.gateware.drtio.rt_packet_satellite import RTPacketSatellite -class PacketInterface: - def __init__(self, direction, ws): - if direction == "m2s": - self.plm = get_m2s_layouts(ws) - elif direction == "s2m": - self.plm = get_s2m_layouts(ws) - else: - raise ValueError - self.frame = Signal() - self.data = Signal(ws) - - def send(self, ty, **kwargs): - idx = 8 - value = self.plm.types[ty] - for field_name, field_size in self.plm.layouts[ty][1:]: - try: - fvalue = kwargs[field_name] - del kwargs[field_name] - except KeyError: - fvalue = 0 - value = value | (fvalue << idx) - idx += field_size - if kwargs: - raise ValueError - - ws = len(self.data) - yield self.frame.eq(1) - for i in range(idx//ws): - yield self.data.eq(value) - value >>= ws - yield - yield self.frame.eq(0) - yield - - @passive - def receive(self, callback): - previous_frame = 0 - frame_words = [] - while True: - frame = yield self.frame - if frame: - frame_words.append((yield self.data)) - if previous_frame and not frame: - packet_type = self.plm.type_names[frame_words[0] & 0xff] - packet_nwords = layout_len(self.plm.layouts[packet_type]) \ - //len(self.data) - packet, trailer = frame_words[:packet_nwords], \ - frame_words[packet_nwords:] - - n = 0 - packet_int = 0 - for w in packet: - packet_int |= (w << n) - n += len(self.data) - - field_dict = dict() - idx = 0 - for field_name, field_size in self.plm.layouts[packet_type]: - v = (packet_int >> idx) & (2**field_size - 1) - field_dict[field_name] = v - idx += field_size - - callback(packet_type, field_dict, trailer) - - frame_words = [] - previous_frame = frame - yield +def create_dut(nwords): + pt = PacketInterface("m2s", nwords*8) + pr = PacketInterface("s2m", nwords*8) + dut = RTPacketSatellite(SimpleNamespace( + rx_rt_frame=pt.frame, rx_rt_data=pt.data, + tx_rt_frame=pr.frame, tx_rt_data=pr.data)) + return pt, pr, dut class TestSatellite(unittest.TestCase): - def create_dut(self, nwords): - pt = PacketInterface("m2s", nwords*8) - pr = PacketInterface("s2m", nwords*8) - dut = RTPacketSatellite(SimpleNamespace( - rx_rt_frame=pt.frame, rx_rt_data=pt.data, - tx_rt_frame=pr.frame, tx_rt_data=pr.data)) - return pt, pr, dut - def test_echo(self): for nwords in range(1, 8): - pt, pr, dut = self.create_dut(nwords) + pt, pr, dut = create_dut(nwords) completed = False def send(): yield from pt.send("echo_request") @@ -102,7 +34,7 @@ class TestSatellite(unittest.TestCase): def test_set_time(self): for nwords in range(1, 8): - pt, _, dut = self.create_dut(nwords) + pt, _, dut = create_dut(nwords) tx_times = [0x12345678aabbccdd, 0x0102030405060708, 0xaabbccddeeff1122] def send(): From 88b7529d099b8698627265201b091d31c3a27d18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Sep 2018 14:37:23 +0800 Subject: [PATCH 06/92] drtio: share CDC --- artiq/gateware/drtio/rt_packet_master.py | 61 ++---------------------- artiq/gateware/test/drtio/test_cdc.py | 8 ++-- 2 files changed, 9 insertions(+), 60 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 2e07dcbc7..39598aba7 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -3,63 +3,12 @@ from migen import * from migen.genlib.fsm import * from migen.genlib.fifo import AsyncFIFO -from migen.genlib.cdc import PulseSynchronizer from artiq.gateware.rtio.cdc import GrayCodeTransfer, BlindTransfer +from artiq.gateware.drtio.cdc import CrossDomainRequest, CrossDomainNotification from artiq.gateware.drtio.rt_serializer import * -class _CrossDomainRequest(Module): - def __init__(self, domain, - req_stb, req_ack, req_data, - srv_stb, srv_ack, srv_data): - dsync = getattr(self.sync, domain) - - request = PulseSynchronizer("sys", domain) - reply = PulseSynchronizer(domain, "sys") - self.submodules += request, reply - - ongoing = Signal() - self.comb += request.i.eq(~ongoing & req_stb) - self.sync += [ - req_ack.eq(reply.o), - If(req_stb, ongoing.eq(1)), - If(req_ack, ongoing.eq(0)) - ] - if req_data is not None: - req_data_r = Signal.like(req_data) - req_data_r.attr.add("no_retiming") - self.sync += If(req_stb, req_data_r.eq(req_data)) - dsync += [ - If(request.o, srv_stb.eq(1)), - If(srv_ack, srv_stb.eq(0)) - ] - if req_data is not None: - dsync += If(request.o, srv_data.eq(req_data_r)) - self.comb += reply.i.eq(srv_stb & srv_ack) - - -class _CrossDomainNotification(Module): - def __init__(self, domain, - emi_stb, emi_data, - rec_stb, rec_ack, rec_data): - emi_data_r = Signal(len(emi_data)) - emi_data_r.attr.add("no_retiming") - dsync = getattr(self.sync, domain) - dsync += If(emi_stb, emi_data_r.eq(emi_data)) - - ps = PulseSynchronizer(domain, "sys") - self.submodules += ps - self.comb += ps.i.eq(emi_stb) - self.sync += [ - If(rec_ack, rec_stb.eq(0)), - If(ps.o, - rec_data.eq(emi_data_r), - rec_stb.eq(1) - ) - ] - - class RTPacketMaster(Module): def __init__(self, link_layer, sr_fifo_depth=4): # all interface signals in sys domain unless otherwise specified @@ -206,19 +155,19 @@ class RTPacketMaster(Module): # CDC buffer_space_not = Signal() buffer_space = Signal(16) - self.submodules += _CrossDomainNotification("rtio_rx", + self.submodules += CrossDomainNotification("rtio_rx", "sys", buffer_space_not, buffer_space, self.buffer_space_not, self.buffer_space_not_ack, self.buffer_space) set_time_stb = Signal() set_time_ack = Signal() - self.submodules += _CrossDomainRequest("rtio", + self.submodules += CrossDomainRequest("rtio", self.set_time_stb, self.set_time_ack, None, set_time_stb, set_time_ack, None) echo_stb = Signal() echo_ack = Signal() - self.submodules += _CrossDomainRequest("rtio", + self.submodules += CrossDomainRequest("rtio", self.echo_stb, self.echo_ack, None, echo_stb, echo_ack, None) @@ -227,7 +176,7 @@ class RTPacketMaster(Module): read_is_overflow = Signal() read_data = Signal(32) read_timestamp = Signal(64) - self.submodules += _CrossDomainNotification("rtio_rx", + self.submodules += CrossDomainNotification("rtio_rx", "sys", read_not, Cat(read_no_event, read_is_overflow, read_data, read_timestamp), diff --git a/artiq/gateware/test/drtio/test_cdc.py b/artiq/gateware/test/drtio/test_cdc.py index 689df6221..5598fd68b 100644 --- a/artiq/gateware/test/drtio/test_cdc.py +++ b/artiq/gateware/test/drtio/test_cdc.py @@ -3,8 +3,8 @@ import random from migen import * -from artiq.gateware.drtio.rt_packet_master import (_CrossDomainRequest, - _CrossDomainNotification) +from artiq.gateware.drtio.cdc import CrossDomainRequest, CrossDomainNotification + class TestCDC(unittest.TestCase): def test_cross_domain_request(self): @@ -43,7 +43,7 @@ class TestCDC(unittest.TestCase): yield srv_ack.eq(0) yield - dut = _CrossDomainRequest("srv", + dut = CrossDomainRequest("srv", req_stb, req_ack, req_data, srv_stb, srv_ack, srv_data) run_simulation(dut, @@ -85,7 +85,7 @@ class TestCDC(unittest.TestCase): for j in range(prng.randrange(0, 3)): yield - dut = _CrossDomainNotification("emi", + dut = CrossDomainNotification("emi", "sys", emi_stb, emi_data, rec_stb, rec_ack, rec_data) run_simulation(dut, From 6768dbab6c428e18f7733240c8dfc02b4a504a64 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Sep 2018 14:38:37 +0800 Subject: [PATCH 07/92] drtio: add buffer space support to rt_packet_repeater --- artiq/gateware/drtio/rt_packet_master.py | 4 +- artiq/gateware/drtio/rt_packet_repeater.py | 80 ++++++++++++++++++- artiq/gateware/drtio/rt_serializer.py | 2 +- .../test/drtio/test_rt_packet_repeater.py | 36 +++++++++ 4 files changed, 118 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 39598aba7..b38ce0abf 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -15,7 +15,7 @@ class RTPacketMaster(Module): # standard request interface # - # notwrite=1 address=0 buffer space request + # notwrite=1 address=0 buffer space request # notwrite=1 address=1 read request # # optimized for write throughput @@ -252,7 +252,7 @@ class RTPacketMaster(Module): ) ) tx_fsm.act("BUFFER_SPACE", - tx_dp.send("buffer_space_request"), + tx_dp.send("buffer_space_request", destination=sr_channel), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 0eb9edfb3..e570b39d6 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -1,14 +1,25 @@ from migen import * from migen.genlib.fsm import * +from migen.genlib.misc import WaitTimer + from artiq.gateware.rtio import cri +from artiq.gateware.drtio.cdc import CrossDomainNotification from artiq.gateware.drtio.rt_serializer import * class RTPacketRepeater(Module): def __init__(self, link_layer): + # CRI target interface in rtio domain self.cri = cri.Interface() + # in rtio_rx domain + self.err_unknown_packet_type = Signal() + self.err_packet_truncated = Signal() + + # in rtio domain + self.buffer_space_timeout = Signal() + # RX/TX datapath assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) assert len(link_layer.tx_rt_data) % 8 == 0 @@ -61,12 +72,30 @@ class RTPacketRepeater(Module): extra_data_counter.eq(1) ) + # Buffer space + buffer_space_destination = Signal(8) + self.sync.rtio += If(self.cri.cmd == cri.commands["get_buffer_space"], + buffer_space_destination.eq(self.cri.chan_sel[16:])) + + rx_buffer_space_not = Signal() + rx_buffer_space = Signal(16) + buffer_space_not = Signal() + buffer_space_not_ack = Signal() + self.submodules += CrossDomainNotification("rtio_rx", "rtio", + rx_buffer_space_not, rx_buffer_space, + buffer_space_not, buffer_space_not_ack, + self.cri.o_buffer_space) + + timeout_counter = WaitTimer(8191) + self.submodules += timeout_counter + # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm tx_fsm.act("IDLE", - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")) + If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) ) tx_fsm.act("WRITE", tx_dp.send("write", @@ -90,3 +119,52 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("BUFFER_SPACE", + tx_dp.send("buffer_space_request", destination=buffer_space_destination), + If(tx_dp.packet_last, + buffer_space_not_ack.eq(1), + NextState("WAIT_BUFFER_SPACE") + ) + ) + tx_fsm.act("WAIT_BUFFER_SPACE", + timeout_counter.wait.eq(1), + If(timeout_counter.done, + self.buffer_space_timeout.eq(1), + NextState("IDLE") + ).Else( + If(buffer_space_not, + self.cri.o_buffer_space_valid.eq(1), + NextState("IDLE") + ), + ) + ) + + # RX FSM + rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) + self.submodules += rx_fsm + + ongoing_packet_next = Signal() + ongoing_packet = Signal() + self.sync.rtio_rx += ongoing_packet.eq(ongoing_packet_next) + + rx_fsm.act("INPUT", + If(rx_dp.frame_r, + rx_dp.packet_buffer_load.eq(1), + If(rx_dp.packet_last, + Case(rx_dp.packet_type, { + rx_plm.types["buffer_space_reply"]: NextState("BUFFER_SPACE"), + "default": self.err_unknown_packet_type.eq(1) + }) + ).Else( + ongoing_packet_next.eq(1) + ) + ), + If(~rx_dp.frame_r & ongoing_packet, + self.err_packet_truncated.eq(1) + ) + ) + rx_fsm.act("BUFFER_SPACE", + rx_buffer_space_not.eq(1), + rx_buffer_space.eq(rx_dp.packet_as["buffer_space_reply"].space), + NextState("INPUT") + ) diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 00a46299f..069680d9e 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -53,7 +53,7 @@ def get_m2s_layouts(alignment): ("address", 16), ("extra_data_cnt", 8), ("short_data", short_data_len)) - plm.add_type("buffer_space_request") + plm.add_type("buffer_space_request", ("destination", 8)) plm.add_type("read_request", ("channel", 16), ("timeout", 64)) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 760a7a9ac..b62fe3329 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -60,3 +60,39 @@ class TestRepeater(unittest.TestCase): run_simulation(dut, [send(), pr.receive(receive)]) self.assertEqual(test_writes, received) + + def test_buffer_space(self): + for nwords in range(1, 8): + pt, pr, dut = create_dut(nwords) + + def send_requests(): + for i in range(10): + yield dut.cri.chan_sel.eq(i << 16) + yield dut.cri.cmd.eq(cri.commands["get_buffer_space"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + while not (yield dut.cri.o_buffer_space_valid): + yield + buffer_space = yield dut.cri.o_buffer_space + self.assertEqual(buffer_space, 2*i) + + current_request = None + + @passive + def send_replies(): + nonlocal current_request + while True: + while current_request is None: + yield + yield from pt.send("buffer_space_reply", space=2*current_request) + current_request = None + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(packet_type, "buffer_space_request") + self.assertEqual(trailer, []) + self.assertEqual(current_request, None) + current_request = field_dict["destination"] + + run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) From 0fe2a6801eebb65fa3debcf4af6e385af6d0b8f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Sep 2018 15:50:23 +0800 Subject: [PATCH 08/92] drtio: forward destination with channel --- artiq/gateware/drtio/rt_controller_master.py | 3 +-- artiq/gateware/drtio/rt_packet_master.py | 20 +++++++++---------- artiq/gateware/drtio/rt_packet_repeater.py | 6 +++--- artiq/gateware/drtio/rt_packet_satellite.py | 4 ++-- artiq/gateware/drtio/rt_serializer.py | 4 ++-- artiq/gateware/rtio/cri.py | 3 ++- .../test/drtio/test_rt_packet_repeater.py | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index c3ef0214b..ec1fd5182 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -93,11 +93,10 @@ class RTController(Module): ] # common packet fields - chan_sel = self.cri.chan_sel[:16] rt_packet_buffer_request = Signal() rt_packet_read_request = Signal() self.comb += [ - rt_packet.sr_channel.eq(chan_sel), + rt_packet.sr_chan_sel.eq(self.cri.chan_sel), rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_data.eq(self.cri.o_data), rt_packet.sr_timestamp.eq(self.cri.timestamp), diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index b38ce0abf..45ffe1278 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -26,7 +26,7 @@ class RTPacketMaster(Module): self.sr_ack = Signal() self.sr_notwrite = Signal() self.sr_timestamp = Signal(64) - self.sr_channel = Signal(16) + self.sr_chan_sel = Signal(24) self.sr_address = Signal(16) self.sr_data = Signal(512) @@ -85,19 +85,19 @@ class RTPacketMaster(Module): # Write FIFO and extra data count sr_fifo = ClockDomainsRenamer({"write": "sys_with_rst", "read": "rtio_with_rst"})( - AsyncFIFO(1+64+16+16+512, sr_fifo_depth)) + AsyncFIFO(1+64+24+16+512, sr_fifo_depth)) self.submodules += sr_fifo sr_notwrite_d = Signal() sr_timestamp_d = Signal(64) - sr_channel_d = Signal(16) + sr_chan_sel_d = Signal(24) sr_address_d = Signal(16) sr_data_d = Signal(512) self.comb += [ sr_fifo.we.eq(self.sr_stb), self.sr_ack.eq(sr_fifo.writable), - sr_fifo.din.eq(Cat(self.sr_notwrite, self.sr_timestamp, self.sr_channel, + sr_fifo.din.eq(Cat(self.sr_notwrite, self.sr_timestamp, self.sr_chan_sel, self.sr_address, self.sr_data)), - Cat(sr_notwrite_d, sr_timestamp_d, sr_channel_d, + Cat(sr_notwrite_d, sr_timestamp_d, sr_chan_sel_d, sr_address_d, sr_data_d).eq(sr_fifo.dout) ] @@ -114,7 +114,7 @@ class RTPacketMaster(Module): sr_notwrite = Signal() sr_timestamp = Signal(64) - sr_channel = Signal(16) + sr_chan_sel = Signal(24) sr_address = Signal(16) sr_extra_data_cnt = Signal(8) sr_data = Signal(512) @@ -122,7 +122,7 @@ class RTPacketMaster(Module): self.sync.rtio += If(sr_fifo.re, sr_notwrite.eq(sr_notwrite_d), sr_timestamp.eq(sr_timestamp_d), - sr_channel.eq(sr_channel_d), + sr_chan_sel.eq(sr_chan_sel_d), sr_address.eq(sr_address_d), sr_data.eq(sr_data_d)) @@ -230,7 +230,7 @@ class RTPacketMaster(Module): tx_fsm.act("WRITE", tx_dp.send("write", timestamp=sr_timestamp, - channel=sr_channel, + chan_sel=sr_chan_sel, address=sr_address, extra_data_cnt=sr_extra_data_cnt, short_data=sr_data[:short_data_len]), @@ -252,14 +252,14 @@ class RTPacketMaster(Module): ) ) tx_fsm.act("BUFFER_SPACE", - tx_dp.send("buffer_space_request", destination=sr_channel), + tx_dp.send("buffer_space_request", destination=sr_chan_sel[16:]), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") ) ) tx_fsm.act("READ", - tx_dp.send("read_request", channel=sr_channel, timeout=sr_timestamp), + tx_dp.send("read_request", chan_sel=sr_chan_sel, timeout=sr_timestamp), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index e570b39d6..d6f27ecc9 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -35,12 +35,12 @@ class RTPacketRepeater(Module): # Write buffer and extra data count wb_timestamp = Signal(64) - wb_channel = Signal(16) + wb_chan_sel = Signal(24) wb_address = Signal(16) wb_data = Signal(512) self.sync.rtio += If(self.cri.cmd == cri.commands["write"], wb_timestamp.eq(self.cri.timestamp), - wb_channel.eq(self.cri.chan_sel), + wb_chan_sel.eq(self.cri.chan_sel), wb_address.eq(self.cri.o_address), wb_data.eq(self.cri.o_data)) @@ -100,7 +100,7 @@ class RTPacketRepeater(Module): tx_fsm.act("WRITE", tx_dp.send("write", timestamp=wb_timestamp, - channel=wb_channel, + chan_sel=wb_chan_sel, address=wb_address, extra_data_cnt=wb_extra_data_cnt, short_data=wb_data[:short_data_len]), diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index c5266e33b..4760e11ac 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -83,12 +83,12 @@ class RTPacketSatellite(Module): rx_dp.packet_as["set_time"].timestamp), If(load_read_request | read_request_pending, self.cri.chan_sel.eq( - rx_dp.packet_as["read_request"].channel), + rx_dp.packet_as["read_request"].chan_sel), self.cri.timestamp.eq( rx_dp.packet_as["read_request"].timeout) ).Else( self.cri.chan_sel.eq( - rx_dp.packet_as["write"].channel), + rx_dp.packet_as["write"].chan_sel), self.cri.timestamp.eq( rx_dp.packet_as["write"].timestamp) ), diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 069680d9e..4b62dbfb6 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -49,13 +49,13 @@ def get_m2s_layouts(alignment): plm.add_type("set_time", ("timestamp", 64)) plm.add_type("write", ("timestamp", 64), - ("channel", 16), + ("chan_sel", 24), ("address", 16), ("extra_data_cnt", 8), ("short_data", short_data_len)) plm.add_type("buffer_space_request", ("destination", 8)) - plm.add_type("read_request", ("channel", 16), ("timeout", 64)) + plm.add_type("read_request", ("chan_sel", 24), ("timeout", 64)) return plm diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 4a889bc27..af3511928 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -25,7 +25,8 @@ commands = { layout = [ ("cmd", 2, DIR_M_TO_S), - # 8 MSBs of chan_sel are used to select core + # 8 MSBs of chan_sel = routing destination + # 16 LSBs of chan_sel = channel within the destination ("chan_sel", 24, DIR_M_TO_S), ("timestamp", 64, DIR_M_TO_S), diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index b62fe3329..bdc753853 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -55,7 +55,7 @@ class TestRepeater(unittest.TestCase): data = field_dict["short_data"] for n, te in enumerate(trailer): data |= te << (n*nwords*8 + short_data_len) - received.append((field_dict["channel"], field_dict["timestamp"], + received.append((field_dict["chan_sel"], field_dict["timestamp"], field_dict["address"], data)) run_simulation(dut, [send(), pr.receive(receive)]) From f3fe818049d7f02d2034bf016924f62248772500 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Sep 2018 09:48:12 +0800 Subject: [PATCH 09/92] rtio: refactor TSC to allow sharing between cores --- artiq/gateware/drtio/core.py | 40 +++++++++---------- artiq/gateware/drtio/rt_controller_master.py | 31 +++----------- artiq/gateware/drtio/rt_errors_satellite.py | 4 +- artiq/gateware/rtio/__init__.py | 1 + artiq/gateware/rtio/core.py | 26 +++--------- artiq/gateware/rtio/cri.py | 11 ++--- artiq/gateware/rtio/input_collector.py | 13 +++--- artiq/gateware/test/drtio/test_full_stack.py | 16 ++++---- artiq/gateware/test/rtio/test_dma.py | 3 +- .../test/rtio/test_input_collector.py | 5 +-- 10 files changed, 56 insertions(+), 94 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 209a3b58d..47a56ce0c 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -5,7 +5,7 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * -from artiq.gateware.rtio import cri +from artiq.gateware.rtio import cri, rtlink from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, @@ -47,32 +47,33 @@ async_errors_layout = [ class SyncRTIO(Module): - def __init__(self, channels, fine_ts_width=3, lane_count=8, fifo_depth=128): + def __init__(self, tsc, channels, lane_count=8, fifo_depth=128): self.cri = cri.Interface() self.async_errors = Record(async_errors_layout) - self.coarse_ts = Signal(64 - fine_ts_width) - self.comb += self.cri.counter.eq(self.coarse_ts << fine_ts_width) + 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 self.submodules.outputs = ClockDomainsRenamer("rio")( - SED(channels, fine_ts_width, "sync", + SED(channels, tsc.glbl_fine_ts_width, "sync", lane_count=lane_count, fifo_depth=fifo_depth, enable_spread=False, report_buffer_space=True, interface=self.cri)) - self.comb += self.outputs.coarse_timestamp.eq(self.coarse_ts) - self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(self.coarse_ts + 16) + self.comb += self.outputs.coarse_timestamp.eq(tsc.coarse_ts) + self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) self.submodules.inputs = ClockDomainsRenamer("rio")( - InputCollector(channels, fine_ts_width, "sync", - interface=self.cri)) - self.comb += self.inputs.coarse_timestamp.eq(self.coarse_ts) + InputCollector(tsc, channels, "sync", interface=self.cri)) for attr, _ in async_errors_layout: self.comb += getattr(self.async_errors, attr).eq(getattr(self.outputs, attr)) class DRTIOSatellite(Module): - def __init__(self, chanif, rx_synchronizer=None, fine_ts_width=3): + def __init__(self, tsc, chanif, rx_synchronizer=None): self.reset = CSRStorage(reset=1) self.reset_phy = CSRStorage(reset=1) self.tsc_loaded = CSR() @@ -127,13 +128,10 @@ class DRTIOSatellite(Module): rt_packet_satellite.RTPacketSatellite(link_layer_sync, interface=self.cri)) self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) - self.coarse_ts = Signal(64 - fine_ts_width) - self.sync.rtio += \ - If(self.rt_packet.tsc_load, - self.coarse_ts.eq(self.rt_packet.tsc_load_value) - ).Else( - self.coarse_ts.eq(self.coarse_ts + 1) - ) + self.comb += [ + tsc.load.eq(self.rt_packet.tsc_load), + tsc.load_value.eq(self.rt_packet.tsc_load_value) + ] ps_tsc_load = PulseSynchronizer("rtio", "sys") self.submodules += ps_tsc_load @@ -144,7 +142,7 @@ class DRTIOSatellite(Module): ] self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, self.cri, self.async_errors) + self.rt_packet, tsc, self.cri, self.async_errors) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -156,7 +154,7 @@ class DRTIOSatellite(Module): class DRTIOMaster(Module): - def __init__(self, chanif, fine_ts_width=3): + def __init__(self, tsc, chanif): self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) @@ -164,7 +162,7 @@ class DRTIOMaster(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( - self.rt_packet, fine_ts_width) + tsc, self.rt_packet) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) self.submodules.aux_controller = aux_controller.AuxController( diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index ec1fd5182..fa2efd457 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -7,7 +7,6 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * -from artiq.gateware.rtio.cdc import GrayCodeTransfer from artiq.gateware.rtio import cri @@ -26,26 +25,8 @@ class _CSRs(AutoCSR): self.o_wait = CSRStatus() -class RTIOCounter(Module): - def __init__(self, width): - self.width = width - # Timestamp counter in RTIO domain - self.value_rtio = Signal(width) - # Timestamp counter resynchronized to sys domain - # Lags behind value_rtio, monotonic and glitch-free - self.value_sys = Signal(width) - - # # # - - # note: counter is in rtio domain and never affected by the reset CSRs - self.sync.rtio += self.value_rtio.eq(self.value_rtio + 1) - gt = GrayCodeTransfer(width) - self.submodules += gt - self.comb += gt.i.eq(self.value_rtio), self.value_sys.eq(gt.o) - - class RTController(Module): - def __init__(self, rt_packet, fine_ts_width): + def __init__(self, tsc, rt_packet): self.csrs = _CSRs() self.cri = cri.Interface() @@ -80,11 +61,9 @@ class RTController(Module): self.comb += self.csrs.protocol_error.w.eq( Cat(err_unknown_packet_type, err_packet_truncated, err_buffer_space_timeout)) - # master RTIO counter and counter synchronization - self.submodules.counter = RTIOCounter(64-fine_ts_width) + # TSC synchronization self.comb += [ - self.cri.counter.eq(self.counter.value_sys << fine_ts_width), - rt_packet.tsc_value.eq(self.counter.value_rtio), + rt_packet.tsc_value.eq(tsc.coarse_ts), self.csrs.set_time.w.eq(rt_packet.set_time_stb) ] self.sync += [ @@ -130,8 +109,8 @@ class RTController(Module): self.submodules += timeout_counter cond_underflow = Signal() - self.comb += cond_underflow.eq((self.cri.timestamp[fine_ts_width:] - - self.csrs.underflow_margin.storage[fine_ts_width:]) < self.counter.value_sys) + self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] + - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) buffer_space = Signal(16) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 50f0b53af..764365730 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,7 +7,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, cri, async_errors): + def __init__(self, rt_packet, tsc, cri, async_errors): self.protocol_error = CSR(4) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) @@ -60,7 +60,7 @@ class RTErrorsSatellite(Module, AutoCSR): overflow.eq(cri.o_status[0]), underflow_error_cri.eq(Cat(cri.chan_sel[:16], cri.timestamp, - cri.counter)), + tsc.full_ts_cri)), Cat(self.underflow_channel.status, self.underflow_timestamp_event.status, self.underflow_timestamp_counter.status).eq(underflow_error_csr) diff --git a/artiq/gateware/rtio/__init__.py b/artiq/gateware/rtio/__init__.py index 718f2bc7f..a144f593c 100644 --- a/artiq/gateware/rtio/__init__.py +++ b/artiq/gateware/rtio/__init__.py @@ -1,3 +1,4 @@ +from artiq.gateware.rtio.tsc import TSC from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared from artiq.gateware.rtio.channel import Channel, LogChannel from artiq.gateware.rtio.core import Core diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index edab0bf08..b76308f62 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -14,8 +14,7 @@ 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): + def __init__(self, tsc, channels, lane_count=8, fifo_depth=128): self.cri = cri.Interface() self.reset = CSR() self.reset_phy = CSR() @@ -61,36 +60,23 @@ class Core(Module, AutoCSR): 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 + 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, glbl_fine_ts_width, "async", + outputs = SED(channels, tsc.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) + self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts) + self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts_sys + 16) - inputs = InputCollector(channels, glbl_fine_ts_width, "async", + inputs = InputCollector(tsc, channels, "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) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index af3511928..d78c5da36 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -49,11 +49,6 @@ layout = [ # <3:link error> # <0> and <1> are mutually exclusive. <1> has higher priority. ("i_status", 4, DIR_S_TO_M), - - # value of the timestamp counter transferred into the CRI clock domain. - # monotonic, may lag behind the counter in the IO clock domain, but - # not be ahead of it. - ("counter", 64, DIR_S_TO_M) ] @@ -63,8 +58,10 @@ class Interface(Record): class KernelInitiator(Module, AutoCSR): - def __init__(self, cri=None): + def __init__(self, tsc, cri=None): self.chan_sel = CSRStorage(24) + # monotonic, may lag behind the counter in the IO clock domain, but + # not be ahead of it. self.timestamp = CSRStorage(64) # Writing timestamp clears o_data. This implements automatic @@ -109,7 +106,7 @@ class KernelInitiator(Module, AutoCSR): self.o_data.dat_w.eq(0), self.o_data.we.eq(self.timestamp.re), ] - self.sync += If(self.counter_update.re, self.counter.status.eq(self.cri.counter)) + self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) class CRIDecoder(Module): diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index cff5aeaf8..ce9bcbc20 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -24,11 +24,10 @@ def get_channel_layout(coarse_ts_width, interface): class InputCollector(Module): - def __init__(self, channels, glbl_fine_ts_width, mode, quash_channels=[], interface=None): + def __init__(self, tsc, channels, mode, quash_channels=[], interface=None): if interface is None: interface = cri.Interface() self.cri = interface - self.coarse_timestamp = Signal(64 - glbl_fine_ts_width) # # # @@ -55,7 +54,7 @@ class InputCollector(Module): continue # FIFO - layout = get_channel_layout(len(self.coarse_timestamp), iif) + layout = get_channel_layout(len(tsc.coarse_ts), iif) fifo = fifo_factory(layout_len(layout), channel.ififo_depth) self.submodules += fifo fifo_in = Record(layout) @@ -67,10 +66,10 @@ class InputCollector(Module): # FIFO write if iif.delay: - counter_rtio = Signal.like(self.coarse_timestamp, reset_less=True) - sync_io += counter_rtio.eq(self.coarse_timestamp - (iif.delay + 1)) + counter_rtio = Signal.like(tsc.coarse_ts, reset_less=True) + sync_io += counter_rtio.eq(tsc.coarse_ts - (iif.delay + 1)) else: - counter_rtio = self.coarse_timestamp + counter_rtio = tsc.coarse_ts if hasattr(fifo_in, "data"): self.comb += fifo_in.data.eq(iif.data) if hasattr(fifo_in, "timestamp"): @@ -130,7 +129,7 @@ class InputCollector(Module): self.cri.i_data.eq(Array(i_datas)[sel]), self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), ), - If((self.cri.counter >= input_timeout) | (i_status_raw != 0), + If((tsc.full_ts_cri >= input_timeout) | (i_status_raw != 0), If(input_pending, i_ack.eq(1)), input_pending.eq(0) ), diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 4abfe9e3c..eafb438c1 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -52,9 +52,11 @@ class DUT(Module): self.ttl1 = Signal() self.transceivers = DummyTransceiverPair(nwords) - self.submodules.master = DRTIOMaster(self.transceivers.alice, - fine_ts_width=0) - self.submodules.master_ki = rtio.KernelInitiator(self.master.cri) + self.submodules.tsc_master = rtio.TSC("async") + self.submodules.master = DRTIOMaster(self.tsc_master, + self.transceivers.alice) + self.submodules.master_ki = rtio.KernelInitiator(self.tsc_master, + self.master.cri) self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() @@ -66,16 +68,16 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1), rtio.Channel.from_phy(self.phy2), ] + self.submodules.tsc_satellite = rtio.TSC("sync") self.submodules.satellite = DRTIOSatellite( - self.transceivers.bob, rx_synchronizer, fine_ts_width=0) + self.tsc_satellite, self.transceivers.bob, rx_synchronizer) self.satellite.reset.storage.reset = 0 self.satellite.reset.storage_full.reset = 0 self.satellite.reset_phy.storage.reset = 0 self.satellite.reset_phy.storage_full.reset = 0 self.submodules.satellite_rtio = SyncRTIO( - rtio_channels, fine_ts_width=0, lane_count=4, fifo_depth=8) + self.tsc_satellite, rtio_channels, lane_count=4, fifo_depth=8) self.comb += [ - self.satellite_rtio.coarse_ts.eq(self.satellite.coarse_ts), self.satellite.cri.connect(self.satellite_rtio.cri), self.satellite.async_errors.eq(self.satellite_rtio.async_errors), ] @@ -106,7 +108,7 @@ class OutputsTestbench: def sync(self): t = self.now + 15 - while (yield self.dut.master.cri.counter) < t: + while (yield self.dut.tsc_master.full_ts_cri) < t: yield def write(self, channel, data): diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 536575b32..ee546e2da 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -127,7 +127,8 @@ class FullStackTB(Module): self.submodules.memory = wishbone.SRAM( 256, init=sequence, bus=bus) self.submodules.dut = dma.DMA(bus) - self.submodules.rtio = rtio.Core(rtio_channels) + self.submodules.tsc = rtio.TSC("async") + self.submodules.rtio = rtio.Core(self.tsc, rtio_channels) self.comb += self.dut.cri.connect(self.rtio.cri) diff --git a/artiq/gateware/test/rtio/test_input_collector.py b/artiq/gateware/test/rtio/test_input_collector.py index c67f2aa53..0c682b28c 100644 --- a/artiq/gateware/test/rtio/test_input_collector.py +++ b/artiq/gateware/test/rtio/test_input_collector.py @@ -38,9 +38,8 @@ class DUT(Module): rtio.Channel.from_phy(self.phy0, ififo_depth=4), rtio.Channel.from_phy(self.phy1, ififo_depth=4) ] - self.submodules.input_collector = InputCollector(rtio_channels, 0, "sync") - self.sync += self.input_collector.coarse_timestamp.eq(self.input_collector.coarse_timestamp + 1) - self.comb += self.input_collector.cri.counter.eq(self.input_collector.coarse_timestamp) + self.submodules.tsc = ClockDomainsRenamer({"rtio": "sys"})(rtio.TSC("sync")) + self.submodules.input_collector = InputCollector(self.tsc, rtio_channels, "sync") @property def cri(self): From 00fabee1ca7ccdfa6cf3b3877bc4e410629599ad Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Sep 2018 09:57:04 +0800 Subject: [PATCH 10/92] drtio: fix rt_packet_repeater timeout --- artiq/gateware/drtio/rt_packet_repeater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index d6f27ecc9..9f5e513f9 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -86,7 +86,7 @@ class RTPacketRepeater(Module): buffer_space_not, buffer_space_not_ack, self.cri.o_buffer_space) - timeout_counter = WaitTimer(8191) + timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter # TX FSM From 778f1de121e2194037f4647943902fff9d473bb7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Sep 2018 18:26:13 +0800 Subject: [PATCH 11/92] drtio: add TSC sync and missed command detection to rt_packet_repeater --- artiq/gateware/drtio/rt_packet_repeater.py | 34 +++++++++++++++++-- .../test/drtio/test_rt_packet_repeater.py | 26 ++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 9f5e513f9..081d444a3 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -18,8 +18,16 @@ class RTPacketRepeater(Module): self.err_packet_truncated = Signal() # in rtio domain + self.command_missed = Signal() self.buffer_space_timeout = Signal() + # set_time interface, in rtio domain + self.set_time_stb = Signal() + self.set_time_ack = Signal() + self.tsc_value = Signal(64) + + # # # + # RX/TX datapath assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) assert len(link_layer.tx_rt_data) % 8 == 0 @@ -33,6 +41,11 @@ class RTPacketRepeater(Module): link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm)) self.submodules += rx_dp + # TSC sync + tsc_value = Signal(64) + tsc_value_load = Signal() + self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) + # Write buffer and extra data count wb_timestamp = Signal(64) wb_chan_sel = Signal(24) @@ -89,13 +102,30 @@ class RTPacketRepeater(Module): timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter + # Missed commands + cri_ready = Signal() + self.sync.rtio += self.command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm tx_fsm.act("IDLE", - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + If(self.set_time_stb, + tsc_value_load.eq(1), + NextState("SET_TIME") + ).Else( + cri_ready.eq(1), + If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + ) + ) + tx_fsm.act("SET_TIME", + tx_dp.send("set_time", timestamp=tsc_value), + If(tx_dp.packet_last, + self.set_time_ack.eq(1), + NextState("IDLE") + ) ) tx_fsm.act("WRITE", tx_dp.send("write", diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index bdc753853..c778d1724 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -19,6 +19,32 @@ def create_dut(nwords): class TestRepeater(unittest.TestCase): + def test_set_time(self): + nwords = 2 + pt, pr, dut = create_dut(nwords) + + def send(): + yield dut.tsc_value.eq(0x12345678) + yield dut.set_time_stb.eq(1) + while not (yield dut.set_time_ack): + yield + yield dut.set_time_stb.eq(0) + yield + for _ in range(30): + yield + + received = False + def receive(packet_type, field_dict, trailer): + nonlocal received + self.assertEqual(packet_type, "set_time") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["timestamp"], 0x12345678) + self.assertEqual(received, False) + received = True + + run_simulation(dut, [send(), pr.receive(receive)]) + self.assertEqual(received, True) + def test_output(self): test_writes = [ (1, 10, 21, 0x42), From 15b16695c673426e334777e7d794794862ab914a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 4 Sep 2018 19:04:27 +0800 Subject: [PATCH 12/92] frontend: add artiq_route --- artiq/frontend/artiq_route.py | 83 +++++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 84 insertions(+) create mode 100755 artiq/frontend/artiq_route.py diff --git a/artiq/frontend/artiq_route.py b/artiq/frontend/artiq_route.py new file mode 100755 index 000000000..c818237ce --- /dev/null +++ b/artiq/frontend/artiq_route.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +import argparse + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ DRTIO routing table " + "manipulation tool") + + parser.add_argument("file", metavar="FILE", type=str, + help="target file") + + action = parser.add_subparsers(dest="action") + action.required = True + + action.add_parser("init", help="create a new empty routing table") + + action.add_parser("show", help="show contents of routing table") + + a_set = action.add_parser("set", help="set routing table entry") + a_set.add_argument("destination", metavar="DESTINATION", type=int, + help="destination to operate on") + a_set.add_argument("hop", metavar="HOP", type=int, nargs="*", + help="hop(s) to the destination") + + return parser + + +ENTRY_COUNT = 256 +MAX_HOPS = 32 + + +def init(filename): + with open(filename, "wb") as f: + f.write(b"\xff"*(ENTRY_COUNT*MAX_HOPS)) + + +def show_routes(filename): + routes = [] + with open(filename, "rb") as f: + for i in range(ENTRY_COUNT): + hops = [int.from_bytes(f.read(1), "big") for j in range(MAX_HOPS)] + routes.append(hops) + + for destination, route in enumerate(routes): + if route[0] != 0xff: + fmt = "{:3d}:".format(destination) + for hop in route: + if hop == 0xff: + break + fmt += " {:3d}".format(hop) + print(fmt) + + +def set_route(filename, destination, hops): + with open(filename, "r+b") as f: + if destination >= ENTRY_COUNT: + raise ValueError("destination must be less than {}".format(ENTRY_COUNT)) + f.seek(destination*MAX_HOPS) + + if len(hops) + 1 >= MAX_HOPS: + raise ValueError("too many hops") + for hop in hops: + if hop >= 0xff: + raise ValueError("all hops must be less than 255") + + hops = hops + [0xff]*(MAX_HOPS-len(hops)) + f.write(bytes(hops)) + + +def main(): + args = get_argparser().parse_args() + if args.action == "init": + init(args.file) + elif args.action == "show": + show_routes(args.file) + elif args.action == "set": + set_route(args.file, args.destination, args.hop) + else: + raise ValueError + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index a85f23ae5..b4c25b027 100755 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ console_scripts = [ "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", "artiq_session = artiq.frontend.artiq_session:main", + "artiq_route = artiq.frontend.artiq_route:main", "artiq_rpctool = artiq.frontend.artiq_rpctool:main", "artiq_run = artiq.frontend.artiq_run:main", "artiq_flash = artiq.frontend.artiq_flash:main", From 4e4398afa6434a038a598a7a60be9d945bbf9118 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:06:20 +0800 Subject: [PATCH 13/92] analyzer: adapt to TSC changes --- artiq/gateware/rtio/analyzer.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/rtio/analyzer.py b/artiq/gateware/rtio/analyzer.py index f958ca8d6..144c62701 100644 --- a/artiq/gateware/rtio/analyzer.py +++ b/artiq/gateware/rtio/analyzer.py @@ -43,7 +43,7 @@ assert layout_len(stopped_layout) == message_len class MessageEncoder(Module, AutoCSR): - def __init__(self, cri, enable): + def __init__(self, tsc, cri, enable): self.source = stream.Endpoint([("data", message_len)]) self.overflow = CSRStatus() @@ -67,7 +67,7 @@ class MessageEncoder(Module, AutoCSR): self.comb += [ input_output.channel.eq(cri.chan_sel), input_output.address_padding.eq(cri.o_address), - input_output.rtio_counter.eq(cri.counter), + input_output.rtio_counter.eq(tsc.full_ts_cri), If(cri.cmd == cri_commands["write"], input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(cri.timestamp), @@ -85,7 +85,7 @@ class MessageEncoder(Module, AutoCSR): self.comb += [ exception.message_type.eq(MessageType.exception.value), exception.channel.eq(cri.chan_sel), - exception.rtio_counter.eq(cri.counter), + exception.rtio_counter.eq(tsc.full_ts_cri), ] just_written = Signal() self.sync += just_written.eq(cri.cmd == cri_commands["write"]) @@ -103,7 +103,7 @@ class MessageEncoder(Module, AutoCSR): stopped = Record(stopped_layout) self.comb += [ stopped.message_type.eq(MessageType.stopped.value), - stopped.rtio_counter.eq(cri.counter), + stopped.rtio_counter.eq(tsc.full_ts_cri), ] enable_r = Signal() @@ -193,13 +193,13 @@ class DMAWriter(Module, AutoCSR): class Analyzer(Module, AutoCSR): - def __init__(self, cri, membus, fifo_depth=128): + def __init__(self, tsc, cri, membus, fifo_depth=128): # shutdown procedure: set enable to 0, wait until busy=0 self.enable = CSRStorage() self.busy = CSRStatus() self.submodules.message_encoder = MessageEncoder( - cri, self.enable.storage) + tsc, cri, self.enable.storage) self.submodules.fifo = stream.SyncFIFO( [("data", message_len)], fifo_depth, True) self.submodules.converter = stream.Converter( From 3d531cc923ddee2fad16ca69c09aef81e3a0b81e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:06:47 +0800 Subject: [PATCH 14/92] kasli: adapt to TSC and DRTIOSatellite changes --- artiq/gateware/targets/kasli.py | 51 ++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f3e400da2..b8d1be155 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,7 @@ from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite +from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO from artiq.build_soc import * @@ -120,9 +120,10 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_crg = _RTIOCRG(self.platform) self.csr_devices.append("rtio_crg") fix_serdes_timing_path(self.platform) - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -138,7 +139,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") @@ -662,6 +663,8 @@ class _MasterBase(MiniSoC, AMPSoC): self.comb += [sfp_ctl.led.eq(channel.rx_ready) for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + drtio_csr_group = [] drtio_memory_group = [] self.drtio_cri = [] @@ -672,7 +675,7 @@ class _MasterBase(MiniSoC, AMPSoC): drtio_memory_group.append(memory_name) core = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})( - DRTIOMaster(self.drtio_transceiver.channels[i])) + DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) self.drtio_cri.append(core.cri) self.csr_devices.append(core_name) @@ -704,10 +707,10 @@ class _MasterBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -717,7 +720,7 @@ class _MasterBase(MiniSoC, AMPSoC): [self.rtio_core.cri] + self.drtio_cri) self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.rtio_analyzer = rtio.Analyzer(self.cri_con.switch.slave, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.cri_con.switch.slave, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") @@ -799,6 +802,21 @@ class _SatelliteBase(BaseSoC): ~self.drtio_transceiver.stable_clkin.storage) self.comb += sfp_ctl.led.eq(self.drtio_transceiver.channels[0].rx_ready) + self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) + self.submodules.drtio0 = rx0(DRTIOSatellite( + self.rtio_tsc, self.drtio_transceiver.channels[0], + self.rx_synchronizer)) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), @@ -829,18 +847,11 @@ class _SatelliteBase(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels, - self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.comb += [ + self.drtio0.cri.connect(self.drtio0_io.cri), + self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + ] class Master(_MasterBase): From 19ae9ac1b1be5dc6225071113b7887c324c621da Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:07:24 +0800 Subject: [PATCH 15/92] kc705: adapt to TSC changes --- artiq/gateware/targets/kc705.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index eb32aedb2..24a11cf96 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -161,9 +161,10 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") self.config["HAS_RTIO_CLOCK_SWITCH"] = None - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -180,7 +181,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") @@ -377,9 +378,10 @@ class SMA_SPI(_StandaloneBase): use_sma=False) self.csr_devices.append("rtio_crg") self.config["HAS_RTIO_CLOCK_SWITCH"] = None - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -395,7 +397,7 @@ class SMA_SPI(_StandaloneBase): self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") From 1450e17a738477b680f8a500d2b5094713a0d174 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:10:41 +0800 Subject: [PATCH 16/92] sayma: adapt to TSC and DRTIOSatellite changes --- artiq/gateware/targets/sayma_amc.py | 41 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 289363184..3e925baa4 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -22,7 +22,7 @@ from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite +from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO from artiq.build_soc import * @@ -201,9 +201,10 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.cd_rtio.clk.eq(ClockSignal("jesd")), self.cd_rtio.rst.eq(ResetSignal("jesd")) ] - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async") + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -215,12 +216,12 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_core.coarse_ts, self.ad9154_crg.jref) + self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) self.csr_devices.append("sysref_sampler") @@ -283,6 +284,8 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + drtio_csr_group = [] drtio_memory_group = [] drtio_cri = [] @@ -293,7 +296,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): drtio_memory_group.append(memory_name) core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.drtio_transceiver.channels[i])) + DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) @@ -357,10 +360,10 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -371,7 +374,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.register_kernel_cpu_csrdevice("cri_con") self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_core.coarse_ts, self.ad9154_crg.jref) + self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) self.csr_devices.append("sysref_sampler") @@ -427,6 +430,8 @@ class Master(MiniSoC, AMPSoC): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + drtio_csr_group = [] drtio_memory_group = [] drtio_cri = [] @@ -437,7 +442,7 @@ class Master(MiniSoC, AMPSoC): drtio_memory_group.append(memory_name) core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.drtio_transceiver.channels[i])) + DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) @@ -499,10 +504,10 @@ class Master(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -583,10 +588,12 @@ class Satellite(BaseSoC, RTMCommon): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels, + self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, @@ -596,6 +603,12 @@ class Satellite(BaseSoC, RTMCommon): self.add_csr_group("drtio", ["drtio0"]) self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.comb += [ + self.drtio0.cri.connect(self.drtio0_io.cri), + self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + ] + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), @@ -614,7 +627,7 @@ class Satellite(BaseSoC, RTMCommon): self.config["HAS_SI5324"] = None self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.drtio0.coarse_ts, self.ad9154_crg.jref) + self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) self.csr_devices.append("sysref_sampler") rtio_clk_period = 1e9/rtio_clk_freq From 5f20d79408fb6ee0fc81c712d4a1f44700f625b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 14:00:09 +0800 Subject: [PATCH 17/92] drtio: add timeout on satellite internal CRI buffer space request --- artiq/firmware/satman/main.rs | 5 ++++- artiq/gateware/drtio/rt_errors_satellite.py | 3 ++- artiq/gateware/drtio/rt_packet_satellite.py | 10 ++++++++++ artiq/gateware/test/drtio/test_full_stack.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 849901e88..85143253d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -210,6 +210,9 @@ fn process_errors() { error!("received truncated packet"); } if errors & 4 != 0 { + error!("timeout attempting to get buffer space from CRI") + } + if errors & 8 != 0 { let channel; let timestamp_event; let timestamp_counter; @@ -221,7 +224,7 @@ fn process_errors() { error!("write underflow, channel={}, timestamp={}, counter={}, slack={}", channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter); } - if errors & 8 != 0 { + if errors & 16 != 0 { error!("write overflow"); } unsafe { diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 764365730..2bf190a0f 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -8,7 +8,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): def __init__(self, rt_packet, tsc, cri, async_errors): - self.protocol_error = CSR(4) + self.protocol_error = CSR(5) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) self.underflow_timestamp_counter = CSRStatus(64) @@ -68,6 +68,7 @@ class RTErrorsSatellite(Module, AutoCSR): error_csr(self.protocol_error, (rt_packet.unknown_packet_type, False, None, None), (rt_packet.packet_truncated, False, None, None), + (rt_packet.buffer_space_timeout, False, None, None), (underflow, True, underflow_error_cri, underflow_error_csr), (overflow, True, None, None) ) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 4760e11ac..1656f41cd 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -2,6 +2,7 @@ from migen import * from migen.genlib.fsm import * +from migen.genlib.misc import WaitTimer from artiq.gateware.rtio import cri from artiq.gateware.drtio.rt_serializer import * @@ -13,6 +14,7 @@ class RTPacketSatellite(Module): self.unknown_packet_type = Signal() self.packet_truncated = Signal() + self.buffer_space_timeout = Signal() self.tsc_load = Signal() self.tsc_load_value = Signal(64) @@ -105,6 +107,9 @@ class RTPacketSatellite(Module): ongoing_packet = Signal() self.sync += ongoing_packet.eq(ongoing_packet_next) + timeout_counter = WaitTimer(8191) + self.submodules += timeout_counter + rx_fsm.act("INPUT", If(rx_dp.frame_r, rx_dp.packet_buffer_load.eq(1), @@ -149,6 +154,11 @@ class RTPacketSatellite(Module): NextState("BUFFER_SPACE") ) rx_fsm.act("BUFFER_SPACE", + timeout_counter.wait.eq(1), + If(timeout_counter.done, + self.buffer_space_timeout.eq(1), + NextState("INPUT") + ), If(self.cri.o_buffer_space_valid, buffer_space_set.eq(1), buffer_space_update.eq(1), diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index eafb438c1..69f89b094 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -236,7 +236,7 @@ class TestFullStack(unittest.TestCase): errors = yield from saterr.protocol_error.read() underflow_channel = yield from saterr.underflow_channel.read() underflow_timestamp_event = yield from saterr.underflow_timestamp_event.read() - self.assertEqual(errors, 4) # write underflow + self.assertEqual(errors, 8) # write underflow self.assertEqual(underflow_channel, 42) self.assertEqual(underflow_timestamp_event, 100) yield from saterr.protocol_error.write(errors) From 839f748a1dda4089a23e933945f2dd1081b83e85 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 15:55:20 +0800 Subject: [PATCH 18/92] drtio: add external TSC to repeater --- artiq/gateware/drtio/core.py | 4 ++-- artiq/gateware/drtio/rt_packet_repeater.py | 5 ++--- .../test/drtio/test_rt_packet_repeater.py | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 47a56ce0c..13afbab46 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -181,13 +181,13 @@ class DRTIOMaster(Module): class DRTIORepeater(Module): - def __init__(self, chanif): + def __init__(self, tsc, chanif): 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") - self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(self.link_layer) + self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 081d444a3..379a445ec 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -9,7 +9,7 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketRepeater(Module): - def __init__(self, link_layer): + def __init__(self, tsc, link_layer): # CRI target interface in rtio domain self.cri = cri.Interface() @@ -24,7 +24,6 @@ class RTPacketRepeater(Module): # set_time interface, in rtio domain self.set_time_stb = Signal() self.set_time_ack = Signal() - self.tsc_value = Signal(64) # # # @@ -44,7 +43,7 @@ class RTPacketRepeater(Module): # TSC sync tsc_value = Signal(64) tsc_value_load = Signal() - self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) + self.sync.rtio += If(tsc_value_load, tsc_value.eq(tsc.coarse_ts)) # Write buffer and extra data count wb_timestamp = Signal(64) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index c778d1724..d348a5efc 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -11,20 +11,23 @@ from artiq.gateware.drtio.rt_packet_repeater import RTPacketRepeater def create_dut(nwords): pt = PacketInterface("s2m", nwords*8) pr = PacketInterface("m2s", nwords*8) + ts = Signal(64) dut = ClockDomainsRenamer({"rtio": "sys", "rtio_rx": "sys"})( - RTPacketRepeater(SimpleNamespace( - rx_rt_frame=pt.frame, rx_rt_data=pt.data, - tx_rt_frame=pr.frame, tx_rt_data=pr.data))) - return pt, pr, dut + RTPacketRepeater( + SimpleNamespace(coarse_ts=ts), + SimpleNamespace( + rx_rt_frame=pt.frame, rx_rt_data=pt.data, + tx_rt_frame=pr.frame, tx_rt_data=pr.data))) + return pt, pr, ts, dut class TestRepeater(unittest.TestCase): def test_set_time(self): nwords = 2 - pt, pr, dut = create_dut(nwords) + pt, pr, ts, dut = create_dut(nwords) def send(): - yield dut.tsc_value.eq(0x12345678) + yield ts.eq(0x12345678) yield dut.set_time_stb.eq(1) while not (yield dut.set_time_ack): yield @@ -55,7 +58,7 @@ class TestRepeater(unittest.TestCase): ] for nwords in range(1, 8): - pt, pr, dut = create_dut(nwords) + pt, pr, ts, dut = create_dut(nwords) def send(): for channel, timestamp, address, data in test_writes: @@ -89,7 +92,7 @@ class TestRepeater(unittest.TestCase): def test_buffer_space(self): for nwords in range(1, 8): - pt, pr, dut = create_dut(nwords) + pt, pr, ts, dut = create_dut(nwords) def send_requests(): for i in range(10): From 2884d595b363428388790dc06904e59dfc4cd4bf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 16:08:40 +0800 Subject: [PATCH 19/92] drtio: add rt_controller_repeater --- artiq/gateware/drtio/core.py | 5 ++- .../gateware/drtio/rt_controller_repeater.py | 42 +++++++++++++++++++ artiq/gateware/drtio/rt_packet_repeater.py | 8 ++-- 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 artiq/gateware/drtio/rt_controller_repeater.py diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 13afbab46..f7a625e09 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -10,7 +10,8 @@ from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, rt_packet_satellite, rt_errors_satellite, - rt_packet_master, rt_controller_master) + rt_packet_master, rt_controller_master, + rt_controller_repeater) from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer @@ -188,6 +189,7 @@ class DRTIORepeater(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer) + self.submodules.rt_controller = rt_controller_repeater.RTController(self.rt_packet) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -195,6 +197,7 @@ class DRTIORepeater(Module): def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + + self.rt_controller.get_csrs() + self.aux_controller.get_csrs()) @property diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py new file mode 100644 index 000000000..97de2d70e --- /dev/null +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -0,0 +1,42 @@ +from migen import * + +from misoc.interconnect.csr import * + +from artiq.gateware.rtio.cdc import BlindTransfer + + +class RTController(Module, AutoCSR): + def __init__(self, rt_packet): + self.set_time = CSR() + self.protocol_error = CSR(4) + + set_time_stb = Signal() + set_time_ack = Signal() + self.submodules += CrossDomainRequest("rtio", + set_time_stb, set_time_ack, None, + rt_packet.set_time_stb, rt_packet.set_time_ack, None) + self.sync += [ + If(set_time_ack, set_time_stb.eq(0)), + If(self.set_time.re, set_time_stb.eq(1)) + ] + self.comb += self.set_time.w.eq(set_time_stb) + + errors = [ + (rt_packet.err_unknown_packet_type, "rtio_rx"), + (rt_packet.err_packet_truncated, "rtio_rx"), + (rt_packet.err_command_missed, "rtio"), + (rt_packet.err_buffer_space_timeout, "rtio") + ] + + for n, (err_i, err_cd) in enumerate(errors): + xfer = BlindTransfer(err_cd, "sys") + self.submodules += xfer + + self.comb += xfer.i.eq(err_i) + + err_pending = Signal() + self.sync += [ + If(self.protocol_error.re & self.protocol_error.r[n], err_pending.eq(0)), + If(xfer.o, err_pending.eq(1)) + ] + self.comb += self.protocol_error.w[n].eq(err_pending) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 379a445ec..5ccd8dd70 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -18,8 +18,8 @@ class RTPacketRepeater(Module): self.err_packet_truncated = Signal() # in rtio domain - self.command_missed = Signal() - self.buffer_space_timeout = Signal() + self.err_command_missed = Signal() + self.err_buffer_space_timeout = Signal() # set_time interface, in rtio domain self.set_time_stb = Signal() @@ -103,7 +103,7 @@ class RTPacketRepeater(Module): # Missed commands cri_ready = Signal() - self.sync.rtio += self.command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + self.sync.rtio += self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) @@ -158,7 +158,7 @@ class RTPacketRepeater(Module): tx_fsm.act("WAIT_BUFFER_SPACE", timeout_counter.wait.eq(1), If(timeout_counter.done, - self.buffer_space_timeout.eq(1), + self.err_buffer_space_timeout.eq(1), NextState("IDLE") ).Else( If(buffer_space_not, From 92be9324df06aea4ae8a925a0b4400977b0f6a18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 16:09:02 +0800 Subject: [PATCH 20/92] add missing files --- artiq/gateware/drtio/cdc.py | 55 +++++++++++++++++++++++++++++++++++++ artiq/gateware/rtio/tsc.py | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 artiq/gateware/drtio/cdc.py create mode 100644 artiq/gateware/rtio/tsc.py diff --git a/artiq/gateware/drtio/cdc.py b/artiq/gateware/drtio/cdc.py new file mode 100644 index 000000000..9edd8a1b4 --- /dev/null +++ b/artiq/gateware/drtio/cdc.py @@ -0,0 +1,55 @@ +from migen import * + +from migen.genlib.cdc import PulseSynchronizer + + +class CrossDomainRequest(Module): + def __init__(self, domain, + req_stb, req_ack, req_data, + srv_stb, srv_ack, srv_data): + dsync = getattr(self.sync, domain) + + request = PulseSynchronizer("sys", domain) + reply = PulseSynchronizer(domain, "sys") + self.submodules += request, reply + + ongoing = Signal() + self.comb += request.i.eq(~ongoing & req_stb) + self.sync += [ + req_ack.eq(reply.o), + If(req_stb, ongoing.eq(1)), + If(req_ack, ongoing.eq(0)) + ] + if req_data is not None: + req_data_r = Signal.like(req_data) + req_data_r.attr.add("no_retiming") + self.sync += If(req_stb, req_data_r.eq(req_data)) + dsync += [ + If(request.o, srv_stb.eq(1)), + If(srv_ack, srv_stb.eq(0)) + ] + if req_data is not None: + dsync += If(request.o, srv_data.eq(req_data_r)) + self.comb += reply.i.eq(srv_stb & srv_ack) + + +class CrossDomainNotification(Module): + def __init__(self, domain, rdomain, + emi_stb, emi_data, + rec_stb, rec_ack, rec_data): + emi_data_r = Signal(len(emi_data)) + emi_data_r.attr.add("no_retiming") + dsync = getattr(self.sync, domain) + dsync += If(emi_stb, emi_data_r.eq(emi_data)) + + ps = PulseSynchronizer(domain, rdomain) + self.submodules += ps + self.comb += ps.i.eq(emi_stb) + rsync = getattr(self.sync, rdomain) + rsync += [ + If(rec_ack, rec_stb.eq(0)), + If(ps.o, + rec_data.eq(emi_data_r), + rec_stb.eq(1) + ) + ] diff --git a/artiq/gateware/rtio/tsc.py b/artiq/gateware/rtio/tsc.py new file mode 100644 index 000000000..e93744553 --- /dev/null +++ b/artiq/gateware/rtio/tsc.py @@ -0,0 +1,48 @@ +from migen import * + +from artiq.gateware.rtio.cdc import GrayCodeTransfer + + +class TSC(Module): + def __init__(self, mode, glbl_fine_ts_width=0): + self.glbl_fine_ts_width = glbl_fine_ts_width + + # in rtio domain + self.coarse_ts = Signal(64 - glbl_fine_ts_width) + self.full_ts = Signal(64) + + # in sys domain + # monotonic, may lag behind the counter in the IO clock domain, but + # not be ahead of it. + self.coarse_ts_sys = Signal.like(self.coarse_ts) + self.full_ts_sys = Signal(64) + + # in rtio domain + self.load = Signal() + self.load_value = Signal.like(self.coarse_ts) + + if mode == "async": + self.full_ts_cri = self.full_ts_sys + elif mode == "sync": + self.full_ts_cri = self.full_ts + else: + raise ValueError + + # # # + + self.sync.rtio += If(self.load, + self.coarse_ts.eq(self.load_value) + ).Else( + self.coarse_ts.eq(self.coarse_ts + 1) + ) + coarse_ts_cdc = GrayCodeTransfer(len(self.coarse_ts)) # from rtio to sys + self.submodules += coarse_ts_cdc + self.comb += [ + coarse_ts_cdc.i.eq(self.coarse_ts), + self.coarse_ts_sys.eq(coarse_ts_cdc.o) + ] + + self.comb += [ + self.full_ts.eq(self.coarse_ts << glbl_fine_ts_width), + self.full_ts_sys.eq(self.coarse_ts_sys << glbl_fine_ts_width) + ] From 87e0384e97fa2f26497e8a70fd322d1de569abbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 17:56:56 +0800 Subject: [PATCH 21/92] drtio: separate aux controller This helps with managing CSR groups and heterogeneous (satellite/repeaters) DRTIO cores. --- artiq/firmware/libboard_artiq/drtioaux.rs | 30 +++---- artiq/firmware/satman/main.rs | 34 ++++---- artiq/gateware/drtio/__init__.py | 2 +- artiq/gateware/drtio/aux_controller.py | 2 +- artiq/gateware/drtio/core.py | 19 +---- artiq/gateware/targets/kasli.py | 54 ++++++++----- artiq/gateware/targets/sayma_amc.py | 81 ++++++++++++------- .../test/drtio/test_aux_controller.py | 2 +- 8 files changed, 123 insertions(+), 101 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 97a06e3b2..9c189e148 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -2,7 +2,7 @@ use core::slice; use crc; use io::{ProtoRead, ProtoWrite, Cursor, Error as IoError}; -use board_misoc::{csr::DRTIO, mem::DRTIO_AUX, clock}; +use board_misoc::{csr::DRTIOAUX, mem::DRTIOAUX_MEM, clock}; use proto_artiq::drtioaux_proto::Error as ProtocolError; pub use proto_artiq::drtioaux_proto::Packet; @@ -40,17 +40,17 @@ pub fn reset(linkno: u8) { // clear buffer first to limit race window with buffer overflow // error. We assume the CPU is fast enough so that no two packets // will be received between the buffer and the error flag are cleared. - (DRTIO[linkno].aux_rx_present_write)(1); - (DRTIO[linkno].aux_rx_error_write)(1); + (DRTIOAUX[linkno].aux_rx_present_write)(1); + (DRTIOAUX[linkno].aux_rx_error_write)(1); } } fn has_rx_error(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { - let error = (DRTIO[linkno].aux_rx_error_read)() != 0; + let error = (DRTIOAUX[linkno].aux_rx_error_read)() != 0; if error { - (DRTIO[linkno].aux_rx_error_write)(1) + (DRTIOAUX[linkno].aux_rx_error_write)(1) } error } @@ -61,11 +61,11 @@ fn receive(linkno: u8, f: F) -> Result, Error> { let linkidx = linkno as usize; unsafe { - if (DRTIO[linkidx].aux_rx_present_read)() == 1 { - let ptr = DRTIO_AUX[linkidx].base + DRTIO_AUX[linkidx].size / 2; - let len = (DRTIO[linkidx].aux_rx_length_read)(); + if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { + let ptr = DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2; + let len = (DRTIOAUX[linkidx].aux_rx_length_read)(); let result = f(slice::from_raw_parts(ptr as *mut u8, len as usize)); - (DRTIO[linkidx].aux_rx_present_write)(1); + (DRTIOAUX[linkidx].aux_rx_present_write)(1); Ok(Some(result?)) } else { Ok(None) @@ -114,12 +114,12 @@ fn transmit(linkno: u8, f: F) -> Result<(), Error> { let linkno = linkno as usize; unsafe { - while (DRTIO[linkno].aux_tx_read)() != 0 {} - let ptr = DRTIO_AUX[linkno].base; - let len = DRTIO_AUX[linkno].size / 2; + while (DRTIOAUX[linkno].aux_tx_read)() != 0 {} + let ptr = DRTIOAUX_MEM[linkno].base; + let len = DRTIOAUX_MEM[linkno].size / 2; let len = f(slice::from_raw_parts_mut(ptr as *mut u8, len))?; - (DRTIO[linkno].aux_tx_length_write)(len as u16); - (DRTIO[linkno].aux_tx_write)(1); + (DRTIOAUX[linkno].aux_tx_length_write)(len as u16); + (DRTIOAUX[linkno].aux_tx_write)(1); Ok(()) } } @@ -146,7 +146,7 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { // TODO: routing fn get_linkno(nodeno: u8) -> Result> { - if nodeno == 0 || nodeno as usize > DRTIO.len() { + if nodeno == 0 || nodeno as usize > DRTIOAUX.len() { return Err(Error::NoRoute) } Ok(nodeno - 1) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 85143253d..c7e7fb73e 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -16,21 +16,21 @@ use board_artiq::hmc830_7043; fn drtio_reset(reset: bool) { unsafe { - (csr::DRTIO[0].reset_write)(if reset { 1 } else { 0 }); + csr::drtiosat::reset_write(if reset { 1 } else { 0 }); } } fn drtio_reset_phy(reset: bool) { unsafe { - (csr::DRTIO[0].reset_phy_write)(if reset { 1 } else { 0 }); + csr::drtiosat::reset_phy_write(if reset { 1 } else { 0 }); } } fn drtio_tsc_loaded() -> bool { unsafe { - let tsc_loaded = (csr::DRTIO[0].tsc_loaded_read)() == 1; + let tsc_loaded = csr::drtiosat::tsc_loaded_read() == 1; if tsc_loaded { - (csr::DRTIO[0].tsc_loaded_write)(1); + csr::drtiosat::tsc_loaded_write(1); } tsc_loaded } @@ -56,29 +56,29 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error drtioaux::Packet::RtioErrorRequest => { let errors; unsafe { - errors = (csr::DRTIO[0].rtio_error_read)(); + errors = csr::drtiosat::rtio_error_read(); } if errors & 1 != 0 { let channel; unsafe { - channel = (csr::DRTIO[0].sequence_error_channel_read)(); - (csr::DRTIO[0].rtio_error_write)(1); + channel = csr::drtiosat::sequence_error_channel_read(); + csr::drtiosat::rtio_error_write(1); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) } else if errors & 2 != 0 { let channel; unsafe { - channel = (csr::DRTIO[0].collision_channel_read)(); - (csr::DRTIO[0].rtio_error_write)(2); + channel = csr::drtiosat::collision_channel_read(); + csr::drtiosat::rtio_error_write(2); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply { channel }) } else if errors & 4 != 0 { let channel; unsafe { - channel = (csr::DRTIO[0].busy_channel_read)(); - (csr::DRTIO[0].rtio_error_write)(4); + channel = csr::drtiosat::busy_channel_read(); + csr::drtiosat::rtio_error_write(4); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel }) @@ -201,7 +201,7 @@ fn process_aux_packets() { fn process_errors() { let errors; unsafe { - errors = (csr::DRTIO[0].protocol_error_read)(); + errors = csr::drtiosat::protocol_error_read(); } if errors & 1 != 0 { error!("received packet of an unknown type"); @@ -217,9 +217,9 @@ fn process_errors() { let timestamp_event; let timestamp_counter; unsafe { - channel = (csr::DRTIO[0].underflow_channel_read)(); - timestamp_event = (csr::DRTIO[0].underflow_timestamp_event_read)() as i64; - timestamp_counter = (csr::DRTIO[0].underflow_timestamp_counter_read)() as i64; + channel = csr::drtiosat::underflow_channel_read(); + timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64; + timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64; } error!("write underflow, channel={}, timestamp={}, counter={}, slack={}", channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter); @@ -228,7 +228,7 @@ fn process_errors() { error!("write overflow"); } unsafe { - (csr::DRTIO[0].protocol_error_write)(errors); + csr::drtiosat::protocol_error_write(errors); } } @@ -247,7 +247,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings fn drtio_link_rx_up() -> bool { unsafe { - (csr::DRTIO[0].rx_up_read)() == 1 + csr::drtiosat::rx_up_read() == 1 } } diff --git a/artiq/gateware/drtio/__init__.py b/artiq/gateware/drtio/__init__.py index 76cb979c7..6efb44361 100644 --- a/artiq/gateware/drtio/__init__.py +++ b/artiq/gateware/drtio/__init__.py @@ -1,2 +1,2 @@ from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster, DRTIORepeater - +from artiq.gateware.drtio.aux_controller import DRTIOAuxController diff --git a/artiq/gateware/drtio/aux_controller.py b/artiq/gateware/drtio/aux_controller.py index b60167dea..8effda67d 100644 --- a/artiq/gateware/drtio/aux_controller.py +++ b/artiq/gateware/drtio/aux_controller.py @@ -211,7 +211,7 @@ class Receiver(Module, AutoCSR): # TODO: FullMemoryWE should be applied by migen.build @FullMemoryWE() -class AuxController(Module): +class DRTIOAuxController(Module): def __init__(self, link_layer): self.bus = wishbone.Interface() self.submodules.transmitter = Transmitter(link_layer, len(self.bus.dat_w)) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index f7a625e09..b1fd8a88a 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -8,7 +8,7 @@ from misoc.interconnect.csr import * from artiq.gateware.rtio import cri, rtlink from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * -from artiq.gateware.drtio import (link_layer, aux_controller, +from artiq.gateware.drtio import (link_layer, rt_packet_satellite, rt_errors_satellite, rt_packet_master, rt_controller_master, rt_controller_repeater) @@ -145,13 +145,10 @@ class DRTIOSatellite(Module): self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( self.rt_packet, tsc, self.cri, self.async_errors) - self.submodules.aux_controller = aux_controller.AuxController( - self.link_layer) - def get_csrs(self): return ([self.reset, self.reset_phy, self.tsc_loaded] + self.link_layer.get_csrs() + self.link_stats.get_csrs() + - self.rt_errors.get_csrs() + self.aux_controller.get_csrs()) + self.rt_errors.get_csrs()) class DRTIOMaster(Module): @@ -166,15 +163,11 @@ class DRTIOMaster(Module): tsc, self.rt_packet) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) - self.submodules.aux_controller = aux_controller.AuxController( - self.link_layer) - def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + self.rt_controller.get_csrs() + - self.rt_manager.get_csrs() + - self.aux_controller.get_csrs()) + self.rt_manager.get_csrs()) @property def cri(self): @@ -191,14 +184,10 @@ class DRTIORepeater(Module): self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer) self.submodules.rt_controller = rt_controller_repeater.RTController(self.rt_packet) - self.submodules.aux_controller = aux_controller.AuxController( - self.link_layer) - def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + - self.rt_controller.get_csrs() + - self.aux_controller.get_csrs()) + self.rt_controller.get_csrs()) @property def cri(self): diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b8d1be155..0aa181ca3 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,7 @@ from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO +from artiq.gateware.drtio import * from artiq.build_soc import * @@ -622,7 +622,7 @@ class _MasterBase(MiniSoC, AMPSoC): "cri_con": 0x10000000, "rtio": 0x20000000, "rtio_dma": 0x30000000, - "drtio_aux": 0x50000000, + "drtioaux": 0x50000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -666,27 +666,36 @@ class _MasterBase(MiniSoC, AMPSoC): self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] - drtio_memory_group = [] + drtioaux_csr_group = [] + drtioaux_memory_group = [] self.drtio_cri = [] for i in range(2): core_name = "drtio" + str(i) - memory_name = "drtio" + str(i) + "_aux" + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" drtio_csr_group.append(core_name) - drtio_memory_group.append(memory_name) + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) - core = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})( - DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) self.drtio_cri.append(core.cri) self.csr_devices.append(core_name) - memory_address = self.mem_map["drtio_aux"] + 0x800*i + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i self.add_wb_slave(memory_address, 0x800, - core.aux_controller.bus) + coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None self.add_csr_group("drtio", drtio_csr_group) - self.add_memory_group("drtio_aux", drtio_memory_group) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq gtp = self.drtio_transceiver.gtps[0] @@ -759,7 +768,7 @@ class _MasterBase(MiniSoC, AMPSoC): class _SatelliteBase(BaseSoC): mem_map = { - "drtio_aux": 0x50000000, + "drtioaux": 0x50000000, } mem_map.update(BaseSoC.mem_map) @@ -806,16 +815,19 @@ class _SatelliteBase(BaseSoC): rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( + self.submodules.drtiosat = rx0(DRTIOSatellite( self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.csr_devices.append("drtiosat") + self.submodules.drtioaux0 = rx0(DRTIOAuxController( + self.drtiosat.link_layer)) + self.csr_devices.append("drtioaux0") + self.add_wb_slave(self.mem_map["drtioaux"], 0x800, + self.drtioaux0.bus) + self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.add_csr_group("drtioaux", ["drtioaux0"]) + self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( @@ -847,10 +859,10 @@ class _SatelliteBase(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) self.comb += [ - self.drtio0.cri.connect(self.drtio0_io.cri), - self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + self.drtiosat.cri.connect(self.local_io.cri), + self.drtiosat.async_errors.eq(self.local_io.async_errors) ] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 3e925baa4..0c731002a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -22,7 +22,7 @@ from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO +from artiq.gateware.drtio import * from artiq.build_soc import * @@ -234,7 +234,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): "rtio": 0x11000000, "rtio_dma": 0x12000000, "serwb": 0x13000000, - "drtio_aux": 0x14000000, + "drtioaux": 0x14000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -287,27 +287,36 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] - drtio_memory_group = [] + drtioaux_csr_group = [] + drtioaux_memory_group = [] drtio_cri = [] for i in range(2): core_name = "drtio" + str(i) - memory_name = "drtio" + str(i) + "_aux" + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" drtio_csr_group.append(core_name) - drtio_memory_group.append(memory_name) + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) - core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) - memory_address = self.mem_map["drtio_aux"] + 0x800*i + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i self.add_wb_slave(memory_address, 0x800, - core.aux_controller.bus) + coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None self.add_csr_group("drtio", drtio_csr_group) - self.add_memory_group("drtio_aux", drtio_memory_group) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] @@ -389,7 +398,7 @@ class Master(MiniSoC, AMPSoC): "cri_con": 0x10000000, "rtio": 0x11000000, "rtio_dma": 0x12000000, - "drtio_aux": 0x14000000, + "drtioaux": 0x14000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -433,27 +442,36 @@ class Master(MiniSoC, AMPSoC): self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] - drtio_memory_group = [] + drtioaux_csr_group = [] + drtioaux_memory_group = [] drtio_cri = [] for i in range(10): core_name = "drtio" + str(i) - memory_name = "drtio" + str(i) + "_aux" + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" drtio_csr_group.append(core_name) - drtio_memory_group.append(memory_name) + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) - core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) - memory_address = self.mem_map["drtio_aux"] + 0x800*i + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i self.add_wb_slave(memory_address, 0x800, - core.aux_controller.bus) + coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None self.add_csr_group("drtio", drtio_csr_group) - self.add_memory_group("drtio_aux", drtio_memory_group) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] @@ -525,7 +543,7 @@ class Satellite(BaseSoC, RTMCommon): """ mem_map = { "serwb": 0x13000000, - "drtio_aux": 0x14000000, + "drtioaux": 0x14000000, } mem_map.update(BaseSoC.mem_map) @@ -592,21 +610,24 @@ class Satellite(BaseSoC, RTMCommon): rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( + self.submodules.drtiosat = rx0(DRTIOSatellite( self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.csr_devices.append("drtiosat") + self.submodules.drtioaux0 = rx0(DRTIOAuxController( + self.drtiosat.link_layer)) + self.csr_devices.append("drtioaux0") + self.add_wb_slave(self.mem_map["drtioaux"], 0x800, + self.drtioaux0.bus) + self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.add_csr_group("drtioaux", ["drtioaux0"]) + self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) - self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) self.comb += [ - self.drtio0.cri.connect(self.drtio0_io.cri), - self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + self.drtiosat.cri.connect(self.local_io.cri), + self.drtiosat.async_errors.eq(self.local_io.async_errors), ] self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) diff --git a/artiq/gateware/test/drtio/test_aux_controller.py b/artiq/gateware/test/drtio/test_aux_controller.py index f07f5eb6d..64e2e15d7 100644 --- a/artiq/gateware/test/drtio/test_aux_controller.py +++ b/artiq/gateware/test/drtio/test_aux_controller.py @@ -36,7 +36,7 @@ class TB(Module): def __init__(self, nwords): self.submodules.link_layer = Loopback(nwords) self.submodules.aux_controller = ClockDomainsRenamer( - {"rtio": "sys", "rtio_rx": "sys"})(AuxController(self.link_layer)) + {"rtio": "sys", "rtio_rx": "sys"})(DRTIOAuxController(self.link_layer)) class TestAuxController(unittest.TestCase): From df61b859882f9d266fbca8b2e00ea37c72276402 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 14:11:21 +0800 Subject: [PATCH 22/92] drtio: fix imports --- artiq/gateware/drtio/core.py | 2 +- artiq/gateware/drtio/rt_controller_repeater.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index b1fd8a88a..b3d722825 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -11,7 +11,7 @@ from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, rt_packet_satellite, rt_errors_satellite, rt_packet_master, rt_controller_master, - rt_controller_repeater) + rt_packet_repeater, rt_controller_repeater) from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index 97de2d70e..d75e87f64 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -3,6 +3,7 @@ from migen import * from misoc.interconnect.csr import * from artiq.gateware.rtio.cdc import BlindTransfer +from artiq.gateware.drtio.cdc import CrossDomainRequest class RTController(Module, AutoCSR): From d5577ec0d0b06fae5399b4a2a26e1af0f884fcba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 16:26:48 +0800 Subject: [PATCH 23/92] cri: add routing table support --- artiq/gateware/rtio/cri.py | 62 ++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index d78c5da36..18ca1956b 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -2,6 +2,7 @@ from migen import * from migen.genlib.record import * +from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * @@ -109,8 +110,8 @@ class KernelInitiator(Module, AutoCSR): self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) -class CRIDecoder(Module): - def __init__(self, slaves=2, master=None): +class CRIDecoder(Module, AutoCSR): + def __init__(self, slaves=2, master=None, mode="async", enable_routing=False): if isinstance(slaves, int): slaves = [Interface() for _ in range(slaves)] if master is None: @@ -118,10 +119,41 @@ class CRIDecoder(Module): self.slaves = slaves self.master = master + slave_bits = bits_for(len(slaves)-1) + if enable_routing: + self.routing_destination = CSRStorage(8) + self.routing_hop = CSR(slave_bits) + # # # - selected = Signal(8, reset_less=True) - self.sync += selected.eq(self.master.chan_sel[16:]) + # routing + selected = Signal(slave_bits) + + if enable_routing: + self.specials.routing_table = Memory(slave_bits, 8) + + rtp_csr = self.routing_table.get_port(write_capable=True) + self.specials += rtp_csr + self.comb += [ + rtp_csr.adr.eq(self.routing_destination.storage), + rtp_csr.dat_w.eq(self.routing_hop.r), + rtp_csr.we.eq(self.routing_hop.re), + self.routing_hop.w.eq(rtp_csr.dat_r) + ] + + if mode == "async": + rtp_decoder = self.routing_table.get_port() + elif mode == "sync": + rtp_decoder = self.routing_table.get_port(clock_domain="rtio") + else: + raise ValueError + self.specials += rtp_decoder + self.comb += [ + rtp_decoder.adr.eq(self.master.chan_sel[16:]), + selected.eq(rtp_decoder.dat_r) + ] + else: + self.sync += selected.eq(self.master.chan_sel[16:]) # master -> slave for n, slave in enumerate(slaves): @@ -141,7 +173,7 @@ class CRIDecoder(Module): class CRISwitch(Module, AutoCSR): - def __init__(self, masters=2, slave=None): + def __init__(self, masters=2, slave=None, mode="async"): if isinstance(masters, int): masters = [Interface() for _ in range(masters)] if slave is None: @@ -153,6 +185,15 @@ class CRISwitch(Module, AutoCSR): # # # + if mode == "async": + selected = self.selected.storage + elif mode == "sync": + self.selected.storage.attr.add("no_retiming") + selected = Signal.like(self.selected.storage) + self.specials += MultiReg(self.selected.storage, selected, "rtio") + else: + raise ValueError + if len(masters) == 1: self.comb += masters[0].connect(slave) else: @@ -160,7 +201,7 @@ class CRISwitch(Module, AutoCSR): for name, size, direction in layout: if direction == DIR_M_TO_S: choices = Array(getattr(m, name) for m in masters) - self.comb += getattr(slave, name).eq(choices[self.selected.storage]) + self.comb += getattr(slave, name).eq(choices[selected]) # connect slave->master signals for name, size, direction in layout: @@ -170,11 +211,12 @@ class CRISwitch(Module, AutoCSR): dest = getattr(m, name) self.comb += dest.eq(source) + class CRIInterconnectShared(Module): - def __init__(self, masters=2, slaves=2): + def __init__(self, masters=2, slaves=2, mode="async", enable_routing=False): shared = Interface() - self.submodules.switch = CRISwitch(masters, shared) - self.submodules.decoder = CRIDecoder(slaves, shared) + self.submodules.switch = CRISwitch(masters, shared, mode) + self.submodules.decoder = CRIDecoder(slaves, shared, mode, enable_routing) def get_csrs(self): - return self.switch.get_csrs() + return self.switch.get_csrs() + self.decoder.get_csrs() From ec302747e0302e0639cd7dc76298d0292ff0e26a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 16:27:39 +0800 Subject: [PATCH 24/92] kasli: add DRTIO repeaters --- artiq/gateware/targets/kasli.py | 77 +++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0aa181ca3..43b7628b8 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -799,35 +799,63 @@ class _SatelliteBase(BaseSoC): qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) self.submodules += qpll - sfp_ctl = platform.request("sfp_ctl", 0) - self.comb += sfp_ctl.tx_disable.eq(0) + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(3)] + self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=qpll.channels[0], - data_pads=[platform.request("sfp", 0)], + data_pads=[platform.request("sfp", i) for i in range(3)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") self.sync += disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) - self.comb += sfp_ctl.led.eq(self.drtio_transceiver.channels[0].rx_ready) + self.comb += [sfp_ctl.led.eq(channel.rx_ready) + for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) - rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtiosat = rx0(DRTIOSatellite( - self.rtio_tsc, self.drtio_transceiver.channels[0], - self.rx_synchronizer)) - self.csr_devices.append("drtiosat") - self.submodules.drtioaux0 = rx0(DRTIOAuxController( - self.drtiosat.link_layer)) - self.csr_devices.append("drtioaux0") - self.add_wb_slave(self.mem_map["drtioaux"], 0x800, - self.drtioaux0.bus) - self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) + drtioaux_csr_group = [] + drtioaux_memory_group = [] + drtiorep_csr_group = [] + self.drtio_cri = [] + for i in range(3): + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) + + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + if i == 0: + self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) + core = cdr(DRTIOSatellite( + self.rtio_tsc, self.drtio_transceiver.channels[i], + self.rx_synchronizer)) + self.submodules.drtiosat = core + self.csr_devices.append("drtiosat") + else: + corerep_name = "drtiorep" + str(i-1) + drtiorep_csr_group.append(corerep_name) + + core = cdr(DRTIORepeater( + self.rtio_tsc, self.drtio_transceiver.channels[i])) + setattr(self.submodules, corerep_name, core) + self.drtio_cri.append(core.cri) + self.csr_devices.append(corerep_name) + + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i + self.add_wb_slave(memory_address, 0x800, + coreaux.bus) + self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtioaux", ["drtioaux0"]) - self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) + self.config["HAS_DRTIOREP"] = None + self.add_csr_group("drtiorep", drtiorep_csr_group) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( @@ -851,6 +879,10 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) + for gtp in self.drtio_transceiver.gtps[1:]: + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, gtp.rxoutclk) self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) fix_serdes_timing_path(platform) @@ -860,10 +892,11 @@ class _SatelliteBase(BaseSoC): self.csr_devices.append("rtio_moninj") self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) - self.comb += [ - self.drtiosat.cri.connect(self.local_io.cri), - self.drtiosat.async_errors.eq(self.local_io.async_errors) - ] + self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.drtiosat.cri], + [self.local_io.cri] + self.drtio_cri, + mode="sync", enable_routing=True) class Master(_MasterBase): From 496d1b08fd97f5460d7bc2effae26fb083930265 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 21:48:12 +0800 Subject: [PATCH 25/92] kasli: enable routing in Master --- artiq/gateware/targets/kasli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 43b7628b8..b19b9ab30 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -693,6 +693,7 @@ class _MasterBase(MiniSoC, AMPSoC): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtio", drtio_csr_group) self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) @@ -726,7 +727,8 @@ class _MasterBase(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + self.drtio_cri) + [self.rtio_core.cri] + self.drtio_cri, + enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.cri_con.switch.slave, From 7ae44f341788850a35b57b96ebffedd21614111c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 21:49:28 +0800 Subject: [PATCH 26/92] firmware: add routing table (WIP) --- .../firmware/libboard_artiq/drtio_routing.rs | 59 +++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/frontend/artiq_route.py | 10 ++-- artiq/gateware/targets/kasli.py | 2 +- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/drtio_routing.rs diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs new file mode 100644 index 000000000..810043297 --- /dev/null +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -0,0 +1,59 @@ +use board_misoc::{csr, config}; + +pub const DEST_COUNT: usize = 256; +pub const MAX_HOPS: usize = 32; +pub const INVALID_HOP: u8 = 0xff; + +pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]); + +impl RoutingTable { + // default routing table is for star topology with no hops + fn default_master() -> RoutingTable { + let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); + for i in 0..csr::DRTIO.len() { + ret.0[i][0] = i as u8; + } + for i in 1..csr::DRTIO.len() { + ret.0[i][1] = 0x00; + } + ret + } + + // satellites receive the routing table from the master + // by default, block everything + fn default_satellite() -> RoutingTable { + RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) + } +} + +pub fn config_routing_table() -> RoutingTable { + let mut ret = RoutingTable::default_master(); + let ok = config::read("routing_table", |result| { + if let Ok(data) = result { + if data.len() == DEST_COUNT*MAX_HOPS { + for i in 0..DEST_COUNT { + for j in 0..MAX_HOPS { + ret.0[i][j] = data[i*MAX_HOPS+j]; + } + } + return true; + } + } + false + }); + if !ok { + warn!("could not read routing table from configuration, using default"); + } + ret +} + +pub fn program_interconnect(rt: &RoutingTable, rank: u8) +{ + for i in 0..DEST_COUNT { + let hop = rt.0[i][rank as usize]; + unsafe { + csr::cri_con::routing_destination_write(i as _); + csr::cri_con::routing_hop_write(hop); + } + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 443737441..228f6ed5e 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -48,3 +48,5 @@ pub mod grabber; #[cfg(has_drtio)] pub mod drtioaux; +#[cfg(has_drtio_routing)] +pub mod drtio_routing; diff --git a/artiq/frontend/artiq_route.py b/artiq/frontend/artiq_route.py index c818237ce..739a649e2 100755 --- a/artiq/frontend/artiq_route.py +++ b/artiq/frontend/artiq_route.py @@ -26,19 +26,19 @@ def get_argparser(): return parser -ENTRY_COUNT = 256 +DEST_COUNT = 256 MAX_HOPS = 32 def init(filename): with open(filename, "wb") as f: - f.write(b"\xff"*(ENTRY_COUNT*MAX_HOPS)) + f.write(b"\xff"*(DEST_COUNT*MAX_HOPS)) def show_routes(filename): routes = [] with open(filename, "rb") as f: - for i in range(ENTRY_COUNT): + for i in range(DEST_COUNT): hops = [int.from_bytes(f.read(1), "big") for j in range(MAX_HOPS)] routes.append(hops) @@ -54,8 +54,8 @@ def show_routes(filename): def set_route(filename, destination, hops): with open(filename, "r+b") as f: - if destination >= ENTRY_COUNT: - raise ValueError("destination must be less than {}".format(ENTRY_COUNT)) + if destination >= DEST_COUNT: + raise ValueError("destination must be less than {}".format(DEST_COUNT)) f.seek(destination*MAX_HOPS) if len(hops) + 1 >= MAX_HOPS: diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b19b9ab30..19b4c3e62 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -854,9 +854,9 @@ class _SatelliteBase(BaseSoC): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - self.config["HAS_DRTIOREP"] = None self.add_csr_group("drtiorep", drtiorep_csr_group) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) From 014cfd8dbd8246fcdcf98d6e4762461be977f2cc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 22:44:25 +0800 Subject: [PATCH 27/92] firmware: add drtioaux routing packets --- .../firmware/libproto_artiq/drtioaux_proto.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 2d0a24e87..babb40571 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -28,6 +28,10 @@ pub enum Packet { RtioErrorCollisionReply { channel: u16 }, RtioErrorBusyReply { channel: u16 }, + RoutingSetPath { destination: u8, hops: [u8; 32] }, + RoutingSetRank { rank: u8 }, + RoutingAck, + MonitorRequest { channel: u16, probe: u8 }, MonitorReply { value: u32 }, InjectionRequest { channel: u16, overrd: u8, value: u8 }, @@ -75,6 +79,20 @@ impl Packet { channel: reader.read_u16()? }, + 0x30 => { + let destination = reader.read_u8()?; + let mut hops = [0; 32]; + reader.read_exact(&mut hops)?; + Packet::RoutingSetPath { + destination: destination, + hops: hops + } + }, + 0x31 => Packet::RoutingSetRank { + rank: reader.read_u8()? + }, + 0x32 => Packet::RoutingAck, + 0x40 => Packet::MonitorRequest { channel: reader.read_u16()?, probe: reader.read_u8()? @@ -185,6 +203,18 @@ impl Packet { writer.write_u16(channel)?; }, + Packet::RoutingSetPath { destination, hops } => { + writer.write_u8(0x30)?; + writer.write_u8(destination)?; + writer.write_all(&hops)?; + }, + Packet::RoutingSetRank { rank } => { + writer.write_u8(0x31)?; + writer.write_u8(rank)?; + }, + Packet::RoutingAck => + writer.write_u8(0x32)?, + Packet::MonitorRequest { channel, probe } => { writer.write_u8(0x40)?; writer.write_u16(channel)?; From 7ec45efdcf9d27cc3cc6a3d5d14f3bb8be287ce8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:16:09 +0800 Subject: [PATCH 28/92] kasli: add missing cri_con to Satellite --- artiq/gateware/targets/kasli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 19b4c3e62..75c3fa5e9 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -899,6 +899,7 @@ class _SatelliteBase(BaseSoC): [self.drtiosat.cri], [self.local_io.cri] + self.drtio_cri, mode="sync", enable_routing=True) + self.csr_devices.append("cri_con") class Master(_MasterBase): From 31bef9918e4cd962b61171c5540f040bca7d76a3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:16:42 +0800 Subject: [PATCH 29/92] firmware: fix drtio_routing compatibility with master and satellite --- artiq/firmware/libboard_artiq/drtio_routing.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 810043297..f5b7c735c 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -8,12 +8,12 @@ pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]); impl RoutingTable { // default routing table is for star topology with no hops - fn default_master() -> RoutingTable { + fn default_master(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); - for i in 0..csr::DRTIO.len() { + for i in 0..default_n_links { ret.0[i][0] = i as u8; } - for i in 1..csr::DRTIO.len() { + for i in 1..default_n_links { ret.0[i][1] = 0x00; } ret @@ -26,8 +26,8 @@ impl RoutingTable { } } -pub fn config_routing_table() -> RoutingTable { - let mut ret = RoutingTable::default_master(); +pub fn config_routing_table(default_n_links: usize) -> RoutingTable { + let mut ret = RoutingTable::default_master(default_n_links); let ok = config::read("routing_table", |result| { if let Ok(data) = result { if data.len() == DEST_COUNT*MAX_HOPS { From bc1d3fda6a1eadeebeebbf481deb7f1c1908247b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:17:02 +0800 Subject: [PATCH 30/92] satman: ping repeater links Tested OK on hardware. --- artiq/firmware/satman/main.rs | 67 ++++++++++++------- artiq/firmware/satman/repeater.rs | 104 ++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 25 deletions(-) create mode 100644 artiq/firmware/satman/repeater.rs diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c7e7fb73e..d53dca4f0 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(never_type, panic_implementation, panic_info_message)] +#![feature(never_type, panic_implementation, panic_info_message, const_slice_len)] #![no_std] #[macro_use] @@ -14,19 +14,27 @@ use board_artiq::serwb; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; -fn drtio_reset(reset: bool) { +mod repeater; + +fn drtiosat_reset(reset: bool) { unsafe { csr::drtiosat::reset_write(if reset { 1 } else { 0 }); } } -fn drtio_reset_phy(reset: bool) { +fn drtiosat_reset_phy(reset: bool) { unsafe { csr::drtiosat::reset_phy_write(if reset { 1 } else { 0 }); } } -fn drtio_tsc_loaded() -> bool { +fn drtiosat_link_rx_up() -> bool { + unsafe { + csr::drtiosat::rx_up_read() == 1 + } +} + +fn drtiosat_tsc_loaded() -> bool { unsafe { let tsc_loaded = csr::drtiosat::tsc_loaded_read() == 1; if tsc_loaded { @@ -44,11 +52,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error drtioaux::send_link(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { if phy { - drtio_reset_phy(true); - drtio_reset_phy(false); + drtiosat_reset_phy(true); + drtiosat_reset_phy(false); } else { - drtio_reset(true); - drtio_reset(false); + drtiosat_reset(true); + drtiosat_reset(false); } drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, @@ -198,7 +206,7 @@ fn process_aux_packets() { } } -fn process_errors() { +fn drtiosat_process_errors() { let errors; unsafe { errors = csr::drtiosat::protocol_error_read(); @@ -245,12 +253,6 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; -fn drtio_link_rx_up() -> bool { - unsafe { - csr::drtiosat::rx_up_read() == 1 - } -} - const SIPHASER_PHASE: u16 = 32; #[no_mangle] @@ -279,9 +281,21 @@ pub extern fn main() -> i32 { #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); + #[cfg(has_drtio_routing)] + let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; + #[cfg(not(has_drtio_routing))] + let mut repeaters = [repeater::Repeater::default(); 0]; + + for i in 0..repeaters.len() { + repeaters[i] = repeater::Repeater::new(i as u8); + } + loop { - while !drtio_link_rx_up() { - process_errors(); + while !drtiosat_link_rx_up() { + drtiosat_process_errors(); + for mut rep in repeaters.iter_mut() { + rep.service(); + } } info!("link is up, switching to recovered clock"); @@ -308,13 +322,16 @@ pub extern fn main() -> i32 { } drtioaux::reset(0); - drtio_reset(false); - drtio_reset_phy(false); + drtiosat_reset(false); + drtiosat_reset_phy(false); - while drtio_link_rx_up() { - process_errors(); + while drtiosat_link_rx_up() { + drtiosat_process_errors(); process_aux_packets(); - if drtio_tsc_loaded() { + for mut rep in repeaters.iter_mut() { + rep.service(); + } + if drtiosat_tsc_loaded() { #[cfg(has_ad9154)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { @@ -333,9 +350,9 @@ pub extern fn main() -> i32 { #[cfg(has_ad9154)] board_artiq::ad9154::jesd_reset(true); - drtio_reset_phy(true); - drtio_reset(true); - drtio_tsc_loaded(); + drtiosat_reset_phy(true); + drtiosat_reset(true); + drtiosat_tsc_loaded(); info!("link is down, switching to local crystal clock"); si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs new file mode 100644 index 000000000..aabd0e3a7 --- /dev/null +++ b/artiq/firmware/satman/repeater.rs @@ -0,0 +1,104 @@ +use board_misoc::{csr, clock}; +use board_artiq::drtioaux; + +#[cfg(has_drtio_routing)] +fn rep_link_rx_up(linkno: u8) -> bool { + let linkno = linkno as usize; + unsafe { + (csr::DRTIOREP[linkno].rx_up_read)() == 1 + } +} + +#[derive(Clone, Copy)] +enum RepeaterState { + Down, + SendPing { ping_count: u16 }, + WaitPingReply { ping_count: u16, timeout: u64 }, + Up, + Failed +} + +impl Default for RepeaterState { + fn default() -> RepeaterState { RepeaterState::Down } +} + +#[derive(Clone, Copy, Default)] +pub struct Repeater { + repno: u8, + auxno: u8, + state: RepeaterState +} + +#[cfg(has_drtio_routing)] +impl Repeater { + pub fn new(repno: u8) -> Repeater { + Repeater { + repno: repno, + auxno: repno + 1, + state: RepeaterState::Down + } + } + + pub fn service(&mut self) { + match self.state { + RepeaterState::Down => { + if rep_link_rx_up(self.repno) { + info!("[REP#{}] link RX became up, pinging", self.repno); + self.state = RepeaterState::SendPing { ping_count: 0 }; + } + } + RepeaterState::SendPing { ping_count } => { + if rep_link_rx_up(self.repno) { + drtioaux::send_link(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); + self.state = RepeaterState::WaitPingReply { + ping_count: ping_count + 1, + timeout: clock::get_ms() + 100 + } + } else { + info!("[REP#{}] link RX went down during ping", self.repno); + self.state = RepeaterState::Down; + } + } + RepeaterState::WaitPingReply { ping_count, timeout } => { + if rep_link_rx_up(self.repno) { + if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { + info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); + // TODO: send TSC, routing table, and rank + self.state = RepeaterState::Up; + } else { + if clock::get_ms() > timeout { + if ping_count > 200 { + info!("[REP#{}] ping failed", self.repno); + self.state = RepeaterState::Failed; + } else { + self.state = RepeaterState::SendPing { ping_count: ping_count }; + } + } + } + } else { + info!("[REP#{}] link RX went down during ping", self.repno); + self.state = RepeaterState::Down; + } + } + RepeaterState::Up => { + if !rep_link_rx_up(self.repno) { + info!("[REP#{}] link is down", self.repno); + self.state = RepeaterState::Down; + } + } + RepeaterState::Failed => { + if !rep_link_rx_up(self.repno) { + info!("[REP#{}] link is down", self.repno); + self.state = RepeaterState::Down; + } + } + } + } +} + +#[cfg(not(has_drtio_routing))] +impl Repeater { + pub fn new(_repno: u8) -> Repeater { Repeater::default() } + + pub fn service(&self) { } +} From 663432adbdbd4a594ead321fc73f6c1d6efa97ea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:33:44 +0800 Subject: [PATCH 31/92] satman: load TSCs of downstream devices --- artiq/firmware/satman/main.rs | 4 ++++ artiq/firmware/satman/repeater.rs | 40 +++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index d53dca4f0..2bce73681 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -332,6 +332,7 @@ pub extern fn main() -> i32 { rep.service(); } if drtiosat_tsc_loaded() { + info!("TSC loaded"); #[cfg(has_ad9154)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { @@ -341,6 +342,9 @@ pub extern fn main() -> i32 { error!("failed to align SYSREF at DAC: {}", e); } } + for rep in repeaters.iter() { + rep.sync_tsc(); + } if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { error!("aux packet error: {}", e); } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index aabd0e3a7..686b3acbb 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -55,7 +55,7 @@ impl Repeater { timeout: clock::get_ms() + 100 } } else { - info!("[REP#{}] link RX went down during ping", self.repno); + error!("[REP#{}] link RX went down during ping", self.repno); self.state = RepeaterState::Down; } } @@ -63,12 +63,17 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); - // TODO: send TSC, routing table, and rank + if !self.sync_tsc() { + error!("[REP#{}] remote failed to ack TSC", self.repno); + self.state = RepeaterState::Failed; + return; + } + // TODO: send routing table and rank self.state = RepeaterState::Up; } else { if clock::get_ms() > timeout { if ping_count > 200 { - info!("[REP#{}] ping failed", self.repno); + error!("[REP#{}] ping failed", self.repno); self.state = RepeaterState::Failed; } else { self.state = RepeaterState::SendPing { ping_count: ping_count }; @@ -76,7 +81,7 @@ impl Repeater { } } } else { - info!("[REP#{}] link RX went down during ping", self.repno); + error!("[REP#{}] link RX went down during ping", self.repno); self.state = RepeaterState::Down; } } @@ -94,11 +99,36 @@ impl Repeater { } } } + + pub fn sync_tsc(&self) -> bool { + let repno = self.repno as usize; + unsafe { + (csr::DRTIOREP[repno].set_time_write)(1); + while (csr::DRTIOREP[repno].set_time_read)() == 1 {} + } + + let timeout = clock::get_ms() + 200; + loop { + if !rep_link_rx_up(self.repno) { + return false; + } + if clock::get_ms() > timeout { + return false; + } + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(self.auxno) { + return true; + } + } + } } #[cfg(not(has_drtio_routing))] impl Repeater { - pub fn new(_repno: u8) -> Repeater { Repeater::default() } + pub fn new(_repno: u8) -> Repeater { Repeater::default() } pub fn service(&self) { } + + pub fn sync_tsc(&self) { } } From 4d889c0c4ebd3354d8fc966621b815d976200006 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 21:40:02 +0800 Subject: [PATCH 32/92] firmware: improve DRTIO log messages --- artiq/firmware/runtime/rtio_mgt.rs | 18 ++++++++---------- artiq/firmware/satman/main.rs | 10 ++++++---- artiq/firmware/satman/repeater.rs | 18 +++++++++++------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f2a606d86..a8685e1bd 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -114,23 +114,21 @@ pub mod drtio { } } - fn wait_tsc_ack(linkno: u8, io: &Io) -> bool { + fn wait_tsc_ack(linkno: u8, io: &Io) -> Result<(), &'static str> { loop { let mut count = 0; if !link_rx_up(linkno) { - return false; + return Err("link went down"); } count += 1; if count > 200 { - return false; + return Err("timeout"); } io.sleep(100).unwrap(); // TSCAck is the only aux packet that is sent spontaneously // by the satellite, in response to a TSC set on the RT link. - let pr = drtioaux::recv_link(linkno); - match pr { - Ok(Some(drtioaux::Packet::TSCAck)) => return true, - _ => {} + if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(linkno) { + return Ok(()) } } } @@ -194,13 +192,13 @@ pub mod drtio { set_link_up(linkno, true); init_buffer_space(linkno); sync_tsc(linkno); - if !wait_tsc_ack(linkno, &io) { - info!("[LINK#{}] remote failed to ack TSC", linkno); + if wait_tsc_ack(linkno, &io).is_err() { + error!("[LINK#{}] remote failed to ack TSC", linkno); } else { info!("[LINK#{}] link initialization completed", linkno); } } else { - info!("[LINK#{}] ping failed", linkno); + error!("[LINK#{}] ping failed", linkno); } } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 2bce73681..8ca8a6b6a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -298,7 +298,7 @@ pub extern fn main() -> i32 { } } - info!("link is up, switching to recovered clock"); + info!("uplink is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); @@ -332,7 +332,7 @@ pub extern fn main() -> i32 { rep.service(); } if drtiosat_tsc_loaded() { - info!("TSC loaded"); + info!("TSC loaded from uplink"); #[cfg(has_ad9154)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { @@ -343,7 +343,9 @@ pub extern fn main() -> i32 { } } for rep in repeaters.iter() { - rep.sync_tsc(); + if rep.sync_tsc().is_err() { + error!("remote failed to ack TSC"); + } } if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { error!("aux packet error: {}", e); @@ -357,7 +359,7 @@ pub extern fn main() -> i32 { drtiosat_reset_phy(true); drtiosat_reset(true); drtiosat_tsc_loaded(); - info!("link is down, switching to local crystal clock"); + info!("uplink is down, switching to local crystal clock"); si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); } } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 686b3acbb..d677c362e 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -9,7 +9,7 @@ fn rep_link_rx_up(linkno: u8) -> bool { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] enum RepeaterState { Down, SendPing { ping_count: u16 }, @@ -63,7 +63,7 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); - if !self.sync_tsc() { + if self.sync_tsc().is_err() { error!("[REP#{}] remote failed to ack TSC", self.repno); self.state = RepeaterState::Failed; return; @@ -100,7 +100,11 @@ impl Repeater { } } - pub fn sync_tsc(&self) -> bool { + pub fn sync_tsc(&self) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + let repno = self.repno as usize; unsafe { (csr::DRTIOREP[repno].set_time_write)(1); @@ -110,15 +114,15 @@ impl Repeater { let timeout = clock::get_ms() + 200; loop { if !rep_link_rx_up(self.repno) { - return false; + return Err("link went down"); } if clock::get_ms() > timeout { - return false; + return Err("timeout"); } // TSCAck is the only aux packet that is sent spontaneously // by the satellite, in response to a TSC set on the RT link. if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(self.auxno) { - return true; + return Ok(()); } } } @@ -130,5 +134,5 @@ impl Repeater { pub fn service(&self) { } - pub fn sync_tsc(&self) { } + pub fn sync_tsc(&self) -> Result<(), &'static str> { Ok(()) } } From e01efbcb8a2fbd8ab2b1c4c96d1f55e68a7bd0db Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 22:17:00 +0800 Subject: [PATCH 33/92] runtime: merge sync_tsc and wait_tsc_ack --- artiq/firmware/runtime/rtio_mgt.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a8685e1bd..abb3a4fba 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -76,14 +76,6 @@ pub mod drtio { } } - fn sync_tsc(linkno: u8) { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].set_time_write)(1); - while (csr::DRTIO[linkno].set_time_read)() == 1 {} - } - } - fn init_buffer_space(linkno: u8) { let linkidx = linkno as usize; unsafe { @@ -114,7 +106,12 @@ pub mod drtio { } } - fn wait_tsc_ack(linkno: u8, io: &Io) -> Result<(), &'static str> { + fn sync_tsc(linkno: u8, io: &Io) -> Result<(), &'static str> { + unsafe { + (csr::DRTIO[linkno as usize].set_time_write)(1); + while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {} + } + loop { let mut count = 0; if !link_rx_up(linkno) { @@ -191,8 +188,7 @@ pub mod drtio { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); init_buffer_space(linkno); - sync_tsc(linkno); - if wait_tsc_ack(linkno, &io).is_err() { + if sync_tsc(linkno, &io).is_err() { error!("[LINK#{}] remote failed to ack TSC", linkno); } else { info!("[LINK#{}] link initialization completed", linkno); From 264078baba45995a106e41879f807ce90710c71f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 22:29:35 +0800 Subject: [PATCH 34/92] style --- artiq/firmware/runtime/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c4c3f674a..e5bed91df 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -34,7 +34,7 @@ use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; use board_artiq::{mailbox, rpc_queue}; -use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; +use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; From 19a14b68b15c73b20e97fc5ce7a53d16862422ae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 22:48:56 +0800 Subject: [PATCH 35/92] runtime: program DRTIO routing table into gateware --- artiq/firmware/runtime/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index e5bed91df..b4a9454bb 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -33,6 +33,8 @@ use board_misoc::{csr, irq, ident, clock, boot, config}; use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; +#[cfg(has_drtio_routing)] +use board_artiq::drtio_routing; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; #[cfg(has_rtio_analyzer)] @@ -280,16 +282,24 @@ fn startup_ethernet() { .ip_addrs([IpCidr::new(protocol_addr, 0)]) .finalize(); + #[cfg(has_drtio_routing)] + let drtio_routing_table = drtio_routing::config_routing_table(csr::DRTIO.len()); + #[cfg(has_drtio_routing)] + drtio_routing::program_interconnect(&drtio_routing_table, 0); + let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); + #[cfg(has_rtio_core)] rtio_mgt::startup(&io); + io.spawn(4096, mgmt::thread); io.spawn(16384, session::thread); #[cfg(any(has_rtio_moninj, has_drtio))] io.spawn(4096, moninj::thread); #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); + #[cfg(has_grabber)] io.spawn(4096, grabber_thread); From 2fff96802b605ac4fa29f6264c2ab37a4bb1497f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 23:09:02 +0800 Subject: [PATCH 36/92] runtime: remove support for building without RTIO --- artiq/firmware/runtime/kern_hwreq.rs | 5 ----- artiq/firmware/runtime/main.rs | 2 -- artiq/firmware/runtime/session.rs | 17 +++++------------ 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index aae7bc99c..4e758ec8d 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,7 +1,6 @@ use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; -#[cfg(has_rtio_core)] use rtio_mgt; #[cfg(has_drtio)] @@ -292,25 +291,21 @@ mod spi { pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { match request { - #[cfg(has_rtio_core)] &kern::RtioInitRequest => { info!("resetting RTIO"); rtio_mgt::init_core(false); kern_acknowledge() } - #[cfg(has_rtio_core)] &kern::DrtioLinkStatusRequest { linkno } => { let up = rtio_mgt::drtio::link_up(linkno); kern_send(io, &kern::DrtioLinkStatusReply { up: up }) } - #[cfg(has_rtio_core)] &kern::DrtioPacketCountRequest { linkno } => { let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno); kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt }) } - #[cfg(has_rtio_core)] &kern::DrtioBufferSpaceReqCountRequest { linkno } => { let cnt = rtio_mgt::drtio_dbg::get_buffer_space_req_count(linkno); kern_send(io, &kern::DrtioBufferSpaceReqCountReply { cnt: cnt }) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b4a9454bb..4a567ed82 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -40,7 +40,6 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; -#[cfg(has_rtio_core)] mod rtio_mgt; mod urc; @@ -290,7 +289,6 @@ fn startup_ethernet() { let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - #[cfg(has_rtio_core)] rtio_mgt::startup(&io); io.spawn(4096, mgmt::thread); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d9812861b..d5a2722d2 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -7,7 +7,6 @@ use board_misoc::{ident, cache, config}; use {mailbox, rpc_queue, kernel}; use urc::Urc; use sched::{ThreadHandle, Io, TcpListener, TcpStream, Error as SchedError}; -#[cfg(has_rtio_core)] use rtio_mgt; use rtio_dma::Manager as DmaManager; use cache::Cache; @@ -517,12 +516,9 @@ fn host_kernel_worker(io: &Io, return Err(Error::WatchdogExpired(idx)) } - #[cfg(has_rtio_core)] - { - if !rtio_mgt::crg::check() { - host_write(stream, host::Reply::ClockFailure)?; - return Err(Error::ClockFailure) - } + if !rtio_mgt::crg::check() { + host_write(stream, host::Reply::ClockFailure)?; + return Err(Error::ClockFailure) } } @@ -562,11 +558,8 @@ fn flash_kernel_worker(io: &Io, return Err(Error::WatchdogExpired(idx)) } - #[cfg(has_rtio_core)] - { - if !rtio_mgt::crg::check() { - return Err(Error::ClockFailure) - } + if !rtio_mgt::crg::check() { + return Err(Error::ClockFailure) } io.relinquish()? From 3d29a7ed14b9445397368a950dea03b73a388674 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 11:27:56 +0800 Subject: [PATCH 37/92] firmware: add fmt::Display to RoutingTable --- .../firmware/libboard_artiq/drtio_routing.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index f5b7c735c..4a3a08c12 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -1,4 +1,5 @@ use board_misoc::{csr, config}; +use core::fmt; pub const DEST_COUNT: usize = 256; pub const MAX_HOPS: usize = 32; @@ -26,6 +27,26 @@ impl RoutingTable { } } +impl fmt::Display for RoutingTable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RoutingTable {{")?; + for i in 0..DEST_COUNT { + if self.0[i][0] != INVALID_HOP { + write!(f, "{}:", i)?; + for j in 0..MAX_HOPS { + if self.0[i][j] == INVALID_HOP { + break; + } + write!(f, " {}", self.0[i][j])?; + } + write!(f, ";")?; + } + } + write!(f, " }}")?; + Ok(()) + } +} + pub fn config_routing_table(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable::default_master(default_n_links); let ok = config::read("routing_table", |result| { From b38c57d73bbcd5d9b52e410b5b582e00fe032822 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 14:12:41 +0800 Subject: [PATCH 38/92] firmware: send DRTIO routing table to satellite --- .../firmware/libboard_artiq/drtio_routing.rs | 11 +-- artiq/firmware/libboard_artiq/lib.rs | 1 - .../firmware/libproto_artiq/drtioaux_proto.rs | 2 +- artiq/firmware/runtime/main.rs | 11 ++- artiq/firmware/runtime/rtio_mgt.rs | 90 +++++++++++++------ artiq/firmware/satman/main.rs | 9 +- artiq/firmware/satman/repeater.rs | 4 +- 7 files changed, 87 insertions(+), 41 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 4a3a08c12..c0242aeb7 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -5,11 +5,11 @@ pub const DEST_COUNT: usize = 256; pub const MAX_HOPS: usize = 32; pub const INVALID_HOP: u8 = 0xff; -pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]); +pub struct RoutingTable(pub [[u8; MAX_HOPS]; DEST_COUNT]); impl RoutingTable { // default routing table is for star topology with no hops - fn default_master(default_n_links: usize) -> RoutingTable { + pub fn default_master(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); for i in 0..default_n_links { ret.0[i][0] = i as u8; @@ -20,9 +20,9 @@ impl RoutingTable { ret } - // satellites receive the routing table from the master - // by default, block everything - fn default_satellite() -> RoutingTable { + // use this by default on satellite, as they receive + // the routing table from the master + pub fn default_empty() -> RoutingTable { RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) } } @@ -68,6 +68,7 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { ret } +#[cfg(has_drtio_routing)] pub fn program_interconnect(rt: &RoutingTable, rank: u8) { for i in 0..DEST_COUNT { diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 228f6ed5e..bcfdf8d9e 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -48,5 +48,4 @@ pub mod grabber; #[cfg(has_drtio)] pub mod drtioaux; -#[cfg(has_drtio_routing)] pub mod drtio_routing; diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index babb40571..e20194442 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -14,7 +14,7 @@ impl From> for Error { } } -#[derive(Debug)] +#[derive(PartialEq, Debug)] pub enum Packet { EchoRequest, EchoReply, diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 4a567ed82..555f5adce 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -25,6 +25,7 @@ extern crate board_artiq; extern crate logger_artiq; extern crate proto_artiq; +use core::cell::RefCell; use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; @@ -282,14 +283,16 @@ fn startup_ethernet() { .finalize(); #[cfg(has_drtio_routing)] - let drtio_routing_table = drtio_routing::config_routing_table(csr::DRTIO.len()); - #[cfg(has_drtio_routing)] - drtio_routing::program_interconnect(&drtio_routing_table, 0); + let drtio_routing_table = urc::Urc::new(RefCell::new( + drtio_routing::config_routing_table(csr::DRTIO.len()))); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io); + #[cfg(has_drtio_routing)] + rtio_mgt::startup(&io, &drtio_routing_table); + #[cfg(not(has_drtio_routing))] + rtio_mgt::startup(&io, &drtio_routing::RoutingTable::default_empty()); io.spawn(4096, mgmt::thread); io.spawn(16384, session::thread); diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index abb3a4fba..a70596b1d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,6 +1,9 @@ -use board_misoc::csr; +use core::cell::RefCell; +use urc::Urc; +use board_misoc::{csr, clock}; #[cfg(has_rtio_clock_switch)] use board_misoc::config; +use board_artiq::drtio_routing; use sched::Io; #[cfg(has_rtio_crg)] @@ -42,11 +45,15 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io) { + pub fn startup(io: &Io, routing_table: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } - io.spawn(4096, link_thread); + let routing_table = routing_table.clone(); + io.spawn(4096, move |io| { + let routing_table = routing_table.borrow(); + link_thread(io, &routing_table) + }); } fn link_rx_up(linkno: u8) -> bool { @@ -106,28 +113,51 @@ pub mod drtio { } } - fn sync_tsc(linkno: u8, io: &Io) -> Result<(), &'static str> { + fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result { + let max_time = clock::get_ms() + timeout as u64; + loop { + if !link_rx_up(linkno) { + return Err("link went down"); + } + if clock::get_ms() > max_time { + return Err("timeout"); + } + match drtioaux::recv_link(linkno) { + Ok(Some(packet)) => return Ok(packet), + Ok(None) => (), + Err(_) => return Err("aux packet error") + } + io.relinquish().unwrap(); + } + } + + fn sync_tsc(io: &Io, linkno: u8) -> Result<(), &'static str> { unsafe { (csr::DRTIO[linkno as usize].set_time_write)(1); while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {} } + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + let reply = recv_aux_timeout(io, linkno, 10000)?; + if reply == drtioaux::Packet::TSCAck { + return Ok(()); + } else { + return Err("unexpected reply"); + } + } - loop { - let mut count = 0; - if !link_rx_up(linkno) { - return Err("link went down"); - } - count += 1; - if count > 200 { - return Err("timeout"); - } - io.sleep(100).unwrap(); - // TSCAck is the only aux packet that is sent spontaneously - // by the satellite, in response to a TSC set on the RT link. - if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(linkno) { - return Ok(()) + fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + for i in 0..drtio_routing::DEST_COUNT { + drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath { + destination: i as u8, + hops: routing_table.0[i] + }).unwrap(); + let reply = recv_aux_timeout(io, linkno, 200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); } } + Ok(()) } fn process_local_errors(linkno: u8) { @@ -166,7 +196,7 @@ pub mod drtio { } } - pub fn link_thread(io: Io) { + pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -188,11 +218,13 @@ pub mod drtio { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); init_buffer_space(linkno); - if sync_tsc(linkno, &io).is_err() { - error!("[LINK#{}] remote failed to ack TSC", linkno); - } else { - info!("[LINK#{}] link initialization completed", linkno); + if let Err(e) = sync_tsc(&io, linkno) { + error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } + if let Err(e) = load_routing_table(&io, linkno, routing_table) { + error!("[LINK#{}] failed to load routing table ({})", linkno, e); + } + info!("[LINK#{}] link initialization completed", linkno); } else { error!("[LINK#{}] ping failed", linkno); } @@ -223,7 +255,7 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io) {} + pub fn startup(_io: &Io, _routing_table: &Urc>) {} pub fn init() {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -250,7 +282,7 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io) { +pub fn startup(io: &Io, routing_table: &Urc>) { #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -290,7 +322,13 @@ pub fn startup(io: &Io) { } } - drtio::startup(io); + #[cfg(has_drtio_routing)] + { + let routing_table = routing_table.clone(); + drtio_routing::program_interconnect(&routing_table.borrow(), 0); + } + + drtio::startup(io, &routing_table); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8ca8a6b6a..019ac767a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -96,6 +96,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error } } + drtioaux::Packet::RoutingSetPath { destination, hops } => { + info!("routing: {} -> {:?}", destination, hops); + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + drtioaux::Packet::MonitorRequest { channel, probe } => { let value; #[cfg(has_rtio_moninj)] @@ -343,8 +348,8 @@ pub extern fn main() -> i32 { } } for rep in repeaters.iter() { - if rep.sync_tsc().is_err() { - error!("remote failed to ack TSC"); + if let Err(e) = rep.sync_tsc() { + error!("failed to sync TSC ({})", e); } } if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index d677c362e..a2d17e285 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -63,8 +63,8 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); - if self.sync_tsc().is_err() { - error!("[REP#{}] remote failed to ack TSC", self.repno); + if let Err(e) = self.sync_tsc() { + error!("[REP#{}] failed to sync TSC ({})", self.repno, e); self.state = RepeaterState::Failed; return; } From f5b386c0d8734284b73ead2e0c3290ef8c099d37 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:22:45 +0800 Subject: [PATCH 39/92] firmware: fix routing table formatting --- artiq/firmware/libboard_artiq/drtio_routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index c0242aeb7..d3a7bcea7 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -32,7 +32,7 @@ impl fmt::Display for RoutingTable { write!(f, "RoutingTable {{")?; for i in 0..DEST_COUNT { if self.0[i][0] != INVALID_HOP { - write!(f, "{}:", i)?; + write!(f, " {}:", i)?; for j in 0..MAX_HOPS { if self.0[i][j] == INVALID_HOP { break; From a23af67f2bb323d851da4dd47f470fc3336df95c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:23:36 +0800 Subject: [PATCH 40/92] satman: print better debugging information on exception --- artiq/firmware/satman/main.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 019ac767a..f927681ab 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(never_type, panic_implementation, panic_info_message, const_slice_len)] +#![feature(never_type, panic_implementation, panic_info_message, const_slice_len, try_from)] #![no_std] #[macro_use] @@ -7,7 +7,8 @@ extern crate log; extern crate board_misoc; extern crate board_artiq; -use board_misoc::{csr, ident, clock, uart_logger}; +use core::convert::TryFrom; +use board_misoc::{csr, irq, ident, clock, uart_logger}; use board_artiq::{i2c, spi, si5324, drtioaux}; #[cfg(has_serwb_phy_amc)] use board_artiq::serwb; @@ -371,6 +372,23 @@ pub extern fn main() -> i32 { #[no_mangle] pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { + let vect = irq::Exception::try_from(vect).expect("unknown exception"); + + fn hexdump(addr: u32) { + let addr = (addr - addr % 4) as *const u32; + let mut ptr = addr; + println!("@ {:08p}", ptr); + for _ in 0..4 { + print!("+{:04x}: ", ptr as usize - addr as usize); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x}\n", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + } + } + + hexdump(pc); + hexdump(ea); panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) } From c0c5867f9e96ae5888e3c3ed17292c36d9916f8c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:23:51 +0800 Subject: [PATCH 41/92] satman: increase stack size Prevents crashing when running the routing code. Will have to be shrunk back on Sayma RTM. --- artiq/firmware/satman/satman.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index efae5d319..69cc737d2 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -49,7 +49,7 @@ SECTIONS .stack : { _estack = .; - . += 0x1000; + . += 0x10000; _fstack = . - 4; } > main_ram } From 2679a35082d06545c5f71ca40de1758e3e1e26b1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:28:17 +0800 Subject: [PATCH 42/92] firwmare: propagate DRTIO routing table and rank all the way --- artiq/firmware/runtime/rtio_mgt.rs | 17 +++++- artiq/firmware/satman/main.rs | 53 ++++++++++++++--- artiq/firmware/satman/repeater.rs | 91 ++++++++++++++++++++++++------ 3 files changed, 135 insertions(+), 26 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a70596b1d..a8055c943 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -146,7 +146,8 @@ pub mod drtio { } } - fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) + -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, @@ -160,6 +161,17 @@ pub mod drtio { Ok(()) } + fn set_rank(io: &Io, linkno: u8, rank: u8) -> Result<(), &'static str> { + drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetRank { + rank: rank + }).unwrap(); + let reply = recv_aux_timeout(io, linkno, 200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); + } + Ok(()) + } + fn process_local_errors(linkno: u8) { let errors; let linkidx = linkno as usize; @@ -224,6 +236,9 @@ pub mod drtio { if let Err(e) = load_routing_table(&io, linkno, routing_table) { error!("[LINK#{}] failed to load routing table ({})", linkno, e); } + if let Err(e) = set_rank(&io, linkno, 1) { + error!("[LINK#{}] failed to set rank ({})", linkno, e); + } info!("[LINK#{}] link initialization completed", linkno); } else { error!("[LINK#{}] ping failed", linkno); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index f927681ab..12bb9d945 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -12,6 +12,7 @@ use board_misoc::{csr, irq, ident, clock, uart_logger}; use board_artiq::{i2c, spi, si5324, drtioaux}; #[cfg(has_serwb_phy_amc)] use board_artiq::serwb; +use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; @@ -45,7 +46,9 @@ fn drtiosat_tsc_loaded() -> bool { } } -fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { +fn process_aux_packet(_repeaters: &mut [repeater::Repeater], + _routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8, + packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. match packet { @@ -97,8 +100,40 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error } } + #[cfg(has_drtio_routing)] drtioaux::Packet::RoutingSetPath { destination, hops } => { - info!("routing: {} -> {:?}", destination, hops); + _routing_table.0[destination as usize] = hops; + for rep in _repeaters.iter() { + if let Err(e) = rep.set_path(destination, &hops) { + error!("failed to set path ({})", e); + } + } + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + #[cfg(has_drtio_routing)] + drtioaux::Packet::RoutingSetRank { rank } => { + *_rank = rank; + drtio_routing::program_interconnect(_routing_table, rank); + + let rep_rank = rank + 1; + for rep in _repeaters.iter() { + if let Err(e) = rep.set_rank(rep_rank) { + error!("failed to set rank ({})", e); + } + } + + info!("rank: {}", rank); + info!("routing table: {}", _routing_table); + + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + + #[cfg(not(has_drtio_routing))] + drtioaux::Packet::RoutingSetPath { _destination, _hops } => { + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + #[cfg(not(has_drtio_routing))] + drtioaux::Packet::RoutingSetRank { _rank } => { drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } @@ -197,11 +232,12 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error } } -fn process_aux_packets() { +fn process_aux_packets(repeaters: &mut [repeater::Repeater], + routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8) { let result = drtioaux::recv_link(0).and_then(|packet| { if let Some(packet) = packet { - process_aux_packet(packet) + process_aux_packet(repeaters, routing_table, rank, packet) } else { Ok(()) } @@ -291,16 +327,17 @@ pub extern fn main() -> i32 { let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; #[cfg(not(has_drtio_routing))] let mut repeaters = [repeater::Repeater::default(); 0]; - for i in 0..repeaters.len() { repeaters[i] = repeater::Repeater::new(i as u8); } + let mut routing_table = drtio_routing::RoutingTable::default_empty(); + let mut rank = 1; loop { while !drtiosat_link_rx_up() { drtiosat_process_errors(); for mut rep in repeaters.iter_mut() { - rep.service(); + rep.service(&routing_table, rank); } } @@ -333,9 +370,9 @@ pub extern fn main() -> i32 { while drtiosat_link_rx_up() { drtiosat_process_errors(); - process_aux_packets(); + process_aux_packets(&mut repeaters, &mut routing_table, &mut rank); for mut rep in repeaters.iter_mut() { - rep.service(); + rep.service(&routing_table, rank); } if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index a2d17e285..4c2dd7287 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -1,5 +1,5 @@ use board_misoc::{csr, clock}; -use board_artiq::drtioaux; +use board_artiq::{drtioaux, drtio_routing}; #[cfg(has_drtio_routing)] fn rep_link_rx_up(linkno: u8) -> bool { @@ -39,7 +39,7 @@ impl Repeater { } } - pub fn service(&mut self) { + pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { match self.state { RepeaterState::Down => { if rep_link_rx_up(self.repno) { @@ -63,13 +63,22 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); + self.state = RepeaterState::Up; if let Err(e) = self.sync_tsc() { error!("[REP#{}] failed to sync TSC ({})", self.repno, e); self.state = RepeaterState::Failed; return; } - // TODO: send routing table and rank - self.state = RepeaterState::Up; + if let Err(e) = self.load_routing_table(routing_table) { + error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + self.state = RepeaterState::Failed; + return; + } + if let Err(e) = self.set_rank(rank) { + error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + self.state = RepeaterState::Failed; + return; + } } else { if clock::get_ms() > timeout { if ping_count > 200 { @@ -100,6 +109,23 @@ impl Repeater { } } + fn recv_aux_timeout(&self, timeout: u32) -> Result { + let max_time = clock::get_ms() + timeout as u64; + loop { + if !rep_link_rx_up(self.repno) { + return Err("link went down"); + } + if clock::get_ms() > max_time { + return Err("timeout"); + } + match drtioaux::recv_link(self.auxno) { + Ok(Some(packet)) => return Ok(packet), + Ok(None) => (), + Err(_) => return Err("aux packet error") + } + } + } + pub fn sync_tsc(&self) -> Result<(), &'static str> { if self.state != RepeaterState::Up { return Ok(()); @@ -111,21 +137,52 @@ impl Repeater { while (csr::DRTIOREP[repno].set_time_read)() == 1 {} } - let timeout = clock::get_ms() + 200; - loop { - if !rep_link_rx_up(self.repno) { - return Err("link went down"); - } - if clock::get_ms() > timeout { - return Err("timeout"); - } - // TSCAck is the only aux packet that is sent spontaneously - // by the satellite, in response to a TSC set on the RT link. - if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(self.auxno) { - return Ok(()); - } + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + let reply = self.recv_aux_timeout(10000)?; + if reply == drtioaux::Packet::TSCAck { + return Ok(()); + } else { + return Err("unexpected reply"); } } + + pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + + drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetPath { + destination: destination, + hops: *hops + }).unwrap(); + let reply = self.recv_aux_timeout(200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); + } + Ok(()) + } + + pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + for i in 0..drtio_routing::DEST_COUNT { + self.set_path(i as u8, &routing_table.0[i])?; + } + Ok(()) + } + + pub fn set_rank(&self, rank: u8) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetRank { + rank: rank + }).unwrap(); + let reply = self.recv_aux_timeout(200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); + } + Ok(()) + } } #[cfg(not(has_drtio_routing))] From e6bd835b5d713f9d57e4da39aa22736ec389d2d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 20:04:51 +0800 Subject: [PATCH 43/92] satman: fix rank setting --- artiq/firmware/satman/repeater.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 4c2dd7287..052fe47ad 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -74,7 +74,7 @@ impl Repeater { self.state = RepeaterState::Failed; return; } - if let Err(e) = self.set_rank(rank) { + if let Err(e) = self.set_rank(rank + 1) { error!("[REP#{}] failed to sync TSC ({})", self.repno, e); self.state = RepeaterState::Failed; return; From 36e3fedfc6726b5068d11da3d5a1d132fe285d7d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 20:10:33 +0800 Subject: [PATCH 44/92] runtime: print routing table at boot --- artiq/firmware/libboard_artiq/drtio_routing.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index d3a7bcea7..4302cd880 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -64,7 +64,8 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { }); if !ok { warn!("could not read routing table from configuration, using default"); - } + } + info!("routing table: {}", ret); ret } From 5439abaa9d940f47e20f6c4aea1a53806c1c381a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 20:10:52 +0800 Subject: [PATCH 45/92] satman: fix error messages --- artiq/firmware/satman/repeater.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 052fe47ad..c58d4b846 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -70,12 +70,12 @@ impl Repeater { return; } if let Err(e) = self.load_routing_table(routing_table) { - error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + error!("[REP#{}] failed to load routing table ({})", self.repno, e); self.state = RepeaterState::Failed; return; } if let Err(e) = self.set_rank(rank + 1) { - error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + error!("[REP#{}] failed to set rank ({})", self.repno, e); self.state = RepeaterState::Failed; return; } From 251b9a2b0d04bfab5894098324be3479a8322376 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:17:57 +0800 Subject: [PATCH 46/92] drtio: do not lock up master when satellite repeatedly fails to answer buffer space reqs --- artiq/gateware/drtio/rt_controller_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index fa2efd457..a1e4f11c9 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -189,7 +189,7 @@ class RTController(Module): timeout_counter.wait.eq(1), If(timeout_counter.done, signal_buffer_space_timeout.eq(1), - NextState("GET_BUFFER_SPACE") + NextState("IDLE") ) ) fsm.act("READ", From 051bafbfd973fe6938d7a6f59984c0b033d6caeb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:18:42 +0800 Subject: [PATCH 47/92] drtio: ensure 2 cycles between frames on the link This gives time for setting chan_sel before cmd on CRI. --- artiq/gateware/drtio/rt_packet_master.py | 4 ++++ artiq/gateware/drtio/rt_packet_repeater.py | 4 ++++ artiq/gateware/test/drtio/test_rt_packet_repeater.py | 3 +++ 3 files changed, 11 insertions(+) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 45ffe1278..42370a09d 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -208,6 +208,10 @@ class RTPacketMaster(Module): self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) tx_fsm.act("IDLE", + # Ensure 2 cycles between frames on the link. + NextState("READY") + ) + tx_fsm.act("READY", If(sr_buf_readable, If(sr_notwrite, Case(sr_address[0], { diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 5ccd8dd70..1798b6da8 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -110,6 +110,10 @@ class RTPacketRepeater(Module): self.submodules += tx_fsm tx_fsm.act("IDLE", + # Ensure 2 cycles between frames on the link. + NextState("READY") + ) + tx_fsm.act("READY", If(self.set_time_stb, tsc_value_load.eq(1), NextState("SET_TIME") diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index d348a5efc..70f25adb0 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -27,6 +27,7 @@ class TestRepeater(unittest.TestCase): pt, pr, ts, dut = create_dut(nwords) def send(): + yield yield ts.eq(0x12345678) yield dut.set_time_stb.eq(1) while not (yield dut.set_time_ack): @@ -61,6 +62,7 @@ class TestRepeater(unittest.TestCase): pt, pr, ts, dut = create_dut(nwords) def send(): + yield for channel, timestamp, address, data in test_writes: yield dut.cri.chan_sel.eq(channel) yield dut.cri.timestamp.eq(timestamp) @@ -96,6 +98,7 @@ class TestRepeater(unittest.TestCase): def send_requests(): for i in range(10): + yield yield dut.cri.chan_sel.eq(i << 16) yield dut.cri.cmd.eq(cri.commands["get_buffer_space"]) yield From 41972d67739e4f0b4fb2da0630ae7307803b6207 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:19:55 +0800 Subject: [PATCH 48/92] drtio: rt_packet_satellite CRI fixes --- artiq/gateware/drtio/rt_packet_satellite.py | 36 ++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 1656f41cd..4aba55dcb 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -79,18 +79,25 @@ class RTPacketSatellite(Module): ] # RX FSM - read = Signal() + cri_read = Signal() + cri_buffer_space = Signal() self.comb += [ self.tsc_load_value.eq( rx_dp.packet_as["set_time"].timestamp), - If(load_read_request | read_request_pending, + If(cri_read | read_request_pending, self.cri.chan_sel.eq( rx_dp.packet_as["read_request"].chan_sel), - self.cri.timestamp.eq( - rx_dp.packet_as["read_request"].timeout) + ).Elif(cri_buffer_space, + self.cri.chan_sel.eq( + rx_dp.packet_as["buffer_space_request"].destination << 16) ).Else( self.cri.chan_sel.eq( rx_dp.packet_as["write"].chan_sel), + ), + If(cri_read | read_request_pending, + self.cri.timestamp.eq( + rx_dp.packet_as["read_request"].timeout) + ).Else( self.cri.timestamp.eq( rx_dp.packet_as["write"].timestamp) ), @@ -139,8 +146,7 @@ class RTPacketSatellite(Module): rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, - self.cri.cmd.eq(cri.commands["write"]), - NextState("INPUT") + NextState("WRITE_CMD") ).Else( write_data_buffer_load.eq(1), If(~rx_dp.frame_r, @@ -149,7 +155,17 @@ class RTPacketSatellite(Module): ) ) ) + rx_fsm.act("WRITE_CMD", + self.cri.cmd.eq(cri.commands["write"]), + NextState("INPUT") + ) + rx_fsm.act("BUFFER_SPACE_REQUEST", + cri_buffer_space.eq(1), + NextState("BUFFER_SPACE_REQUEST_CMD") + ) + rx_fsm.act("BUFFER_SPACE_REQUEST_CMD", + cri_buffer_space.eq(1), self.cri.cmd.eq(cri.commands["get_buffer_space"]), NextState("BUFFER_SPACE") ) @@ -158,8 +174,7 @@ class RTPacketSatellite(Module): If(timeout_counter.done, self.buffer_space_timeout.eq(1), NextState("INPUT") - ), - If(self.cri.o_buffer_space_valid, + ).Elif(self.cri.o_buffer_space_valid, buffer_space_set.eq(1), buffer_space_update.eq(1), NextState("INPUT") @@ -167,7 +182,12 @@ class RTPacketSatellite(Module): ) rx_fsm.act("READ_REQUEST", + cri_read.eq(1), + NextState("READ_REQUEST_CMD") + ) + rx_fsm.act("READ_REQUEST_CMD", load_read_request.eq(1), + cri_read.eq(1), self.cri.cmd.eq(cri.commands["read"]), NextState("INPUT") ) From 8227037a84293727f50a6e9dbee361eeae6bcffb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:20:18 +0800 Subject: [PATCH 49/92] examples: add kasli_drtioswitching --- .../kasli_drtioswitching/device_db.py | 34 +++++++++++++++++++ .../kasli_drtioswitching/repository/blink.py | 17 ++++++++++ 2 files changed, 51 insertions(+) create mode 100644 artiq/examples/kasli_drtioswitching/device_db.py create mode 100644 artiq/examples/kasli_drtioswitching/repository/blink.py diff --git a/artiq/examples/kasli_drtioswitching/device_db.py b/artiq/examples/kasli_drtioswitching/device_db.py new file mode 100644 index 000000000..f04ee1869 --- /dev/null +++ b/artiq/examples/kasli_drtioswitching/device_db.py @@ -0,0 +1,34 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, +} + +for i in range(3): + device_db["led" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": i << 16}, + } diff --git a/artiq/examples/kasli_drtioswitching/repository/blink.py b/artiq/examples/kasli_drtioswitching/repository/blink.py new file mode 100644 index 000000000..e5068efda --- /dev/null +++ b/artiq/examples/kasli_drtioswitching/repository/blink.py @@ -0,0 +1,17 @@ +from artiq.experiment import * + + +class Blink(EnvExperiment): + def build(self): + self.setattr_device("core") + self.leds = [self.get_device("led0"), self.get_device("led2")] + + @kernel + def run(self): + while True: + self.core.reset() + + while True: + for led in self.leds: + led.pulse(200*ms) + delay(200*ms) From 95432a4ac140a93366b68dbd2725bfcdd699c1b6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 13:01:27 +0800 Subject: [PATCH 50/92] drtio: remove old debugging features --- artiq/coredevice/drtio_dbg.py | 17 ----------- artiq/firmware/ksupport/api.rs | 2 -- artiq/firmware/ksupport/rtio.rs | 15 ---------- artiq/firmware/libproto_artiq/kernel_proto.rs | 5 ---- artiq/firmware/runtime/kern_hwreq.rs | 9 ------ artiq/firmware/runtime/rtio_mgt.rs | 28 ------------------- artiq/gateware/drtio/core.py | 4 +-- artiq/gateware/drtio/rt_controller_master.py | 23 --------------- artiq/gateware/test/drtio/test_full_stack.py | 21 +++++++------- 9 files changed, 11 insertions(+), 113 deletions(-) delete mode 100644 artiq/coredevice/drtio_dbg.py diff --git a/artiq/coredevice/drtio_dbg.py b/artiq/coredevice/drtio_dbg.py deleted file mode 100644 index 56482c6dc..000000000 --- a/artiq/coredevice/drtio_dbg.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -DRTIO debugging functions. - -Those syscalls are intended for ARTIQ developers only. -""" - -from artiq.language.core import syscall -from artiq.language.types import TTuple, TInt32, TInt64, TNone - - -@syscall(flags={"nounwind", "nowrite"}) -def drtio_get_packet_counts(linkno: TInt32) -> TTuple([TInt32, TInt32]): - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nounwind", "nowrite"}) -def drtio_get_fifo_space_req_count(linkno: TInt32) -> TInt32: - raise NotImplementedError("syscall not simulated") diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 77d8b1edc..c1a0c22ff 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -109,8 +109,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_playback = ::dma_playback), api!(drtio_get_link_status = ::rtio::drtio::get_link_status), - api!(drtio_get_packet_counts = ::rtio::drtio::get_packet_counts), - api!(drtio_get_buffer_space_req_count = ::rtio::drtio::get_buffer_space_req_count), api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 123d15d07..119fab8f5 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -219,19 +219,4 @@ pub mod drtio { send(&DrtioLinkStatusRequest { linkno: linkno as u8 }); recv!(&DrtioLinkStatusReply { up } => up) } - - #[repr(C)] - pub struct PacketCounts(i32, i32); - - pub extern fn get_packet_counts(linkno: i32) -> PacketCounts { - send(&DrtioPacketCountRequest { linkno: linkno as u8 }); - recv!(&DrtioPacketCountReply { tx_cnt, rx_cnt } - => PacketCounts(tx_cnt as i32, rx_cnt as i32)) - } - - pub extern fn get_buffer_space_req_count(linkno: i32) -> i32 { - send(&DrtioBufferSpaceReqCountRequest { linkno: linkno as u8 }); - recv!(&DrtioBufferSpaceReqCountReply { cnt } - => cnt as i32) - } } diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index ae794ec34..477c00a1b 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -49,11 +49,6 @@ pub enum Message<'a> { DrtioLinkStatusRequest { linkno: u8 }, DrtioLinkStatusReply { up: bool }, - DrtioPacketCountRequest { linkno: u8 }, - DrtioPacketCountReply { tx_cnt: u32, rx_cnt: u32 }, - DrtioBufferSpaceReqCountRequest { linkno: u8 }, - DrtioBufferSpaceReqCountReply { cnt: u32 }, - RunFinished, RunException { exception: Exception<'a>, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 4e758ec8d..c1bfbf7b0 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -302,15 +302,6 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result { - let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno); - kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt }) - } - &kern::DrtioBufferSpaceReqCountRequest { linkno } => { - let cnt = rtio_mgt::drtio_dbg::get_buffer_space_req_count(linkno); - kern_send(io, &kern::DrtioBufferSpaceReqCountReply { cnt: cnt }) - } - &kern::I2cStartRequest { busno } => { let succeeded = i2c::start(busno).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a8055c943..4f9b6d718 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -357,31 +357,3 @@ pub fn init_core(phy: bool) { } drtio::init() } - -#[cfg(has_drtio)] -pub mod drtio_dbg { - use board_misoc::csr; - - pub fn get_packet_counts(linkno: u8) -> (u32, u32) { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].update_packet_cnt_write)(1); - ((csr::DRTIO[linkno].packet_cnt_tx_read)(), - (csr::DRTIO[linkno].packet_cnt_rx_read)()) - } - } - - pub fn get_buffer_space_req_count(linkno: u8) -> u32 { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].o_dbg_buffer_space_req_cnt_read)() - } - } -} - -#[cfg(not(has_drtio))] -pub mod drtio_dbg { - pub fn get_packet_counts(_linkno: u8) -> (u32, u32) { (0, 0) } - - pub fn get_buffer_space_req_count(_linkno: u8) -> u32 { 0 } -} diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index b3d722825..52e2bb948 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -161,13 +161,11 @@ class DRTIOMaster(Module): self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( tsc, self.rt_packet) - self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + - self.rt_controller.get_csrs() + - self.rt_manager.get_csrs()) + self.rt_controller.get_csrs()) @property def cri(self): diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index a1e4f11c9..473d2126d 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -220,26 +220,3 @@ class RTController(Module): def get_csrs(self): return self.csrs.get_csrs() - - -class RTManager(Module, AutoCSR): - def __init__(self, rt_packet): - self.request_echo = CSR() - - self.update_packet_cnt = CSR() - self.packet_cnt_tx = CSRStatus(32) - self.packet_cnt_rx = CSRStatus(32) - - # # # - - self.comb += self.request_echo.w.eq(rt_packet.echo_stb) - self.sync += [ - If(rt_packet.echo_ack, rt_packet.echo_stb.eq(0)), - If(self.request_echo.re, rt_packet.echo_stb.eq(1)) - ] - - self.sync += \ - If(self.update_packet_cnt.re, - self.packet_cnt_tx.status.eq(rt_packet.packet_cnt_tx), - self.packet_cnt_rx.status.eq(rt_packet.packet_cnt_rx) - ) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 69f89b094..8a23b2db9 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -291,26 +291,25 @@ class TestFullStack(unittest.TestCase): def test_echo(self): dut = DUT(2) - csrs = dut.master.rt_controller.csrs - mgr = dut.master.rt_manager + packet = dut.master.rt_packet def test(): while not (yield from dut.master.link_layer.rx_up.read()): yield - yield from mgr.update_packet_cnt.write(1) - yield - self.assertEqual((yield from mgr.packet_cnt_tx.read()), 0) - self.assertEqual((yield from mgr.packet_cnt_rx.read()), 0) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_tx), 0) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_rx), 0) - yield from mgr.request_echo.write(1) + yield dut.master.rt_packet.echo_stb.eq(1) + yield + while not (yield dut.master.rt_packet.echo_ack): + yield + yield dut.master.rt_packet.echo_stb.eq(0) for i in range(15): yield - yield from mgr.update_packet_cnt.write(1) - yield - self.assertEqual((yield from mgr.packet_cnt_tx.read()), 1) - self.assertEqual((yield from mgr.packet_cnt_rx.read()), 1) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_tx), 1) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_rx), 1) run_simulation(dut, test(), self.clocks) From edf403b837258ce42ed91886579ac82d85629e9f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 15:44:34 +0800 Subject: [PATCH 51/92] drtio: improve error reporting --- artiq/firmware/satman/main.rs | 6 ++- artiq/firmware/satman/repeater.rs | 39 +++++++++++++++++-- artiq/gateware/drtio/core.py | 2 +- .../gateware/drtio/rt_controller_repeater.py | 25 +++++++++--- artiq/gateware/drtio/rt_errors_satellite.py | 7 +++- artiq/gateware/drtio/rt_packet_repeater.py | 6 +-- artiq/gateware/drtio/rt_packet_satellite.py | 2 + 7 files changed, 71 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 12bb9d945..56345ae7a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -260,7 +260,11 @@ fn drtiosat_process_errors() { error!("received truncated packet"); } if errors & 4 != 0 { - error!("timeout attempting to get buffer space from CRI") + let destination; + unsafe { + destination = csr::drtiosat::buffer_space_timeout_dest_read(); + } + error!("timeout attempting to get buffer space from CRI, destination=0x{:02x}", destination) } if errors & 8 != 0 { let channel; diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index c58d4b846..6f5b7b28f 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -2,10 +2,10 @@ use board_misoc::{csr, clock}; use board_artiq::{drtioaux, drtio_routing}; #[cfg(has_drtio_routing)] -fn rep_link_rx_up(linkno: u8) -> bool { - let linkno = linkno as usize; +fn rep_link_rx_up(repno: u8) -> bool { + let repno = repno as usize; unsafe { - (csr::DRTIOREP[linkno].rx_up_read)() == 1 + (csr::DRTIOREP[repno].rx_up_read)() == 1 } } @@ -40,6 +40,8 @@ impl Repeater { } pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { + self.process_errors(); + match self.state { RepeaterState::Down => { if rep_link_rx_up(self.repno) { @@ -109,6 +111,37 @@ impl Repeater { } } + fn process_errors(&self) { + let repno = self.repno as usize; + let errors; + unsafe { + errors = (csr::DRTIOREP[repno].protocol_error_read)(); + } + if errors & 1 != 0 { + error!("[REP#{}] received packet of an unknown type", repno); + } + if errors & 2 != 0 { + error!("[REP#{}] received truncated packet", repno); + } + if errors & 4 != 0 { + let chan_sel; + unsafe { + chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)(); + } + error!("[REP#{}] CRI command missed, chan_sel=0x{:06x}", repno, chan_sel) + } + if errors & 8 != 0 { + let destination; + unsafe { + destination = (csr::DRTIOREP[repno].buffer_space_timeout_dest_read)(); + } + error!("[REP#{}] timeout attempting to get remote buffer space, destination=0x{:02x}", repno, destination); + } + unsafe { + (csr::DRTIOREP[repno].protocol_error_write)(errors); + } + } + fn recv_aux_timeout(&self, timeout: u32) -> Result { let max_time = clock::get_ms() + timeout as u64; loop { diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 52e2bb948..55176b1ce 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -143,7 +143,7 @@ class DRTIOSatellite(Module): ] self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, tsc, self.cri, self.async_errors) + self.rt_packet, tsc, self.async_errors) def get_csrs(self): return ([self.reset, self.reset_phy, self.tsc_loaded] + diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index d75e87f64..655bf641e 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -10,6 +10,8 @@ class RTController(Module, AutoCSR): def __init__(self, rt_packet): self.set_time = CSR() self.protocol_error = CSR(4) + self.command_missed_chan_sel = CSRStatus(24) + self.buffer_space_timeout_dest = CSRStatus(8) set_time_stb = Signal() set_time_ack = Signal() @@ -23,14 +25,21 @@ class RTController(Module, AutoCSR): self.comb += self.set_time.w.eq(set_time_stb) errors = [ - (rt_packet.err_unknown_packet_type, "rtio_rx"), - (rt_packet.err_packet_truncated, "rtio_rx"), - (rt_packet.err_command_missed, "rtio"), - (rt_packet.err_buffer_space_timeout, "rtio") + (rt_packet.err_unknown_packet_type, "rtio_rx", None, None), + (rt_packet.err_packet_truncated, "rtio_rx", None, None), + (rt_packet.err_command_missed, "rtio", + rt_packet.cri.chan_sel, self.command_missed_chan_sel.status), + (rt_packet.err_buffer_space_timeout, "rtio", + rt_packet.buffer_space_destination, self.buffer_space_timeout_dest.status) ] - for n, (err_i, err_cd) in enumerate(errors): - xfer = BlindTransfer(err_cd, "sys") + for n, (err_i, err_cd, din, dout) in enumerate(errors): + if din is not None: + data_width = len(din) + else: + data_width = 0 + + xfer = BlindTransfer(err_cd, "sys", data_width=data_width) self.submodules += xfer self.comb += xfer.i.eq(err_i) @@ -41,3 +50,7 @@ class RTController(Module, AutoCSR): If(xfer.o, err_pending.eq(1)) ] self.comb += self.protocol_error.w[n].eq(err_pending) + + if din is not None: + self.comb += xfer.data_i.eq(din) + self.sync += If(xfer.o & ~err_pending, dout.eq(xfer.data_o)) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 2bf190a0f..1d857654c 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,11 +7,12 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, tsc, cri, async_errors): + def __init__(self, rt_packet, tsc, async_errors): self.protocol_error = CSR(5) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) self.underflow_timestamp_counter = CSRStatus(64) + self.buffer_space_timeout_dest = CSRStatus(8) self.rtio_error = CSR(3) self.sequence_error_channel = CSRStatus(16) @@ -47,6 +48,7 @@ class RTErrorsSatellite(Module, AutoCSR): self.comb += xfer.data_i.eq(din) self.sync += If(xfer.o & ~pending, dout.eq(xfer.data_o)) + cri = rt_packet.cri # The master is normally responsible for avoiding output overflows # and output underflows. The error reports here are only for diagnosing @@ -68,7 +70,8 @@ class RTErrorsSatellite(Module, AutoCSR): error_csr(self.protocol_error, (rt_packet.unknown_packet_type, False, None, None), (rt_packet.packet_truncated, False, None, None), - (rt_packet.buffer_space_timeout, False, None, None), + (rt_packet.buffer_space_timeout, False, + cri.chan_sel[16:], self.buffer_space_timeout_dest.status), (underflow, True, underflow_error_cri, underflow_error_csr), (overflow, True, None, None) ) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 1798b6da8..0ecd353a8 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -20,6 +20,7 @@ class RTPacketRepeater(Module): # in rtio domain self.err_command_missed = Signal() self.err_buffer_space_timeout = Signal() + self.buffer_space_destination = Signal(8) # set_time interface, in rtio domain self.set_time_stb = Signal() @@ -85,9 +86,8 @@ class RTPacketRepeater(Module): ) # Buffer space - buffer_space_destination = Signal(8) self.sync.rtio += If(self.cri.cmd == cri.commands["get_buffer_space"], - buffer_space_destination.eq(self.cri.chan_sel[16:])) + self.buffer_space_destination.eq(self.cri.chan_sel[16:])) rx_buffer_space_not = Signal() rx_buffer_space = Signal(16) @@ -153,7 +153,7 @@ class RTPacketRepeater(Module): ) ) tx_fsm.act("BUFFER_SPACE", - tx_dp.send("buffer_space_request", destination=buffer_space_destination), + tx_dp.send("buffer_space_request", destination=self.buffer_space_destination), If(tx_dp.packet_last, buffer_space_not_ack.eq(1), NextState("WAIT_BUFFER_SPACE") diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 4aba55dcb..49ea2c3d0 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -144,6 +144,7 @@ class RTPacketSatellite(Module): NextState("INPUT") ) + # CRI mux defaults to write information rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, NextState("WRITE_CMD") @@ -170,6 +171,7 @@ class RTPacketSatellite(Module): NextState("BUFFER_SPACE") ) rx_fsm.act("BUFFER_SPACE", + cri_buffer_space.eq(1), timeout_counter.wait.eq(1), If(timeout_counter.done, self.buffer_space_timeout.eq(1), From 5bcd40ff59d9b2048875f9f6ba9f8ee31e6dbf4b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 17:30:55 +0800 Subject: [PATCH 52/92] cri: fix routing table depth --- artiq/gateware/rtio/cri.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 18ca1956b..0ed0d50e2 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -130,7 +130,7 @@ class CRIDecoder(Module, AutoCSR): selected = Signal(slave_bits) if enable_routing: - self.specials.routing_table = Memory(slave_bits, 8) + self.specials.routing_table = Memory(slave_bits, 256) rtp_csr = self.routing_table.get_port(write_capable=True) self.specials += rtp_csr From e36a8536d7fb0e390acd1517fc7c6a14e06e7904 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 17:31:23 +0800 Subject: [PATCH 53/92] runtime: better handling of aux timeouts --- artiq/firmware/runtime/rtio_mgt.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 4f9b6d718..093b37d79 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -193,9 +193,9 @@ pub mod drtio { } } - fn process_aux_errors(linkno: u8) { + fn process_aux_errors(io: &Io, linkno: u8) { drtioaux::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); - match drtioaux::recv_timeout_link(linkno, None) { + match recv_aux_timeout(io, linkno, 200) { Ok(drtioaux::Packet::RtioNoErrorReply) => (), Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), @@ -204,7 +204,7 @@ pub mod drtio { Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) => error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel), Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno), - Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e) + Err(e) => error!("[LINK#{}] communication failed ({})", linkno, e) } } @@ -216,7 +216,7 @@ pub mod drtio { /* link was previously up */ if link_rx_up(linkno) { process_local_errors(linkno); - process_aux_errors(linkno); + process_aux_errors(&io, linkno); } else { info!("[LINK#{}] link is down", linkno); set_link_up(linkno, false); From 420e1cb1d0676a0dd0b3c5187fb33adb595e4125 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 18:08:16 +0800 Subject: [PATCH 54/92] cri: fix firmware routing table access --- .../firmware/libboard_artiq/drtio_routing.rs | 4 +-- artiq/gateware/rtio/__init__.py | 2 +- artiq/gateware/rtio/cri.py | 34 +++++++++++-------- artiq/gateware/targets/kasli.py | 4 +++ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 4302cd880..c78b5cddd 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -75,8 +75,8 @@ pub fn program_interconnect(rt: &RoutingTable, rank: u8) for i in 0..DEST_COUNT { let hop = rt.0[i][rank as usize]; unsafe { - csr::cri_con::routing_destination_write(i as _); - csr::cri_con::routing_hop_write(hop); + csr::routing_table::destination_write(i as _); + csr::routing_table::hop_write(hop); } } } diff --git a/artiq/gateware/rtio/__init__.py b/artiq/gateware/rtio/__init__.py index a144f593c..af4989f7c 100644 --- a/artiq/gateware/rtio/__init__.py +++ b/artiq/gateware/rtio/__init__.py @@ -1,5 +1,5 @@ from artiq.gateware.rtio.tsc import TSC -from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared +from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared, RoutingTableAccess from artiq.gateware.rtio.channel import Channel, LogChannel from artiq.gateware.rtio.core import Core from artiq.gateware.rtio.analyzer import Analyzer diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 0ed0d50e2..b60164ba2 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -119,28 +119,15 @@ class CRIDecoder(Module, AutoCSR): self.slaves = slaves self.master = master - slave_bits = bits_for(len(slaves)-1) - if enable_routing: - self.routing_destination = CSRStorage(8) - self.routing_hop = CSR(slave_bits) - # # # # routing + slave_bits = bits_for(len(slaves)-1) selected = Signal(slave_bits) if enable_routing: self.specials.routing_table = Memory(slave_bits, 256) - rtp_csr = self.routing_table.get_port(write_capable=True) - self.specials += rtp_csr - self.comb += [ - rtp_csr.adr.eq(self.routing_destination.storage), - rtp_csr.dat_w.eq(self.routing_hop.r), - rtp_csr.we.eq(self.routing_hop.re), - self.routing_hop.w.eq(rtp_csr.dat_r) - ] - if mode == "async": rtp_decoder = self.routing_table.get_port() elif mode == "sync": @@ -220,3 +207,22 @@ class CRIInterconnectShared(Module): def get_csrs(self): return self.switch.get_csrs() + self.decoder.get_csrs() + + +class RoutingTableAccess(Module, AutoCSR): + def __init__(self, interconnect): + if isinstance(interconnect, CRIInterconnectShared): + interconnect = interconnect.decoder + + rtp_csr = interconnect.routing_table.get_port(write_capable=True) + self.specials += rtp_csr + + self.destination = CSRStorage(8) + self.hop = CSR(len(rtp_csr.dat_w)) + + self.comb += [ + rtp_csr.adr.eq(self.destination.storage), + rtp_csr.dat_w.eq(self.hop.r), + rtp_csr.we.eq(self.hop.re), + self.hop.w.eq(rtp_csr.dat_r) + ] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 75c3fa5e9..9070bf241 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -730,6 +730,8 @@ class _MasterBase(MiniSoC, AMPSoC): [self.rtio_core.cri] + self.drtio_cri, enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.cri_con.switch.slave, self.get_native_sdram_if()) @@ -900,6 +902,8 @@ class _SatelliteBase(BaseSoC): [self.local_io.cri] + self.drtio_cri, mode="sync", enable_routing=True) self.csr_devices.append("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") class Master(_MasterBase): From 0befec7d26671eb486ed50100d09a9e18966d632 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 20:54:01 +0800 Subject: [PATCH 55/92] drtio: improve repeater error reports --- artiq/firmware/satman/repeater.rs | 4 +++- artiq/gateware/drtio/rt_controller_repeater.py | 4 +++- artiq/gateware/drtio/rt_packet_repeater.py | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 6f5b7b28f..889e4aba7 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -124,11 +124,13 @@ impl Repeater { error!("[REP#{}] received truncated packet", repno); } if errors & 4 != 0 { + let cmd; let chan_sel; unsafe { + cmd = (csr::DRTIOREP[repno].command_missed_cmd_read)(); chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)(); } - error!("[REP#{}] CRI command missed, chan_sel=0x{:06x}", repno, chan_sel) + error!("[REP#{}] CRI command missed, cmd={}, chan_sel=0x{:06x}", repno, cmd, chan_sel) } if errors & 8 != 0 { let destination; diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index 655bf641e..b877700b1 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -10,6 +10,7 @@ class RTController(Module, AutoCSR): def __init__(self, rt_packet): self.set_time = CSR() self.protocol_error = CSR(4) + self.command_missed_cmd = CSRStatus(2) self.command_missed_chan_sel = CSRStatus(24) self.buffer_space_timeout_dest = CSRStatus(8) @@ -28,7 +29,8 @@ class RTController(Module, AutoCSR): (rt_packet.err_unknown_packet_type, "rtio_rx", None, None), (rt_packet.err_packet_truncated, "rtio_rx", None, None), (rt_packet.err_command_missed, "rtio", - rt_packet.cri.chan_sel, self.command_missed_chan_sel.status), + Cat(rt_packet.command_missed_cmd, rt_packet.command_missed_chan_sel), + Cat(self.command_missed_cmd.status, self.command_missed_chan_sel.status)), (rt_packet.err_buffer_space_timeout, "rtio", rt_packet.buffer_space_destination, self.buffer_space_timeout_dest.status) ] diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 0ecd353a8..7f709589f 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -19,6 +19,8 @@ class RTPacketRepeater(Module): # in rtio domain self.err_command_missed = Signal() + self.command_missed_cmd = Signal(2) + self.command_missed_chan_sel = Signal(24) self.err_buffer_space_timeout = Signal() self.buffer_space_destination = Signal(8) @@ -103,7 +105,11 @@ class RTPacketRepeater(Module): # Missed commands cri_ready = Signal() - self.sync.rtio += self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + self.sync.rtio += [ + self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])), + self.command_missed_chan_sel.eq(self.cri.chan_sel), + self.command_missed_cmd.eq(self.cri.cmd) + ] # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) From 5a9cc004f2f62f81a89a2749b3b00ad65d5772d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 22:57:21 +0800 Subject: [PATCH 56/92] drtio: receive and print unsolicited aux packets Helps with debugging and prevents the aux channel from getting stuck after packets arrive after the timeout. --- artiq/firmware/runtime/rtio_mgt.rs | 9 +++++++++ artiq/firmware/satman/repeater.rs | 13 +++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 093b37d79..ea34792c4 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -172,6 +172,14 @@ pub mod drtio { Ok(()) } + fn process_unsolicited_aux(linkno: u8) { + match drtioaux::recv_link(linkno) { + Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), + Ok(None) => (), + Err(_) => warn!("[LINK#{}] aux packet error", linkno) + } + } + fn process_local_errors(linkno: u8) { let errors; let linkidx = linkno as usize; @@ -215,6 +223,7 @@ pub mod drtio { if link_up(linkno) { /* link was previously up */ if link_rx_up(linkno) { + process_unsolicited_aux(linkno); process_local_errors(linkno); process_aux_errors(&io, linkno); } else { diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 889e4aba7..9b1f39849 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -40,7 +40,7 @@ impl Repeater { } pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { - self.process_errors(); + self.process_local_errors(); match self.state { RepeaterState::Down => { @@ -97,6 +97,7 @@ impl Repeater { } } RepeaterState::Up => { + self.process_unsolicited_aux(); if !rep_link_rx_up(self.repno) { info!("[REP#{}] link is down", self.repno); self.state = RepeaterState::Down; @@ -111,7 +112,15 @@ impl Repeater { } } - fn process_errors(&self) { + fn process_unsolicited_aux(&self) { + match drtioaux::recv_link(self.auxno) { + Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet), + Ok(None) => (), + Err(_) => warn!("[REP#{}] aux packet error", self.repno) + } + } + + fn process_local_errors(&self) { let repno = self.repno as usize; let errors; unsafe { From 6cf3db3485f8241c2cefa7744c9944b59b407573 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 23:02:54 +0800 Subject: [PATCH 57/92] satman: forward RTIO resets --- artiq/firmware/satman/main.rs | 6 ++++++ artiq/firmware/satman/repeater.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 56345ae7a..e8c0b60f4 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -55,6 +55,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::Packet::EchoRequest => drtioaux::send_link(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { + info!("resetting RTIO"); if phy { drtiosat_reset_phy(true); drtiosat_reset_phy(false); @@ -62,6 +63,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtiosat_reset(true); drtiosat_reset(false); } + for rep in _repeaters.iter() { + if let Err(e) = rep.rtio_reset(phy) { + error!("failed to issue RTIO reset ({})", e); + } + } drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 9b1f39849..bd2fe8999 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -227,6 +227,20 @@ impl Repeater { } Ok(()) } + + pub fn rtio_reset(&self, phy: bool) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + drtioaux::send_link(self.auxno, &drtioaux::Packet::ResetRequest { + phy: phy + }).unwrap(); + let reply = self.recv_aux_timeout(200)?; + if reply != drtioaux::Packet::ResetAck { + return Err("unexpected reply"); + } + Ok(()) + } } #[cfg(not(has_drtio_routing))] From fa872c33414f0b758a46c356de7069adf7aa8b1c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 12:00:29 +0800 Subject: [PATCH 58/92] firmware: implement DRTIO destination survey --- artiq/firmware/libboard_artiq/drtioaux.rs | 15 +++- .../firmware/libproto_artiq/drtioaux_proto.rs | 46 ++++++---- artiq/firmware/runtime/rtio_mgt.rs | 67 +++++++++++--- artiq/firmware/satman/main.rs | 89 +++++++++++++------ artiq/firmware/satman/repeater.rs | 36 +++++--- 5 files changed, 175 insertions(+), 78 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 9c189e148..d176e67da 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -10,14 +10,21 @@ pub use proto_artiq::drtioaux_proto::Packet; // this is parametric over T because there's no impl Fail for !. #[derive(Fail, Debug)] pub enum Error { - #[fail(display = "packet CRC failed")] - CorruptedPacket, - #[fail(display = "timed out waiting for data")] - TimedOut, #[fail(display = "invalid node number")] NoRoute, + #[fail(display = "gateware reported error")] GatewareError, + #[fail(display = "packet CRC failed")] + CorruptedPacket, + + #[fail(display = "link is down")] + LinkDown, + #[fail(display = "timed out waiting for data")] + TimedOut, + #[fail(display = "unexpected reply")] + UnexpectedReply, + #[fail(display = "protocol error: {}", _0)] Protocol(#[cause] ProtocolError) } diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index e20194442..044f9b80e 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -22,11 +22,12 @@ pub enum Packet { ResetAck, TSCAck, - RtioErrorRequest, - RtioNoErrorReply, - RtioErrorSequenceErrorReply { channel: u16 }, - RtioErrorCollisionReply { channel: u16 }, - RtioErrorBusyReply { channel: u16 }, + DestinationStatusRequest { destination: u8 }, + DestinationDownReply, + DestinationOkReply, + DestinationSequenceErrorReply { channel: u16 }, + DestinationCollisionReply { channel: u16 }, + DestinationBusyReply { channel: u16 }, RoutingSetPath { destination: u8, hops: [u8; 32] }, RoutingSetRank { rank: u8 }, @@ -67,15 +68,18 @@ impl Packet { 0x03 => Packet::ResetAck, 0x04 => Packet::TSCAck, - 0x20 => Packet::RtioErrorRequest, - 0x21 => Packet::RtioNoErrorReply, - 0x22 => Packet::RtioErrorSequenceErrorReply { + 0x20 => Packet::DestinationStatusRequest { + destination: reader.read_u8()? + }, + 0x21 => Packet::DestinationDownReply, + 0x22 => Packet::DestinationOkReply, + 0x23 => Packet::DestinationSequenceErrorReply { channel: reader.read_u16()? }, - 0x23 => Packet::RtioErrorCollisionReply { + 0x24 => Packet::DestinationCollisionReply { channel: reader.read_u16()? }, - 0x24 => Packet::RtioErrorBusyReply { + 0x25 => Packet::DestinationBusyReply { channel: reader.read_u16()? }, @@ -186,22 +190,26 @@ impl Packet { Packet::TSCAck => writer.write_u8(0x04)?, - Packet::RtioErrorRequest => - writer.write_u8(0x20)?, - Packet::RtioNoErrorReply => - writer.write_u8(0x21)?, - Packet::RtioErrorSequenceErrorReply { channel } => { - writer.write_u8(0x22)?; - writer.write_u16(channel)?; + Packet::DestinationStatusRequest {destination } => { + writer.write_u8(0x20)?; + writer.write_u8(destination)?; }, - Packet::RtioErrorCollisionReply { channel } => { + Packet::DestinationDownReply => + writer.write_u8(0x21)?, + Packet::DestinationOkReply => + writer.write_u8(0x22)?, + Packet::DestinationSequenceErrorReply { channel } => { writer.write_u8(0x23)?; writer.write_u16(channel)?; }, - Packet::RtioErrorBusyReply { channel } => { + Packet::DestinationCollisionReply { channel } => { writer.write_u8(0x24)?; writer.write_u16(channel)?; }, + Packet::DestinationBusyReply { channel } => { + writer.write_u8(0x25)?; + writer.write_u16(channel)?; + }, Packet::RoutingSetPath { destination, hops } => { writer.write_u8(0x30)?; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index ea34792c4..c6ba76d43 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -201,22 +201,63 @@ pub mod drtio { } } - fn process_aux_errors(io: &Io, linkno: u8) { - drtioaux::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); - match recv_aux_timeout(io, linkno, 200) { - Ok(drtioaux::Packet::RtioNoErrorReply) => (), - Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => - error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), - Ok(drtioaux::Packet::RtioErrorCollisionReply { channel }) => - error!("[LINK#{}] RTIO collision involving channel {}", linkno, channel), - Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) => - error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel), - Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno), - Err(e) => error!("[LINK#{}] communication failed ({})", linkno, e) + fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, + up_destinations: &mut [bool; drtio_routing::DEST_COUNT]) { + for destination in 0..drtio_routing::DEST_COUNT { + let hop = routing_table.0[destination][0]; + + if hop == 0 { + /* local RTIO */ + up_destinations[destination] = true; + } else if hop as usize <= csr::DRTIO.len() { + let linkno = hop - 1; + if up_destinations[destination] { + if link_up(linkno) { + drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + destination: destination as u8 + }).unwrap(); + match recv_aux_timeout(io, linkno, 200) { + Ok(drtioaux::Packet::DestinationDownReply) => { + info!("[DEST#{}] destination is down", destination); + up_destinations[destination] = false; + }, + Ok(drtioaux::Packet::DestinationOkReply) => (), + Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => + error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel), + Ok(drtioaux::Packet::DestinationCollisionReply { channel }) => + error!("[DEST#{}] RTIO collision involving channel 0x{:04x}", destination, channel), + Ok(drtioaux::Packet::DestinationBusyReply { channel }) => + error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}", destination, channel), + Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), + Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) + } + } else { + info!("[DEST#{}] destination is down", destination); + up_destinations[destination] = false; + } + } else { + if link_up(linkno) { + drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + destination: destination as u8 + }).unwrap(); + match recv_aux_timeout(io, linkno, 200) { + Ok(drtioaux::Packet::DestinationDownReply) => (), + Ok(drtioaux::Packet::DestinationOkReply) => { + info!("[DEST#{}] destination is up", destination); + up_destinations[destination] = true; + /* TODO: get buffer space */ + }, + Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), + Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) + } + } + } + } } } pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { + let mut up_destinations = [false; drtio_routing::DEST_COUNT]; loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -225,7 +266,6 @@ pub mod drtio { if link_rx_up(linkno) { process_unsolicited_aux(linkno); process_local_errors(linkno); - process_aux_errors(&io, linkno); } else { info!("[LINK#{}] link is down", linkno); set_link_up(linkno, false); @@ -255,6 +295,7 @@ pub mod drtio { } } } + destination_survey(&io, routing_table, &mut up_destinations); io.sleep(200).unwrap(); } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e8c0b60f4..8e3b22e7d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -71,39 +71,70 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, - drtioaux::Packet::RtioErrorRequest => { - let errors; - unsafe { - errors = csr::drtiosat::rtio_error_read(); - } - if errors & 1 != 0 { - let channel; + drtioaux::Packet::DestinationStatusRequest { destination } => { + #[cfg(has_drtio_routing)] + let hop = _routing_table.0[destination as usize][*_rank as usize]; + #[cfg(not(has_drtio_routing))] + let hop = 0; + + if hop == 0 { + let errors; unsafe { - channel = csr::drtiosat::sequence_error_channel_read(); - csr::drtiosat::rtio_error_write(1); + errors = csr::drtiosat::rtio_error_read(); } - drtioaux::send_link(0, - &drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) - } else if errors & 2 != 0 { - let channel; - unsafe { - channel = csr::drtiosat::collision_channel_read(); - csr::drtiosat::rtio_error_write(2); + if errors & 1 != 0 { + let channel; + unsafe { + channel = csr::drtiosat::sequence_error_channel_read(); + csr::drtiosat::rtio_error_write(1); + } + drtioaux::send_link(0, + &drtioaux::Packet::DestinationSequenceErrorReply { channel })?; + } else if errors & 2 != 0 { + let channel; + unsafe { + channel = csr::drtiosat::collision_channel_read(); + csr::drtiosat::rtio_error_write(2); + } + drtioaux::send_link(0, + &drtioaux::Packet::DestinationCollisionReply { channel })?; + } else if errors & 4 != 0 { + let channel; + unsafe { + channel = csr::drtiosat::busy_channel_read(); + csr::drtiosat::rtio_error_write(4); + } + drtioaux::send_link(0, + &drtioaux::Packet::DestinationBusyReply { channel })?; } - drtioaux::send_link(0, - &drtioaux::Packet::RtioErrorCollisionReply { channel }) - } else if errors & 4 != 0 { - let channel; - unsafe { - channel = csr::drtiosat::busy_channel_read(); - csr::drtiosat::rtio_error_write(4); + else { + drtioaux::send_link(0, &drtioaux::Packet::DestinationOkReply)?; } - drtioaux::send_link(0, - &drtioaux::Packet::RtioErrorBusyReply { channel }) } - else { - drtioaux::send_link(0, &drtioaux::Packet::RtioNoErrorReply) + + #[cfg(has_drtio_routing)] + { + if hop != 0 { + let hop = hop as usize; + if hop <= csr::DRTIOREP.len() { + let repno = hop - 1; + match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest { + destination: destination + }) { + Ok(()) => (), + Err(drtioaux::Error::LinkDown) => drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?, + Err(e) => { + drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + error!("aux error when handling destination status request: {}", e); + }, + } + } else { + drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + } + } } + + Ok(()) } #[cfg(has_drtio_routing)] @@ -135,11 +166,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetPath { _destination, _hops } => { + drtioaux::Packet::RoutingSetPath { destination, hops } => { drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetRank { _rank } => { + drtioaux::Packet::RoutingSetRank { rank } => { drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index bd2fe8999..c97ece3e5 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -153,24 +153,34 @@ impl Repeater { } } - fn recv_aux_timeout(&self, timeout: u32) -> Result { + fn recv_aux_timeout(&self, timeout: u32) -> Result> { let max_time = clock::get_ms() + timeout as u64; loop { if !rep_link_rx_up(self.repno) { - return Err("link went down"); + return Err(drtioaux::Error::LinkDown); } if clock::get_ms() > max_time { - return Err("timeout"); + return Err(drtioaux::Error::TimedOut); } match drtioaux::recv_link(self.auxno) { Ok(Some(packet)) => return Ok(packet), Ok(None) => (), - Err(_) => return Err("aux packet error") + Err(e) => return Err(e) } } } - pub fn sync_tsc(&self) -> Result<(), &'static str> { + pub fn aux_forward(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error> { + if self.state != RepeaterState::Up { + return Err(drtioaux::Error::LinkDown); + } + drtioaux::send_link(self.auxno, request).unwrap(); + let reply = self.recv_aux_timeout(200)?; + drtioaux::send_link(0, &reply).unwrap(); + Ok(()) + } + + pub fn sync_tsc(&self) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -187,11 +197,11 @@ impl Repeater { if reply == drtioaux::Packet::TSCAck { return Ok(()); } else { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } } - pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), &'static str> { + pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -202,19 +212,19 @@ impl Repeater { }).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::RoutingAck { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } Ok(()) } - pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable) -> Result<(), drtioaux::Error> { for i in 0..drtio_routing::DEST_COUNT { self.set_path(i as u8, &routing_table.0[i])?; } Ok(()) } - pub fn set_rank(&self, rank: u8) -> Result<(), &'static str> { + pub fn set_rank(&self, rank: u8) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -223,12 +233,12 @@ impl Repeater { }).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::RoutingAck { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } Ok(()) } - pub fn rtio_reset(&self, phy: bool) -> Result<(), &'static str> { + pub fn rtio_reset(&self, phy: bool) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -237,7 +247,7 @@ impl Repeater { }).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::ResetAck { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } Ok(()) } From 042b0065de036737641d7052d9d1e1efa79dcd74 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 14:10:52 +0800 Subject: [PATCH 59/92] runtime: print destination up message for local RTIO --- artiq/firmware/runtime/rtio_mgt.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index c6ba76d43..f9df23b38 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -208,7 +208,10 @@ pub mod drtio { if hop == 0 { /* local RTIO */ - up_destinations[destination] = true; + if !up_destinations[destination] { + info!("[DEST#{}] destination is up", destination); + up_destinations[destination] = true; + } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; if up_destinations[destination] { From e95638e0a73f7ac3daf65565d856b3ee13275edb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 15:54:28 +0800 Subject: [PATCH 60/92] style --- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 044f9b80e..288913282 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -190,7 +190,7 @@ impl Packet { Packet::TSCAck => writer.write_u8(0x04)?, - Packet::DestinationStatusRequest {destination } => { + Packet::DestinationStatusRequest { destination } => { writer.write_u8(0x20)?; writer.write_u8(destination)?; }, From 1ef39a98a7ae605c659fea980673afdd8281051f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 16:16:32 +0800 Subject: [PATCH 61/92] drtio: implement per-destination buffer space --- artiq/firmware/runtime/rtio_mgt.rs | 26 +++++++------- artiq/gateware/drtio/rt_controller_master.py | 36 ++++++++++++++++---- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f9df23b38..2153e9986 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -83,16 +83,6 @@ pub mod drtio { } } - fn init_buffer_space(linkno: u8) { - let linkidx = linkno as usize; - unsafe { - (csr::DRTIO[linkidx].o_get_buffer_space_write)(1); - while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} - info!("[LINK#{}] buffer space is {}", - linkno, (csr::DRTIO[linkidx].o_dbg_buffer_space_read)()); - } - } - fn ping_remote(linkno: u8, io: &Io) -> u32 { let mut count = 0; loop { @@ -172,6 +162,19 @@ pub mod drtio { Ok(()) } + fn init_buffer_space(destination: u8, linkno: u8) { + let linkno = linkno as usize; + unsafe { + (csr::DRTIO[linkno].destination_write)(destination); + (csr::DRTIO[linkno].force_destination_write)(1); + (csr::DRTIO[linkno].o_get_buffer_space_write)(1); + while (csr::DRTIO[linkno].o_wait_read)() == 1 {} + info!("[DEST#{}] buffer space is {}", + destination, (csr::DRTIO[linkno].o_dbg_buffer_space_read)()); + (csr::DRTIO[linkno].force_destination_write)(0); + } + } + fn process_unsolicited_aux(linkno: u8) { match drtioaux::recv_link(linkno) { Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), @@ -248,7 +251,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationOkReply) => { info!("[DEST#{}] destination is up", destination); up_destinations[destination] = true; - /* TODO: get buffer space */ + init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) @@ -281,7 +284,6 @@ pub mod drtio { if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); - init_buffer_space(linkno); if let Err(e) = sync_tsc(&io, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 473d2126d..d1e0dd1e2 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -19,6 +19,9 @@ class _CSRs(AutoCSR): self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=300) + self.force_destination = CSRStorage() + self.destination = CSRStorage(8) + self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -71,11 +74,17 @@ class RTController(Module): If(self.csrs.set_time.re, rt_packet.set_time_stb.eq(1)) ] + # chan_sel forcing + chan_sel = Signal(24) + self.comb += chan_sel.eq(Mux(self.csrs.force_destination.storage, + self.csrs.destination.storage << 16, + self.cri.chan_sel)) + # common packet fields rt_packet_buffer_request = Signal() rt_packet_read_request = Signal() self.comb += [ - rt_packet.sr_chan_sel.eq(self.cri.chan_sel), + rt_packet.sr_chan_sel.eq(chan_sel), rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_data.eq(self.cri.o_data), rt_packet.sr_timestamp.eq(self.cri.timestamp), @@ -112,7 +121,22 @@ class RTController(Module): self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) - buffer_space = Signal(16) + # buffer space + buffer_space = Memory(16, 256) + buffer_space_port = buffer_space.get_port(write_capable=True) + self.specials += buffer_space, buffer_space_port + + buffer_space_load = Signal() + buffer_space_dec = Signal() + self.comb += [ + buffer_space_port.adr.eq(chan_sel[16:]), + buffer_space_port.we.eq(buffer_space_load | buffer_space_dec), + If(buffer_space_load, + buffer_space_port.dat_w.eq(rt_packet.buffer_space) + ).Else( + buffer_space_port.dat_w.eq(buffer_space_port.dat_r - 1) + ) + ] # input status i_status_wait_event = Signal() @@ -158,8 +182,8 @@ class RTController(Module): o_status_wait.eq(1), rt_packet.sr_stb.eq(1), If(rt_packet.sr_ack, - NextValue(buffer_space, buffer_space - 1), - If(buffer_space <= 1, + buffer_space_dec.eq(1), + If(buffer_space_port.dat_r <= 1, NextState("GET_BUFFER_SPACE") ).Else( NextState("IDLE") @@ -177,7 +201,7 @@ class RTController(Module): ) fsm.act("GET_BUFFER_SPACE_REPLY", o_status_wait.eq(1), - NextValue(buffer_space, rt_packet.buffer_space), + buffer_space_load.eq(1), rt_packet.buffer_space_not_ack.eq(1), If(rt_packet.buffer_space_not, If(rt_packet.buffer_space != 0, @@ -211,7 +235,7 @@ class RTController(Module): ) # debug CSRs - self.comb += self.csrs.o_dbg_buffer_space.status.eq(buffer_space), + self.comb += self.csrs.o_dbg_buffer_space.status.eq(buffer_space_port.dat_r), self.sync += \ If((rt_packet.sr_stb & rt_packet.sr_ack & rt_packet_buffer_request), self.csrs.o_dbg_buffer_space_req_cnt.status.eq( From ae72e3a51efaf472eca899b704109b50c9503508 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:26:39 +0800 Subject: [PATCH 62/92] firmware: add support for moninj and kern_hwreq over DRTIO switching --- artiq/firmware/libboard_artiq/drtioaux.rs | 29 +- .../firmware/libproto_artiq/drtioaux_proto.rs | 66 +++-- artiq/firmware/runtime/kern_hwreq.rs | 255 ++++++----------- artiq/firmware/runtime/main.rs | 18 +- artiq/firmware/runtime/moninj.rs | 264 +++++++++--------- artiq/firmware/runtime/session.rs | 28 +- artiq/firmware/satman/main.rs | 54 +++- 7 files changed, 332 insertions(+), 382 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index d176e67da..a0465b230 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -10,9 +10,6 @@ pub use proto_artiq::drtioaux_proto::Packet; // this is parametric over T because there's no impl Fail for !. #[derive(Fail, Debug)] pub enum Error { - #[fail(display = "invalid node number")] - NoRoute, - #[fail(display = "gateware reported error")] GatewareError, #[fail(display = "packet CRC failed")] @@ -25,6 +22,9 @@ pub enum Error { #[fail(display = "unexpected reply")] UnexpectedReply, + #[fail(display = "routing error")] + RoutingError, + #[fail(display = "protocol error: {}", _0)] Protocol(#[cause] ProtocolError) } @@ -150,26 +150,3 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { Ok(writer.position()) }) } - -// TODO: routing -fn get_linkno(nodeno: u8) -> Result> { - if nodeno == 0 || nodeno as usize > DRTIOAUX.len() { - return Err(Error::NoRoute) - } - Ok(nodeno - 1) -} - -pub fn recv(nodeno: u8) -> Result, Error> { - let linkno = get_linkno(nodeno)?; - recv_link(linkno) -} - -pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result> { - let linkno = get_linkno(nodeno)?; - recv_timeout_link(linkno, timeout_ms) -} - -pub fn send(nodeno: u8, packet: &Packet) -> Result<(), Error> { - let linkno = get_linkno(nodeno)?; - send_link(linkno, packet) -} diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 288913282..3d526734d 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -33,24 +33,24 @@ pub enum Packet { RoutingSetRank { rank: u8 }, RoutingAck, - MonitorRequest { channel: u16, probe: u8 }, + MonitorRequest { destination: u8, channel: u16, probe: u8 }, MonitorReply { value: u32 }, - InjectionRequest { channel: u16, overrd: u8, value: u8 }, - InjectionStatusRequest { channel: u16, overrd: u8 }, + InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 }, + InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 }, InjectionStatusReply { value: u8 }, - I2cStartRequest { busno: u8 }, - I2cRestartRequest { busno: u8 }, - I2cStopRequest { busno: u8 }, - I2cWriteRequest { busno: u8, data: u8 }, + I2cStartRequest { destination: u8, busno: u8 }, + I2cRestartRequest { destination: u8, busno: u8 }, + I2cStopRequest { destination: u8, busno: u8 }, + I2cWriteRequest { destination: u8, busno: u8, data: u8 }, I2cWriteReply { succeeded: bool, ack: bool }, - I2cReadRequest { busno: u8, ack: bool }, + I2cReadRequest { destination: u8, busno: u8, ack: bool }, I2cReadReply { succeeded: bool, data: u8 }, I2cBasicReply { succeeded: bool }, - SpiSetConfigRequest { busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, - SpiWriteRequest { busno: u8, data: u32 }, - SpiReadRequest { busno: u8 }, + SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, + SpiWriteRequest { destination: u8, busno: u8, data: u32 }, + SpiReadRequest { destination: u8, busno: u8 }, SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, } @@ -98,6 +98,7 @@ impl Packet { 0x32 => Packet::RoutingAck, 0x40 => Packet::MonitorRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, probe: reader.read_u8()? }, @@ -105,11 +106,13 @@ impl Packet { value: reader.read_u32()? }, 0x50 => Packet::InjectionRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, overrd: reader.read_u8()?, value: reader.read_u8()? }, 0x51 => Packet::InjectionStatusRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, overrd: reader.read_u8()? }, @@ -118,15 +121,19 @@ impl Packet { }, 0x80 => Packet::I2cStartRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x81 => Packet::I2cRestartRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x82 => Packet::I2cStopRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x83 => Packet::I2cWriteRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, data: reader.read_u8()? }, @@ -135,6 +142,7 @@ impl Packet { ack: reader.read_bool()? }, 0x85 => Packet::I2cReadRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, ack: reader.read_bool()? }, @@ -147,6 +155,7 @@ impl Packet { }, 0x90 => Packet::SpiSetConfigRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, flags: reader.read_u8()?, length: reader.read_u8()?, @@ -155,10 +164,12 @@ impl Packet { }, /* 0x91: was Packet::SpiSetXferRequest */ 0x92 => Packet::SpiWriteRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, data: reader.read_u32()? }, 0x93 => Packet::SpiReadRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x94 => Packet::SpiReadReply { @@ -223,8 +234,9 @@ impl Packet { Packet::RoutingAck => writer.write_u8(0x32)?, - Packet::MonitorRequest { channel, probe } => { + Packet::MonitorRequest { destination, channel, probe } => { writer.write_u8(0x40)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(probe)?; }, @@ -232,14 +244,16 @@ impl Packet { writer.write_u8(0x41)?; writer.write_u32(value)?; }, - Packet::InjectionRequest { channel, overrd, value } => { + Packet::InjectionRequest { destination, channel, overrd, value } => { writer.write_u8(0x50)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(overrd)?; writer.write_u8(value)?; }, - Packet::InjectionStatusRequest { channel, overrd } => { + Packet::InjectionStatusRequest { destination, channel, overrd } => { writer.write_u8(0x51)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(overrd)?; }, @@ -248,20 +262,24 @@ impl Packet { writer.write_u8(value)?; }, - Packet::I2cStartRequest { busno } => { + Packet::I2cStartRequest { destination, busno } => { writer.write_u8(0x80)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cRestartRequest { busno } => { + Packet::I2cRestartRequest { destination, busno } => { writer.write_u8(0x81)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cStopRequest { busno } => { + Packet::I2cStopRequest { destination, busno } => { writer.write_u8(0x82)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cWriteRequest { busno, data } => { + Packet::I2cWriteRequest { destination, busno, data } => { writer.write_u8(0x83)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u8(data)?; }, @@ -270,8 +288,9 @@ impl Packet { writer.write_bool(succeeded)?; writer.write_bool(ack)?; }, - Packet::I2cReadRequest { busno, ack } => { + Packet::I2cReadRequest { destination, busno, ack } => { writer.write_u8(0x85)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_bool(ack)?; }, @@ -285,21 +304,24 @@ impl Packet { writer.write_bool(succeeded)?; }, - Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { writer.write_u8(0x90)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u8(flags)?; writer.write_u8(length)?; writer.write_u8(div)?; writer.write_u8(cs)?; }, - Packet::SpiWriteRequest { busno, data } => { + Packet::SpiWriteRequest { destination, busno, data } => { writer.write_u8(0x92)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u32(data)?; }, - Packet::SpiReadRequest { busno } => { + Packet::SpiReadRequest { destination, busno } => { writer.write_u8(0x93)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, Packet::SpiReadReply { succeeded, data } => { diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index c1bfbf7b0..00d20be3b 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -2,13 +2,16 @@ use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; +use board_artiq::drtio_routing; +use board_artiq::i2c as local_i2c; +use board_artiq::spi as local_spi; #[cfg(has_drtio)] -mod drtio_i2c { +mod remote_i2c { use drtioaux; - fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(nodeno, None) { + fn basic_reply(linkno: u8) -> Result<(), ()> { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -23,39 +26,49 @@ mod drtio_i2c { } } - pub fn start(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStartRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn start(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cStartRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn restart(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cRestartRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn restart(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cRestartRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn stop(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStopRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn stop(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cStopRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn write(nodeno: u8, busno: u8, data: u8) -> Result { + pub fn write(linkno: u8, destination: u8, busno: u8, data: u8) -> Result { let request = drtioaux::Packet::I2cWriteRequest { + destination: destination, busno: busno, data: data }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -70,15 +83,16 @@ mod drtio_i2c { } } - pub fn read(nodeno: u8, busno: u8, ack: bool) -> Result { + pub fn read(linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { let request = drtioaux::Packet::I2cReadRequest { + destination: destination, busno: busno, ack: ack }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -94,90 +108,12 @@ mod drtio_i2c { } } -#[cfg(not(has_drtio))] -mod drtio_i2c { - pub fn start(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn restart(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn stop(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn write(_nodeno: u8, _busno: u8, _data: u8) -> Result { - Err(()) - } - - pub fn read(_nodeno: u8, _busno: u8, _ack: bool) -> Result { - Err(()) - } -} - -mod i2c { - use board_artiq::i2c as local_i2c; - use super::drtio_i2c; - - pub fn start(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::start(node_busno) - } else { - drtio_i2c::start(nodeno, node_busno) - } - } - - pub fn restart(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::restart(node_busno) - } else { - drtio_i2c::restart(nodeno, node_busno) - } - } - - pub fn stop(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::stop(node_busno) - } else { - drtio_i2c::stop(nodeno, node_busno) - } - } - - pub fn write(busno: u32, data: u8) -> Result { - let nodeno = (busno >> 16 )as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::write(node_busno, data) - } else { - drtio_i2c::write(nodeno, node_busno, data) - } - } - - pub fn read(busno: u32, ack: bool) -> Result { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::read(node_busno, ack) - } else { - drtio_i2c::read(nodeno, node_busno, ack) - } - } -} - #[cfg(has_drtio)] -mod drtio_spi { +mod remote_spi { use drtioaux; - fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(nodeno, None) { + fn basic_reply(linkno: u8) -> Result<(), ()> { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -192,37 +128,42 @@ mod drtio_spi { } } - pub fn set_config(nodeno: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { + pub fn set_config(linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { let request = drtioaux::Packet::SpiSetConfigRequest { + destination: destination, busno: busno, flags: flags, length: length, div: div, cs: cs }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn write(nodeno: u8, busno: u8, data: u32) -> Result<(), ()> { + pub fn write(linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { let request = drtioaux::Packet::SpiWriteRequest { + destination: destination, busno: busno, data: data }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn read(nodeno: u8, busno: u8) -> Result { - let request = drtioaux::Packet::SpiReadRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn read(linkno: u8, destination: u8, busno: u8) -> Result { + let request = drtioaux::Packet::SpiReadRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -238,58 +179,32 @@ mod drtio_spi { } } + +#[cfg(has_drtio)] +macro_rules! dispatch { + ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + let destination = ($busno >> 16) as u8; + let busno = $busno as u8; + let hop = $routing_table.0[destination as usize][0]; + if hop == 0 { + $mod_local::$func(busno, $($param, )*) + } else { + let linkno = hop - 1; + $mod_remote::$func(linkno, destination, busno, $($param, )*) + } + }} +} + #[cfg(not(has_drtio))] -mod drtio_spi { - pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, - _length: u8, _div: u8, _cs: u8) -> Result<(), ()> { - Err(()) - } - - pub fn write(_nodeno: u8, _busno: u8, _data: u32) -> Result<(), ()> { - Err(()) - } - - pub fn read(_nodeno: u8, _busno: u8) -> Result { - Err(()) - } +macro_rules! dispatch { + ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + let busno = $busno as u8; + $mod_local::$func(busno, $($param, )*) + }} } -mod spi { - use board_artiq::spi as local_spi; - use super::drtio_spi; - - pub fn set_config(busno: u32, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::set_config(node_busno, flags, length, div, cs) - } else { - drtio_spi::set_config(nodeno, node_busno, flags, length, div, cs) - } - } - - pub fn write(busno: u32, data: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::write(node_busno, data) - } else { - drtio_spi::write(nodeno, node_busno, data) - } - } - - pub fn read(busno: u32) -> Result { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::read(node_busno) - } else { - drtio_spi::read(nodeno, node_busno) - } - } -} - -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { +pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, + request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { info!("resetting RTIO"); @@ -303,40 +218,42 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result { - let succeeded = i2c::start(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cRestartRequest { busno } => { - let succeeded = i2c::restart(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cStopRequest { busno } => { - let succeeded = i2c::stop(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cWriteRequest { busno, data } => { - match i2c::write(busno, data) { + match dispatch!(local_i2c, remote_i2c, _routing_table, busno, write, data) { Ok(ack) => kern_send(io, &kern::I2cWriteReply { succeeded: true, ack: ack }), Err(_) => kern_send(io, &kern::I2cWriteReply { succeeded: false, ack: false }) } } &kern::I2cReadRequest { busno, ack } => { - match i2c::read(busno, ack) { + match dispatch!(local_i2c, remote_i2c, _routing_table, busno, read, ack) { Ok(data) => kern_send(io, &kern::I2cReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff }) } } &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { - let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); + let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + set_config, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, &kern::SpiWriteRequest { busno, data } => { - let succeeded = spi::write(busno, data).is_ok(); + let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + write, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) } &kern::SpiReadRequest { busno } => { - match spi::read(busno) { + match dispatch!(local_spi, remote_spi, _routing_table, busno, read) { Ok(data) => kern_send(io, &kern::SpiReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::SpiReadReply { succeeded: false, data: 0 }) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 555f5adce..16f0fca05 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -282,22 +282,28 @@ fn startup_ethernet() { .ip_addrs([IpCidr::new(protocol_addr, 0)]) .finalize(); - #[cfg(has_drtio_routing)] + #[cfg(has_drtio)] let drtio_routing_table = urc::Urc::new(RefCell::new( drtio_routing::config_routing_table(csr::DRTIO.len()))); + #[cfg(not(has_drtio))] + let drtio_routing_table = urc::Urc::new(RefCell::new( + drtio_routing::RoutingTable::default_empty())); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - #[cfg(has_drtio_routing)] rtio_mgt::startup(&io, &drtio_routing_table); - #[cfg(not(has_drtio_routing))] - rtio_mgt::startup(&io, &drtio_routing::RoutingTable::default_empty()); io.spawn(4096, mgmt::thread); - io.spawn(16384, session::thread); + { + let drtio_routing_table = drtio_routing_table.clone(); + io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table) }); + } #[cfg(any(has_rtio_moninj, has_drtio))] - io.spawn(4096, moninj::thread); + { + let drtio_routing_table = drtio_routing_table.clone(); + io.spawn(4096, move |io| { moninj::thread(io, &drtio_routing_table) }); + } #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 665927e39..a1a0765ac 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,151 +1,137 @@ use alloc::btree_map::BTreeMap; +use core::cell::RefCell; use io::Error as IoError; use moninj_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; -use board_misoc::{clock, csr}; -#[cfg(has_drtio)] -use drtioaux; +use urc::Urc; +use board_misoc::clock; +use board_artiq::drtio_routing; #[cfg(has_rtio_moninj)] -fn read_probe_local(channel: u16, probe: u8) -> u32 { - unsafe { - csr::rtio_moninj::mon_chan_sel_write(channel as _); - csr::rtio_moninj::mon_probe_sel_write(probe); - csr::rtio_moninj::mon_value_update_write(1); - csr::rtio_moninj::mon_value_read() as u32 +mod local_moninj { + use board_misoc::csr; + + pub fn read_probe(channel: u16, probe: u8) -> u32 { + unsafe { + csr::rtio_moninj::mon_chan_sel_write(channel as _); + csr::rtio_moninj::mon_probe_sel_write(probe); + csr::rtio_moninj::mon_value_update_write(1); + csr::rtio_moninj::mon_value_read() as u32 + } + } + + pub fn inject(channel: u16, overrd: u8, value: u8) { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_write(value); + } + } + + pub fn read_injection_status(channel: u16, overrd: u8) -> u8 { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_read() + } + } +} + +#[cfg(not(has_rtio_moninj))] +mod local_moninj { + pub fn read_probe(_channel: u16, _probe: u8) -> u32 { 0 } + + pub fn inject(_channel: u16, _overrd: u8, _value: u8) { } + + pub fn read_injection_status(_channel: u16, _overrd: u8) -> u8 { 0 } +} + +#[cfg(has_drtio)] +mod remote_moninj { + use drtioaux; + + pub fn read_probe(linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { + let request = drtioaux::Packet::MonitorRequest { + destination: destination, + channel: channel, + probe: probe + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => { + error!("aux packet error ({})", e); + return 0; + } + } + match drtioaux::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::MonitorReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + 0 + } + + pub fn inject(linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { + let request = drtioaux::Packet::InjectionRequest { + destination: destination, + channel: channel, + overrd: overrd, + value: value + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => error!("aux packet error ({})", e) + } + } + + pub fn read_injection_status(linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { + let request = drtioaux::Packet::InjectionStatusRequest { + destination: destination, + channel: channel, + overrd: overrd + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => { + error!("aux packet error ({})", e); + return 0; + } + } + match drtioaux::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + 0 } } #[cfg(has_drtio)] -fn read_probe_drtio(nodeno: u8, channel: u16, probe: u8) -> u32 { - let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; +macro_rules! dispatch { + ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + let destination = ($channel >> 16) as u8; + let channel = $channel as u16; + let hop = $routing_table.0[destination as usize][0]; + if hop == 0 { + local_moninj::$func(channel, $($param, )*) + } else { + let linkno = hop - 1; + remote_moninj::$func(linkno, destination, channel, $($param, )*) } - } - match drtioaux::recv_timeout(nodeno, None) { - Ok(drtioaux::Packet::MonitorReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), - Err(e) => error!("aux packet error ({})", e) - } - 0 + }} } -fn read_probe(channel: u32, probe: u8) -> u32 { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - return read_probe_local(node_channel, probe) - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - return read_probe_drtio(nodeno, node_channel, probe) - } - } - error!("read_probe: unrecognized channel number {}", channel); - 0 +#[cfg(not(has_drtio))] +macro_rules! dispatch { + ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + let channel = $channel as u8; + local_moninj::$func(channel, $($param, )*) + }} } -#[cfg(has_rtio_moninj)] -fn inject_local(channel: u16, overrd: u8, value: u8) { - unsafe { - csr::rtio_moninj::inj_chan_sel_write(channel as _); - csr::rtio_moninj::inj_override_sel_write(overrd); - csr::rtio_moninj::inj_value_write(value); - } -} - -#[cfg(has_drtio)] -fn inject_drtio(nodeno: u8, channel: u16, overrd: u8, value: u8) { - let request = drtioaux::Packet::InjectionRequest { - channel: channel, - overrd: overrd, - value: value - }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => error!("aux packet error ({})", e) - } -} - -fn inject(channel: u32, overrd: u8, value: u8) { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - inject_local(node_channel, overrd, value); - return - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - inject_drtio(nodeno, node_channel, overrd, value); - return - } - } - error!("inject: unrecognized channel number {}", channel); -} - -#[cfg(has_rtio_moninj)] -fn read_injection_status_local(channel: u16, overrd: u8) -> u8 { - unsafe { - csr::rtio_moninj::inj_chan_sel_write(channel as _); - csr::rtio_moninj::inj_override_sel_write(overrd); - csr::rtio_moninj::inj_value_read() - } -} - -#[cfg(has_drtio)] -fn read_injection_status_drtio(nodeno: u8, channel: u16, overrd: u8) -> u8 { - let request = drtioaux::Packet::InjectionStatusRequest { - channel: channel, - overrd: overrd - }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(nodeno, None) { - Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), - Err(e) => error!("aux packet error ({})", e) - } - 0 -} - -fn read_injection_status(channel: u32, probe: u8) -> u8 { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - return read_injection_status_local(node_channel, probe) - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - return read_injection_status_drtio(nodeno, node_channel, probe) - } - } - error!("read_injection_status: unrecognized channel number {}", channel); - 0 -} - -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error> { +fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, + mut stream: &mut TcpStream) -> Result<(), Error> { let mut probe_watch_list = BTreeMap::new(); let mut inject_watch_list = BTreeMap::new(); let mut next_check = 0; @@ -173,9 +159,9 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error inject(channel, overrd, value), + HostMessage::Inject { channel, overrd, value } => dispatch!(_routing_table, channel, inject, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = read_injection_status(channel, overrd); + let value = dispatch!(_routing_table, channel, read_injection_status, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -192,7 +178,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error next_check { for (&(channel, probe), previous) in probe_watch_list.iter_mut() { - let current = read_probe(channel, probe); + let current = dispatch!(_routing_table, channel, read_probe, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, @@ -207,7 +193,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error Result<(), Error>) { let listener = TcpListener::new(&io, 2047); listener.listen(1383).expect("moninj: cannot listen"); loop { + let routing_table = routing_table.clone(); let stream = listener.accept().expect("moninj: cannot accept").into_handle(); io.spawn(16384, move |io| { + let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match connection_worker(&io, &mut stream) { + match connection_worker(&io, &routing_table, &mut stream) { Ok(()) => {}, Err(err) => error!("moninj aborted: {}", err) } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d5a2722d2..4c081810e 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -12,6 +12,7 @@ use rtio_dma::Manager as DmaManager; use cache::Cache; use kern_hwreq; use watchdog::WatchdogSet; +use board_artiq::drtio_routing; use rpc_proto as rpc; use session_proto as host; @@ -323,7 +324,8 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, +fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, + mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { @@ -341,7 +343,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, request)? { + if kern_hwreq::process_kern_hwreq(io, routing_table, request)? { return Ok(false) } @@ -490,7 +492,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, +fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -507,7 +509,7 @@ fn host_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - process_kern_message(io, Some(stream), &mut session)?; + process_kern_message(io, routing_table, Some(stream), &mut session)?; } if session.kernel_state == KernelState::Running { @@ -526,7 +528,7 @@ fn host_kernel_worker(io: &Io, } } -fn flash_kernel_worker(io: &Io, +fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -549,7 +551,7 @@ fn flash_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - if process_kern_message(io, None, &mut session)? { + if process_kern_message(io, routing_table, None, &mut session)? { return Ok(()) } } @@ -581,7 +583,7 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io) { +pub fn thread(io: Io, routing_table: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -590,11 +592,13 @@ pub fn thread(io: Io) { let mut kernel_thread = None; { + let routing_table = routing_table.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &routing_table, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -623,12 +627,14 @@ pub fn thread(io: Io) { } info!("new connection from {}", stream.remote_endpoint()); + let routing_table = routing_table.clone(); let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &routing_table, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -646,10 +652,12 @@ pub fn thread(io: Io) { if kernel_thread.as_ref().map_or(true, |h| h.terminated()) { info!("no connection, starting idle kernel"); + let routing_table = routing_table.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &routing_table, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8e3b22e7d..1bb4c6155 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -46,6 +46,27 @@ fn drtiosat_tsc_loaded() -> bool { } } + +#[cfg(has_drtio_routing)] +macro_rules! forward { + ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {{ + let hop = $routing_table.0[$destination as usize][$rank as usize]; + if hop != 0 { + let repno = (hop - 1) as usize; + if repno < $repeaters.len() { + return $repeaters[repno].aux_forward($packet); + } else { + return Err(drtioaux::Error::RoutingError); + } + } + }} +} + +#[cfg(not(has_drtio_routing))] +macro_rules! forward { + ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {} +} + fn process_aux_packet(_repeaters: &mut [repeater::Repeater], _routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8, packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { @@ -174,7 +195,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } - drtioaux::Packet::MonitorRequest { channel, probe } => { + drtioaux::Packet::MonitorRequest { destination, channel, probe } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -190,7 +212,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; drtioaux::send_link(0, &reply) }, - drtioaux::Packet::InjectionRequest { channel, overrd, value } => { + drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); #[cfg(has_rtio_moninj)] unsafe { csr::rtio_moninj::inj_chan_sel_write(channel as _); @@ -199,7 +222,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } Ok(()) }, - drtioaux::Packet::InjectionStatusRequest { channel, overrd } => { + drtioaux::Packet::InjectionStatusRequest { destination, channel, overrd } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -214,19 +238,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, - drtioaux::Packet::I2cStartRequest { busno } => { + drtioaux::Packet::I2cStartRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cRestartRequest { busno } => { + drtioaux::Packet::I2cRestartRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cStopRequest { busno } => { + drtioaux::Packet::I2cStopRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cWriteRequest { busno, data } => { + drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { Ok(ack) => drtioaux::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), @@ -234,7 +262,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } - drtioaux::Packet::I2cReadRequest { busno, ack } => { + drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), @@ -243,17 +272,20 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, - drtioaux::Packet::SpiWriteRequest { busno, data } => { + drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } - drtioaux::Packet::SpiReadRequest { busno } => { + drtioaux::Packet::SpiReadRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match spi::read(busno) { Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), From d19550daf8fa3af5ff8eca25735fdaa03ed967f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:32:09 +0800 Subject: [PATCH 63/92] firmware: simplify drtioaux function names --- artiq/firmware/libboard_artiq/drtioaux.rs | 8 ++-- artiq/firmware/runtime/kern_hwreq.rs | 26 +++++------ artiq/firmware/runtime/moninj.rs | 10 ++-- artiq/firmware/runtime/rtio_mgt.rs | 20 ++++---- artiq/firmware/satman/main.rs | 56 +++++++++++------------ artiq/firmware/satman/repeater.rs | 18 ++++---- 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index a0465b230..f72072702 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -80,7 +80,7 @@ fn receive(linkno: u8, f: F) -> Result, Error> } } -pub fn recv_link(linkno: u8) -> Result, Error> { +pub fn recv(linkno: u8) -> Result, Error> { if has_rx_error(linkno) { return Err(Error::GatewareError) } @@ -104,11 +104,11 @@ pub fn recv_link(linkno: u8) -> Result, Error> { }) } -pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result> { +pub fn recv_timeout(linkno: u8, timeout_ms: Option) -> Result> { let timeout_ms = timeout_ms.unwrap_or(10); let limit = clock::get_ms() + timeout_ms; while clock::get_ms() < limit { - match recv_link(linkno)? { + match recv(linkno)? { None => (), Some(packet) => return Ok(packet), } @@ -131,7 +131,7 @@ fn transmit(linkno: u8, f: F) -> Result<(), Error> } } -pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { +pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> { transmit(linkno, |buffer| { let mut writer = Cursor::new(buffer); diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 00d20be3b..7a9ce6061 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -11,7 +11,7 @@ mod remote_i2c { use drtioaux; fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -31,7 +31,7 @@ mod remote_i2c { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -42,7 +42,7 @@ mod remote_i2c { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -53,7 +53,7 @@ mod remote_i2c { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -65,10 +65,10 @@ mod remote_i2c { busno: busno, data: data }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -89,10 +89,10 @@ mod remote_i2c { busno: busno, ack: ack }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -113,7 +113,7 @@ mod remote_spi { use drtioaux; fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -137,7 +137,7 @@ mod remote_spi { div: div, cs: cs }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -149,7 +149,7 @@ mod remote_spi { busno: busno, data: data }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -160,10 +160,10 @@ mod remote_spi { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index a1a0765ac..d2713bd4c 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -57,14 +57,14 @@ mod remote_moninj { channel: channel, probe: probe }; - match drtioaux::send_link(linkno, &request) { + match drtioaux::send(linkno, &request) { Ok(_) => (), Err(e) => { error!("aux packet error ({})", e); return 0; } } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::MonitorReply { value }) => return value, Ok(_) => error!("received unexpected aux packet"), Err(e) => error!("aux packet error ({})", e) @@ -79,7 +79,7 @@ mod remote_moninj { overrd: overrd, value: value }; - match drtioaux::send_link(linkno, &request) { + match drtioaux::send(linkno, &request) { Ok(_) => (), Err(e) => error!("aux packet error ({})", e) } @@ -91,14 +91,14 @@ mod remote_moninj { channel: channel, overrd: overrd }; - match drtioaux::send_link(linkno, &request) { + match drtioaux::send(linkno, &request) { Ok(_) => (), Err(e) => { error!("aux packet error ({})", e); return 0; } } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, Ok(_) => error!("received unexpected aux packet"), Err(e) => error!("aux packet error ({})", e) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 2153e9986..c3b67567d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -93,9 +93,9 @@ pub mod drtio { if count > 200 { return 0; } - drtioaux::send_link(linkno, &drtioaux::Packet::EchoRequest).unwrap(); + drtioaux::send(linkno, &drtioaux::Packet::EchoRequest).unwrap(); io.sleep(100).unwrap(); - let pr = drtioaux::recv_link(linkno); + let pr = drtioaux::recv(linkno); match pr { Ok(Some(drtioaux::Packet::EchoReply)) => return count, _ => {} @@ -112,7 +112,7 @@ pub mod drtio { if clock::get_ms() > max_time { return Err("timeout"); } - match drtioaux::recv_link(linkno) { + match drtioaux::recv(linkno) { Ok(Some(packet)) => return Ok(packet), Ok(None) => (), Err(_) => return Err("aux packet error") @@ -139,7 +139,7 @@ pub mod drtio { fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { - drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath { + drtioaux::send(linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, hops: routing_table.0[i] }).unwrap(); @@ -152,7 +152,7 @@ pub mod drtio { } fn set_rank(io: &Io, linkno: u8, rank: u8) -> Result<(), &'static str> { - drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetRank { + drtioaux::send(linkno, &drtioaux::Packet::RoutingSetRank { rank: rank }).unwrap(); let reply = recv_aux_timeout(io, linkno, 200)?; @@ -176,7 +176,7 @@ pub mod drtio { } fn process_unsolicited_aux(linkno: u8) { - match drtioaux::recv_link(linkno) { + match drtioaux::recv(linkno) { Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(None) => (), Err(_) => warn!("[LINK#{}] aux packet error", linkno) @@ -219,7 +219,7 @@ pub mod drtio { let linkno = hop - 1; if up_destinations[destination] { if link_up(linkno) { - drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination as u8 }).unwrap(); match recv_aux_timeout(io, linkno, 200) { @@ -243,7 +243,7 @@ pub mod drtio { } } else { if link_up(linkno) { - drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination as u8 }).unwrap(); match recv_aux_timeout(io, linkno, 200) { @@ -309,9 +309,9 @@ pub mod drtio { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; if link_up(linkno) { - drtioaux::send_link(linkno, + drtioaux::send(linkno, &drtioaux::Packet::ResetRequest { phy: false }).unwrap(); - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1bb4c6155..7c47011ee 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -74,7 +74,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], // and u16 otherwise; hence the `as _` conversion. match packet { drtioaux::Packet::EchoRequest => - drtioaux::send_link(0, &drtioaux::Packet::EchoReply), + drtioaux::send(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { info!("resetting RTIO"); if phy { @@ -89,7 +89,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], error!("failed to issue RTIO reset ({})", e); } } - drtioaux::send_link(0, &drtioaux::Packet::ResetAck) + drtioaux::send(0, &drtioaux::Packet::ResetAck) }, drtioaux::Packet::DestinationStatusRequest { destination } => { @@ -109,7 +109,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], channel = csr::drtiosat::sequence_error_channel_read(); csr::drtiosat::rtio_error_write(1); } - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::DestinationSequenceErrorReply { channel })?; } else if errors & 2 != 0 { let channel; @@ -117,7 +117,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], channel = csr::drtiosat::collision_channel_read(); csr::drtiosat::rtio_error_write(2); } - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::DestinationCollisionReply { channel })?; } else if errors & 4 != 0 { let channel; @@ -125,11 +125,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], channel = csr::drtiosat::busy_channel_read(); csr::drtiosat::rtio_error_write(4); } - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::DestinationBusyReply { channel })?; } else { - drtioaux::send_link(0, &drtioaux::Packet::DestinationOkReply)?; + drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?; } } @@ -143,14 +143,14 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], destination: destination }) { Ok(()) => (), - Err(drtioaux::Error::LinkDown) => drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?, + Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?, Err(e) => { - drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?; error!("aux error when handling destination status request: {}", e); }, } } else { - drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?; } } } @@ -166,7 +166,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], error!("failed to set path ({})", e); } } - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(has_drtio_routing)] drtioaux::Packet::RoutingSetRank { rank } => { @@ -183,16 +183,16 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], info!("rank: {}", rank); info!("routing table: {}", _routing_table); - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] drtioaux::Packet::RoutingSetPath { destination, hops } => { - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] drtioaux::Packet::RoutingSetRank { rank } => { - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } drtioaux::Packet::MonitorRequest { destination, channel, probe } => { @@ -210,7 +210,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], value = 0; } let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; - drtioaux::send_link(0, &reply) + drtioaux::send(0, &reply) }, drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); @@ -235,39 +235,39 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], { value = 0; } - drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) + drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, drtioaux::Packet::I2cStartRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); - drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cRestartRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); - drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cStopRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); - drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { - Ok(ack) => drtioaux::send_link(0, + Ok(ack) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), - Err(_) => drtioaux::send_link(0, + Err(_) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { - Ok(data) => drtioaux::send_link(0, + Ok(data) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), - Err(_) => drtioaux::send_link(0, + Err(_) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }) } } @@ -275,21 +275,21 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } drtioaux::Packet::SpiReadRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); match spi::read(busno) { - Ok(data) => drtioaux::send_link(0, + Ok(data) => drtioaux::send(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), - Err(_) => drtioaux::send_link(0, + Err(_) => drtioaux::send(0, &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }) } } @@ -304,7 +304,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], fn process_aux_packets(repeaters: &mut [repeater::Repeater], routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8) { let result = - drtioaux::recv_link(0).and_then(|packet| { + drtioaux::recv(0).and_then(|packet| { if let Some(packet) = packet { process_aux_packet(repeaters, routing_table, rank, packet) } else { @@ -463,7 +463,7 @@ pub extern fn main() -> i32 { error!("failed to sync TSC ({})", e); } } - if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { + if let Err(e) = drtioaux::send(0, &drtioaux::Packet::TSCAck) { error!("aux packet error: {}", e); } } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index c97ece3e5..dae775364 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -51,7 +51,7 @@ impl Repeater { } RepeaterState::SendPing { ping_count } => { if rep_link_rx_up(self.repno) { - drtioaux::send_link(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); + drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); self.state = RepeaterState::WaitPingReply { ping_count: ping_count + 1, timeout: clock::get_ms() + 100 @@ -63,7 +63,7 @@ impl Repeater { } RepeaterState::WaitPingReply { ping_count, timeout } => { if rep_link_rx_up(self.repno) { - if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { + if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); self.state = RepeaterState::Up; if let Err(e) = self.sync_tsc() { @@ -113,7 +113,7 @@ impl Repeater { } fn process_unsolicited_aux(&self) { - match drtioaux::recv_link(self.auxno) { + match drtioaux::recv(self.auxno) { Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet), Ok(None) => (), Err(_) => warn!("[REP#{}] aux packet error", self.repno) @@ -162,7 +162,7 @@ impl Repeater { if clock::get_ms() > max_time { return Err(drtioaux::Error::TimedOut); } - match drtioaux::recv_link(self.auxno) { + match drtioaux::recv(self.auxno) { Ok(Some(packet)) => return Ok(packet), Ok(None) => (), Err(e) => return Err(e) @@ -174,9 +174,9 @@ impl Repeater { if self.state != RepeaterState::Up { return Err(drtioaux::Error::LinkDown); } - drtioaux::send_link(self.auxno, request).unwrap(); + drtioaux::send(self.auxno, request).unwrap(); let reply = self.recv_aux_timeout(200)?; - drtioaux::send_link(0, &reply).unwrap(); + drtioaux::send(0, &reply).unwrap(); Ok(()) } @@ -206,7 +206,7 @@ impl Repeater { return Ok(()); } - drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetPath { + drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetPath { destination: destination, hops: *hops }).unwrap(); @@ -228,7 +228,7 @@ impl Repeater { if self.state != RepeaterState::Up { return Ok(()); } - drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetRank { + drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank { rank: rank }).unwrap(); let reply = self.recv_aux_timeout(200)?; @@ -242,7 +242,7 @@ impl Repeater { if self.state != RepeaterState::Up { return Ok(()); } - drtioaux::send_link(self.auxno, &drtioaux::Packet::ResetRequest { + drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest { phy: phy }).unwrap(); let reply = self.recv_aux_timeout(200)?; From 65da1fee4a22707865db333386c7069e4aadd99f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:38:41 +0800 Subject: [PATCH 64/92] firmware: fix build without DRTIO --- artiq/firmware/libboard_artiq/drtio_routing.rs | 4 +++- artiq/firmware/runtime/main.rs | 1 - artiq/firmware/runtime/moninj.rs | 2 +- artiq/firmware/runtime/rtio_mgt.rs | 4 +++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index c78b5cddd..fe51c3cc4 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -1,4 +1,6 @@ -use board_misoc::{csr, config}; +use board_misoc::config; +#[cfg(has_drtio_routing)] +use board_misoc::csr; use core::fmt; pub const DEST_COUNT: usize = 256; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 16f0fca05..6ecf79dd0 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -34,7 +34,6 @@ use board_misoc::{csr, irq, ident, clock, boot, config}; use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; -#[cfg(has_drtio_routing)] use board_artiq::drtio_routing; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index d2713bd4c..b049806df 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -125,7 +125,7 @@ macro_rules! dispatch { #[cfg(not(has_drtio))] macro_rules! dispatch { ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ - let channel = $channel as u8; + let channel = $channel as u16; local_moninj::$func(channel, $($param, )*) }} } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index c3b67567d..1635586a0 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,6 +1,8 @@ use core::cell::RefCell; use urc::Urc; -use board_misoc::{csr, clock}; +use board_misoc::csr; +#[cfg(has_drtio))] +use board_misoc::clock; #[cfg(has_rtio_clock_switch)] use board_misoc::config; use board_artiq::drtio_routing; From f8c6fa5ad6179b6f7248d35506ffa942d1fd93ca Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:43:36 +0800 Subject: [PATCH 65/92] typo --- artiq/firmware/runtime/rtio_mgt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 1635586a0..237b71667 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,7 +1,7 @@ use core::cell::RefCell; use urc::Urc; use board_misoc::csr; -#[cfg(has_drtio))] +#[cfg(has_drtio)] use board_misoc::clock; #[cfg(has_rtio_clock_switch)] use board_misoc::config; From 20ed393c1e7677f4f0d0f6952f5c019cfd647a25 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:43:50 +0800 Subject: [PATCH 66/92] style --- artiq/frontend/aqctl_corelog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index 7cee0b974..9df2c3a8d 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -16,7 +16,7 @@ def get_argparser(): parser = argparse.ArgumentParser( description="ARTIQ controller for core device logs") simple_network_args(parser, 1068) - parser.add_argument("core_addr", + parser.add_argument("core_addr", metavar="CORE_ADDR", help="hostname or IP address of the core device") return parser From 2f010e0109d6d0ddec64fd4e9abfe2aa0cc54109 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:44:41 +0800 Subject: [PATCH 67/92] runtime: improve moninj aux error logging --- artiq/firmware/runtime/moninj.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index b049806df..5ffaa96a0 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -66,7 +66,7 @@ mod remote_moninj { } match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::MonitorReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) } 0 @@ -100,7 +100,7 @@ mod remote_moninj { } match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) } 0 From 0017cb756ef4f384a6eac1fc646fe87923ef0b2b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:44:59 +0800 Subject: [PATCH 68/92] frontend: add artiq_rtiomon --- artiq/frontend/artiq_rtiomon.py | 39 +++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 40 insertions(+) create mode 100755 artiq/frontend/artiq_rtiomon.py diff --git a/artiq/frontend/artiq_rtiomon.py b/artiq/frontend/artiq_rtiomon.py new file mode 100755 index 000000000..eed6a9074 --- /dev/null +++ b/artiq/frontend/artiq_rtiomon.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import argparse +import asyncio + +from artiq.coredevice.comm_moninj import * + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ RTIO monitor") + parser.add_argument("core_addr", metavar="CORE_ADDR", + help="hostname or IP address of the core device") + parser.add_argument("channel", metavar="CHANNEL", type=lambda x: int(x, 0), nargs="+", + help="channel(s) to monitor") + return parser + + +def main(): + args = get_argparser().parse_args() + + loop = asyncio.get_event_loop() + try: + comm = CommMonInj( + lambda channel, probe, value: print("0x{:06x}: {}".format(channel, value)), + lambda channel, override, value: None) + loop.run_until_complete(comm.connect(args.core_addr)) + try: + for channel in args.channel: + comm.monitor_probe(True, channel, 0) + loop.run_forever() + finally: + loop.run_until_complete(comm.close()) + finally: + loop.close() + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index b4c25b027..a10ec254b 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ console_scripts = [ "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", + "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", "artiq_session = artiq.frontend.artiq_session:main", "artiq_route = artiq.frontend.artiq_route:main", "artiq_rpctool = artiq.frontend.artiq_rpctool:main", From f097b4104cf93bea62ce20d8cc66a67a6c9a749c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 11:33:18 +0800 Subject: [PATCH 69/92] satman: not(has_drtio_routing) fixes --- artiq/firmware/satman/main.rs | 54 +++++++++++++++---------------- artiq/firmware/satman/repeater.rs | 17 ++++++++-- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7c47011ee..8fb9c287e 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -92,9 +92,9 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send(0, &drtioaux::Packet::ResetAck) }, - drtioaux::Packet::DestinationStatusRequest { destination } => { + drtioaux::Packet::DestinationStatusRequest { destination: _destination } => { #[cfg(has_drtio_routing)] - let hop = _routing_table.0[destination as usize][*_rank as usize]; + let hop = _routing_table.0[_destination as usize][*_rank as usize]; #[cfg(not(has_drtio_routing))] let hop = 0; @@ -140,7 +140,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], if hop <= csr::DRTIOREP.len() { let repno = hop - 1; match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest { - destination: destination + destination: _destination }) { Ok(()) => (), Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?, @@ -187,16 +187,16 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetPath { destination, hops } => { + drtioaux::Packet::RoutingSetPath { destination: _, hops: _ } => { drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetRank { rank } => { + drtioaux::Packet::RoutingSetRank { rank: _ } => { drtioaux::send(0, &drtioaux::Packet::RoutingAck) } - drtioaux::Packet::MonitorRequest { destination, channel, probe } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::MonitorRequest { destination: _destination, channel, probe } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -212,8 +212,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; drtioaux::send(0, &reply) }, - drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::InjectionRequest { destination: _destination, channel, overrd, value } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); #[cfg(has_rtio_moninj)] unsafe { csr::rtio_moninj::inj_chan_sel_write(channel as _); @@ -222,8 +222,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } Ok(()) }, - drtioaux::Packet::InjectionStatusRequest { destination, channel, overrd } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::InjectionStatusRequest { destination: _destination, channel, overrd } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -238,23 +238,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, - drtioaux::Packet::I2cStartRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cStartRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cRestartRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cRestartRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cStopRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cStopRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cWriteRequest { destination: _destination, busno, data } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { Ok(ack) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), @@ -262,8 +262,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } - drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cReadRequest { destination: _destination, busno, ack } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { Ok(data) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), @@ -272,20 +272,20 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno, flags, length, div, cs } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, - drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::SpiWriteRequest { destination: _destination, busno, data } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } - drtioaux::Packet::SpiReadRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::SpiReadRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); match spi::read(busno) { Ok(data) => drtioaux::send(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index dae775364..d5b04a94f 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -1,5 +1,6 @@ -use board_misoc::{csr, clock}; use board_artiq::{drtioaux, drtio_routing}; +#[cfg(has_drtio_routing)] +use board_misoc::{csr, clock}; #[cfg(has_drtio_routing)] fn rep_link_rx_up(repno: u8) -> bool { @@ -9,6 +10,7 @@ fn rep_link_rx_up(repno: u8) -> bool { } } +#[cfg(has_drtio_routing)] #[derive(Clone, Copy, PartialEq)] enum RepeaterState { Down, @@ -18,10 +20,12 @@ enum RepeaterState { Failed } +#[cfg(has_drtio_routing)] impl Default for RepeaterState { fn default() -> RepeaterState { RepeaterState::Down } } +#[cfg(has_drtio_routing)] #[derive(Clone, Copy, Default)] pub struct Repeater { repno: u8, @@ -253,11 +257,18 @@ impl Repeater { } } +#[cfg(not(has_drtio_routing))] +#[derive(Clone, Copy, Default)] +pub struct Repeater { +} + #[cfg(not(has_drtio_routing))] impl Repeater { pub fn new(_repno: u8) -> Repeater { Repeater::default() } - pub fn service(&self) { } + pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8) { } - pub fn sync_tsc(&self) -> Result<(), &'static str> { Ok(()) } + pub fn sync_tsc(&self) -> Result<(), drtioaux::Error> { Ok(()) } + + pub fn rtio_reset(&self, _phy: bool) -> Result<(), drtioaux::Error> { Ok(()) } } From c0c413196a912f7d36ab04cb8f5561b5fc18e83c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 12:08:06 +0800 Subject: [PATCH 70/92] frontend: remove artiq_pcap. Closes #1152 --- artiq/frontend/artiq_pcap.py | 57 ------------------------------------ setup.py | 1 - 2 files changed, 58 deletions(-) delete mode 100755 artiq/frontend/artiq_pcap.py diff --git a/artiq/frontend/artiq_pcap.py b/artiq/frontend/artiq_pcap.py deleted file mode 100755 index 59f124734..000000000 --- a/artiq/frontend/artiq_pcap.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 - -# This script makes the following assumptions: -# * tcpdump has CAP_NET_RAW capabilities set -# use # setcap cap_net_raw+eip /usr/sbin/tcpdump - -import os -import argparse -import subprocess - -from artiq.tools import verbosity_args, init_logger, logger, SSHClient - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device " - "packet capture tool") - - verbosity_args(parser) - - parser.add_argument("-H", "--host", metavar="HOST", - type=str, default="lab.m-labs.hk", - help="SSH host where the development board is located") - parser.add_argument("-D", "--device", metavar="DEVICE", - type=str, default="kc705.lab.m-labs.hk", - help="address or domain corresponding to the development board") - parser.add_argument("-f", "--file", metavar="PCAP_FILE", - type=str, default="coredevice.pcap", - help="Location to retrieve the pcap file into") - - parser.add_argument("command", metavar="COMMAND", - type=str, default=[], nargs=argparse.REMAINDER, - help="command to execute while capturing") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - client = SSHClient(args.host) - - sftp = client.get_sftp() - tcpdump = client.spawn_command( - "/usr/sbin/tcpdump host {device} -w {tmp}/trace.pcap", get_pty=True, - device=args.device) - - try: - subprocess.check_call(args.command) - except subprocess.CalledProcessError: - logger.error("Command failed") - - tcpdump.close() - sftp.get("{tmp}/trace.pcap".format(tmp=client.tmp), - args.file + ".new") - os.rename(args.file + ".new", args.file) - logger.info("Pcap file {file} retrieved".format(file=args.file)) diff --git a/setup.py b/setup.py index a10ec254b..70187c8b2 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ console_scripts = [ "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", - "artiq_pcap = artiq.frontend.artiq_pcap:main", "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", From cd61ee858ce3b651896f061d900e66529bfa8328 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 14:06:54 +0800 Subject: [PATCH 71/92] kasli: fix satellite TSC instantiation --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9070bf241..9c37c2220 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -816,7 +816,7 @@ class _SatelliteBase(BaseSoC): self.comb += [sfp_ctl.led.eq(channel.rx_ready) for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] - self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) drtioaux_csr_group = [] drtioaux_memory_group = [] From 1990ab35d387b1fa12e2991643cf2fa3f06e1a44 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 15 Sep 2018 07:35:35 +0000 Subject: [PATCH 72/92] firmware: implement mutexes. --- artiq/firmware/runtime/sched.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index c28fff956..4c027e895 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -265,6 +265,28 @@ impl<'a> Io<'a> { } } +pub struct Mutex(Urc>); + +impl Mutex { + pub fn new() -> Mutex { + Mutex(Urc::new(Cell::new(false))) + } + + pub fn lock<'a>(&'a self, io: Io) -> Result, Error> { + io.until(|| !self.0.get())?; + self.0.set(true); + Ok(MutexGuard(&*self.0)) + } +} + +pub struct MutexGuard<'a>(&'a Cell); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) { + self.0.set(false) + } +} + macro_rules! until { ($socket:expr, $ty:ty, |$var:ident| $cond:expr) => ({ let (sockets, handle) = ($socket.io.sockets.clone(), $socket.handle); From d38755feff1c25c456854cbfa8beb72d4b52c628 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 15:55:45 +0800 Subject: [PATCH 73/92] drtio: implement destination state checks on operations --- artiq/coredevice/exceptions.py | 2 +- artiq/firmware/ksupport/lib.rs | 4 +-- artiq/firmware/ksupport/rtio.rs | 32 +++++++++---------- .../firmware/libboard_artiq/drtio_routing.rs | 28 +++++++++++----- artiq/firmware/runtime/rtio_mgt.rs | 10 +++--- artiq/firmware/satman/main.rs | 2 +- artiq/gateware/drtio/rt_controller_master.py | 6 ++-- artiq/gateware/rtio/cri.py | 15 +++++++-- artiq/gateware/test/drtio/test_full_stack.py | 4 +-- artiq/gateware/test/rtio/test_dma.py | 4 +-- 10 files changed, 63 insertions(+), 44 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 017266729..0d84d49c0 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -91,7 +91,7 @@ class RTIOOverflow(Exception): artiq_builtin = True -class RTIOLinkError(Exception): +class RTIODestinationUnreachable(Exception): """Raised with a RTIO operation could not be completed due to a DRTIO link being down. """ diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index d4a6615d2..35ac00eb4 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -428,8 +428,8 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { timestamp as i64, channel as i64, 0); } if error & 2 != 0 { - raise!("RTIOLinkError", - "RTIO output link error at {0} mu, channel {1}", + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, output, at {0} mu, channel {1}", timestamp as i64, channel as i64, 0); } } diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 119fab8f5..e0368b593 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -7,13 +7,13 @@ mod imp { use ::send; use kernel_proto::*; - pub const RTIO_O_STATUS_WAIT: u8 = 1; - pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; - pub const RTIO_O_STATUS_LINK_ERROR: u8 = 4; - pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; - pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; - pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; - pub const RTIO_I_STATUS_LINK_ERROR: u8 = 8; + pub const RTIO_O_STATUS_WAIT: u8 = 1; + pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; + pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4; + pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; + pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; + pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; + pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8; pub extern fn init() { send(&RtioInitRequest); @@ -49,9 +49,9 @@ mod imp { "RTIO underflow at {0} mu, channel {1}, slack {2} mu", timestamp, channel as i64, timestamp - get_counter()); } - if status & RTIO_O_STATUS_LINK_ERROR != 0 { - raise!("RTIOLinkError", - "RTIO output link error at {0} mu, channel {1}", + if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, output, at {0} mu, channel {1}", timestamp, channel as i64, 0); } } @@ -108,9 +108,9 @@ mod imp { if status & RTIO_I_STATUS_WAIT_EVENT != 0 { return !0 } - if status & RTIO_I_STATUS_LINK_ERROR != 0 { - raise!("RTIOLinkError", - "RTIO input link error on channel {0}", + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, input, on channel {0}", channel as i64, 0, 0); } @@ -135,9 +135,9 @@ mod imp { "RTIO input overflow on channel {0}", channel as i64, 0, 0); } - if status & RTIO_I_STATUS_LINK_ERROR != 0 { - raise!("RTIOLinkError", - "RTIO input link error on channel {0}", + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, input, on channel {0}", channel as i64, 0, 0); } diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index fe51c3cc4..cc49c7b54 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -72,13 +72,25 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { } #[cfg(has_drtio_routing)] -pub fn program_interconnect(rt: &RoutingTable, rank: u8) -{ - for i in 0..DEST_COUNT { - let hop = rt.0[i][rank as usize]; - unsafe { - csr::routing_table::destination_write(i as _); - csr::routing_table::hop_write(hop); - } +pub fn interconnect_enable(routing_table: &RoutingTable, rank: u8, destination: u8) { + let hop = routing_table.0[destination as usize][rank as usize]; + unsafe { + csr::routing_table::destination_write(destination); + csr::routing_table::hop_write(hop); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_disable(destination: u8) { + unsafe { + csr::routing_table::destination_write(destination); + csr::routing_table::hop_write(INVALID_HOP); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_enable_all(routing_table: &RoutingTable, rank: u8) { + for i in 0..DEST_COUNT { + interconnect_enable(routing_table, rank, i as u8); } } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 237b71667..042db050f 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -216,6 +216,7 @@ pub mod drtio { if !up_destinations[destination] { info!("[DEST#{}] destination is up", destination); up_destinations[destination] = true; + drtio_routing::interconnect_enable(routing_table, 0, destination as u8); } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; @@ -228,6 +229,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationDownReply) => { info!("[DEST#{}] destination is down", destination); up_destinations[destination] = false; + drtio_routing::interconnect_disable(destination as u8); }, Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => @@ -242,6 +244,7 @@ pub mod drtio { } else { info!("[DEST#{}] destination is down", destination); up_destinations[destination] = false; + drtio_routing::interconnect_disable(destination as u8); } } else { if link_up(linkno) { @@ -253,6 +256,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationOkReply) => { info!("[DEST#{}] destination is up", destination); up_destinations[destination] = true; + drtio_routing::interconnect_enable(routing_table, 0, destination as u8); init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -394,12 +398,6 @@ pub fn startup(io: &Io, routing_table: &Urc } } - #[cfg(has_drtio_routing)] - { - let routing_table = routing_table.clone(); - drtio_routing::program_interconnect(&routing_table.borrow(), 0); - } - drtio::startup(io, &routing_table); init_core(true); io.spawn(4096, async_error_thread); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8fb9c287e..1e69111b2 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -171,7 +171,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], #[cfg(has_drtio_routing)] drtioaux::Packet::RoutingSetRank { rank } => { *_rank = rank; - drtio_routing::program_interconnect(_routing_table, rank); + drtio_routing::interconnect_enable_all(_routing_table, rank); let rep_rank = rank + 1; for rep in _repeaters.iter() { diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index d1e0dd1e2..40014dce0 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -102,8 +102,7 @@ class RTController(Module): o_status_wait = Signal() o_status_underflow = Signal() self.comb += [ - self.cri.o_status.eq(Cat( - o_status_wait, o_status_underflow, ~self.csrs.link_up.storage)), + self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow)), self.csrs.o_wait.status.eq(o_status_wait) ] o_underflow_set = Signal() @@ -143,8 +142,7 @@ class RTController(Module): i_status_overflow = Signal() i_status_wait_status = Signal() self.comb += self.cri.i_status.eq(Cat( - i_status_wait_event, i_status_overflow, i_status_wait_status, - ~self.csrs.link_up.storage)) + i_status_wait_event, i_status_overflow, i_status_wait_status)) load_read_reply = Signal() self.sync.sys_with_rst += [ diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index b60164ba2..adafa8d29 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -34,7 +34,7 @@ layout = [ ("o_data", 512, DIR_M_TO_S), ("o_address", 16, DIR_M_TO_S), # o_status bits: - # <0:wait> <1:underflow> <2:link error> + # <0:wait> <1:underflow> <2:destination unreachable> ("o_status", 3, DIR_S_TO_M), # pessimistic estimate of the number of outputs events that can be @@ -47,7 +47,7 @@ layout = [ ("i_timestamp", 64, DIR_S_TO_M), # i_status bits: # <0:wait for event (command timeout)> <1:overflow> <2:wait for status> - # <3:link error> + # <3:destination unreachable> # <0> and <1> are mutually exclusive. <1> has higher priority. ("i_status", 4, DIR_S_TO_M), ] @@ -122,6 +122,17 @@ class CRIDecoder(Module, AutoCSR): # # # # routing + if enable_routing: + destination_unreachable = Interface() + self.comb += [ + destination_unreachable.o_status.eq(4), + destination_unreachable.i_status.eq(8) + ] + slaves = slaves[:] + slaves.append(destination_unreachable) + target_len = 2**(len(slaves) - 1).bit_length() + slaves += [destination_unreachable]*(target_len - len(slaves)) + slave_bits = bits_for(len(slaves)-1) selected = Signal(slave_bits) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 8a23b2db9..579d78f9b 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -125,7 +125,7 @@ class OutputsTestbench: if status & 0x2: raise RTIOUnderflow if status & 0x4: - raise RTIOLinkError + raise RTIODestinationUnreachable yield wlen += 1 return wlen @@ -264,7 +264,7 @@ class TestFullStack(unittest.TestCase): if status & 0x2: return "overflow" if status & 0x8: - return "link error" + return "destination unreachable" return ((yield from kcsrs.i_data.read()), (yield from kcsrs.i_timestamp.read())) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index ee546e2da..1ff14c8d4 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -5,7 +5,7 @@ import itertools from migen import * from misoc.interconnect import wishbone -from artiq.coredevice.exceptions import RTIOUnderflow, RTIOLinkError +from artiq.coredevice.exceptions import RTIOUnderflow, RTIODestinationUnreachable from artiq.gateware import rtio from artiq.gateware.rtio import dma, cri from artiq.gateware.rtio.phy import ttl_simple @@ -61,7 +61,7 @@ def do_dma(dut, address): if error & 1: raise RTIOUnderflow if error & 2: - raise RTIOLinkError + raise RTIODestinationUnreachable test_writes1 = [ From 3cbdf2fbac8902e4968f94b6dccdbcf8f9753491 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 18:43:27 +0800 Subject: [PATCH 74/92] kasli: cleanup drtio blink example --- .../examples/kasli_drtioswitching/repository/blink.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/artiq/examples/kasli_drtioswitching/repository/blink.py b/artiq/examples/kasli_drtioswitching/repository/blink.py index e5068efda..2af2d1233 100644 --- a/artiq/examples/kasli_drtioswitching/repository/blink.py +++ b/artiq/examples/kasli_drtioswitching/repository/blink.py @@ -8,10 +8,9 @@ class Blink(EnvExperiment): @kernel def run(self): - while True: - self.core.reset() + self.core.reset() - while True: - for led in self.leds: - led.pulse(200*ms) - delay(200*ms) + while True: + for led in self.leds: + led.pulse(200*ms) + delay(200*ms) From f7ad7a99e309b17e168ae99e951697dfeadf6fcb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 19:10:52 +0800 Subject: [PATCH 75/92] firmware: set DEST_COUNT to 0 without routing --- artiq/firmware/libboard_artiq/drtio_routing.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index cc49c7b54..562517342 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -3,7 +3,10 @@ use board_misoc::config; use board_misoc::csr; use core::fmt; +#[cfg(has_drtio_routing)] pub const DEST_COUNT: usize = 256; +#[cfg(not(has_drtio_routing))] +pub const DEST_COUNT: usize = 0; pub const MAX_HOPS: usize = 32; pub const INVALID_HOP: u8 = 0xff; From c8cd830118c04953474bdb60ef31e191a7c854cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 19:11:22 +0800 Subject: [PATCH 76/92] drtio: implement get_rtio_destination_status for kernels --- artiq/coredevice/core.py | 12 ++-- .../repository/sines_2sayma.py | 6 +- .../repository/sines_urukul_sayma.py | 4 +- .../sayma_masterdac/repository/sines_drtio.py | 2 +- artiq/firmware/ksupport/api.rs | 3 +- artiq/firmware/ksupport/rtio.rs | 21 +++--- artiq/firmware/libproto_artiq/kernel_proto.rs | 6 +- artiq/firmware/runtime/kern_hwreq.rs | 18 +++-- artiq/firmware/runtime/main.rs | 7 +- artiq/firmware/runtime/rtio_mgt.rs | 69 +++++++++++-------- artiq/firmware/runtime/session.rs | 32 ++++++--- doc/manual/installing.rst | 2 +- 12 files changed, 110 insertions(+), 72 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 9f84efe60..4c33fd266 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -44,11 +44,11 @@ def rtio_init() -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def rtio_get_counter() -> TInt64: +def rtio_get_destination_status(linkno: TInt32) -> TBool: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def drtio_get_link_status(linkno: TInt32) -> TBool: +def rtio_get_counter() -> TInt64: raise NotImplementedError("syscall not simulated") @@ -154,12 +154,12 @@ class Core: return rtio_get_counter() @kernel - def get_drtio_link_status(self, linkno): - """Returns whether the specified DRTIO link is up. + def get_rtio_destination_status(self, destination): + """Returns whether the specified RTIO destination is up. This is particularly useful in startup kernels to delay - startup until certain DRTIO links are up.""" - return drtio_get_link_status(linkno) + startup until certain DRTIO destinations are up.""" + return rtio_get_destination_status(destination) @kernel def reset(self): diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py index 9b8e4d661..b6bc7884c 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py @@ -10,8 +10,8 @@ class Sines2Sayma(EnvExperiment): def run(self): while True: print("waiting for DRTIO ready...") - while not (self.core.get_drtio_link_status(0) and - self.core.get_drtio_link_status(1)): + while not (self.core.get_rtio_destination_status(0) and + self.core.get_rtio_destination_status(1)): pass print("OK") @@ -27,5 +27,5 @@ class Sines2Sayma(EnvExperiment): # Do not use a sub-multiple of oscilloscope sample rates. sawg.frequency0.set(9*MHz) - while self.core.get_drtio_link_status(0) and self.core.get_drtio_link_status(1): + while self.core.get_rtio_destination_status(0) and self.core.get_rtio_destination_status(1): pass diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 318a6e1ab..9b9ab68de 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -23,7 +23,7 @@ class SinesUrukulSayma(EnvExperiment): while True: print("waiting for DRTIO ready...") - while not self.core.get_drtio_link_status(0): + while not self.core.get_rtio_destination_status(0): pass print("OK") @@ -38,5 +38,5 @@ class SinesUrukulSayma(EnvExperiment): sawg.amplitude1.set(.4) sawg.frequency0.set(9*MHz) - while self.core.get_drtio_link_status(0): + while self.core.get_rtio_destination_status(0): pass diff --git a/artiq/examples/sayma_masterdac/repository/sines_drtio.py b/artiq/examples/sayma_masterdac/repository/sines_drtio.py index 7f242e4b8..70a7b3484 100644 --- a/artiq/examples/sayma_masterdac/repository/sines_drtio.py +++ b/artiq/examples/sayma_masterdac/repository/sines_drtio.py @@ -10,7 +10,7 @@ class SAWGTestDRTIO(EnvExperiment): @kernel def run(self): core_log("waiting for DRTIO ready...") - while not self.core.get_drtio_link_status(0): + while not self.core.get_rtio_destination_status(0): pass core_log("OK") diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index c1a0c22ff..be616256f 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -95,6 +95,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* direct syscalls */ api!(rtio_init = ::rtio::init), + api!(rtio_get_destination_status = ::rtio::get_destination_status), api!(rtio_get_counter = ::rtio::get_counter), api!(rtio_log), api!(rtio_output = ::rtio::output), @@ -108,8 +109,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_retrieve = ::dma_retrieve), api!(dma_playback = ::dma_playback), - api!(drtio_get_link_status = ::rtio::drtio::get_link_status), - api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), api!(i2c_stop = ::nrt_bus::i2c::stop), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index e0368b593..1324c0353 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -5,6 +5,7 @@ mod imp { use board_misoc::csr; use ::send; + use ::recv; use kernel_proto::*; pub const RTIO_O_STATUS_WAIT: u8 = 1; @@ -19,6 +20,15 @@ mod imp { send(&RtioInitRequest); } + pub extern fn get_destination_status(destination: i32) -> bool { + if 0 <= destination && destination <= 255 { + send(&RtioDestinationStatusRequest { destination: destination as u8 }); + recv!(&RtioDestinationStatusReply { up } => up) + } else { + false + } + } + pub extern fn get_counter() -> i64 { unsafe { csr::rtio::counter_update_write(1); @@ -209,14 +219,3 @@ mod imp { } pub use self::imp::*; - -pub mod drtio { - use ::send; - use ::recv; - use kernel_proto::*; - - pub extern fn get_link_status(linkno: i32) -> bool { - send(&DrtioLinkStatusRequest { linkno: linkno as u8 }); - recv!(&DrtioLinkStatusReply { up } => up) - } -} diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 477c00a1b..73c9e2765 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -28,6 +28,9 @@ pub enum Message<'a> { RtioInitRequest, + RtioDestinationStatusRequest { destination: u8 }, + RtioDestinationStatusReply { up: bool }, + DmaRecordStart(&'a str), DmaRecordAppend(&'a [u8]), DmaRecordStop { @@ -46,9 +49,6 @@ pub enum Message<'a> { duration: u64 }, - DrtioLinkStatusRequest { linkno: u8 }, - DrtioLinkStatusReply { up: bool }, - RunFinished, RunException { exception: Exception<'a>, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 7a9ce6061..631209923 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,7 +1,9 @@ +use core::cell::RefCell; use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; +use urc::Urc; use board_artiq::drtio_routing; use board_artiq::i2c as local_i2c; use board_artiq::spi as local_spi; @@ -203,7 +205,9 @@ macro_rules! dispatch { }} } -pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, +pub fn process_kern_hwreq(io: &Io, + _routing_table: &drtio_routing::RoutingTable, + _up_destinations: &Urc>, request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { @@ -212,9 +216,15 @@ pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, kern_acknowledge() } - &kern::DrtioLinkStatusRequest { linkno } => { - let up = rtio_mgt::drtio::link_up(linkno); - kern_send(io, &kern::DrtioLinkStatusReply { up: up }) + &kern::RtioDestinationStatusRequest { destination: _destination } => { + #[cfg(has_drtio)] + let up = { + let up_destinations = _up_destinations.borrow(); + up_destinations[_destination as usize] + }; + #[cfg(not(has_drtio))] + let up = true; + kern_send(io, &kern::RtioDestinationStatusReply { up: up }) } &kern::I2cStartRequest { busno } => { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6ecf79dd0..fe7a26d91 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -287,16 +287,19 @@ fn startup_ethernet() { #[cfg(not(has_drtio))] let drtio_routing_table = urc::Urc::new(RefCell::new( drtio_routing::RoutingTable::default_empty())); + let up_destinations = urc::Urc::new(RefCell::new( + [false; drtio_routing::DEST_COUNT])); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io, &drtio_routing_table); + rtio_mgt::startup(&io, &drtio_routing_table, &up_destinations); io.spawn(4096, mgmt::thread); { let drtio_routing_table = drtio_routing_table.clone(); - io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table) }); + let up_destinations = up_destinations.clone(); + io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table, &up_destinations) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 042db050f..e3688fb57 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -47,14 +47,16 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io, routing_table: &Urc>) { + pub fn startup(io: &Io, routing_table: &Urc>, + up_destinations: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); io.spawn(4096, move |io| { let routing_table = routing_table.borrow(); - link_thread(io, &routing_table) + link_thread(io, &routing_table, &up_destinations); }); } @@ -206,31 +208,46 @@ pub mod drtio { } } + fn destination_set_up(routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, + destination: u8, up: bool) { + let mut up_destinations = up_destinations.borrow_mut(); + up_destinations[destination as usize] = up; + if up { + drtio_routing::interconnect_enable(routing_table, 0, destination); + info!("[DEST#{}] destination is up", destination); + } else { + drtio_routing::interconnect_disable(destination); + info!("[DEST#{}] destination is down", destination); + } + } + + fn destination_up(up_destinations: &Urc>, destination: u8) -> bool { + let up_destinations = up_destinations.borrow(); + up_destinations[destination as usize] + } + fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, - up_destinations: &mut [bool; drtio_routing::DEST_COUNT]) { + up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; + let destination = destination as u8; if hop == 0 { /* local RTIO */ - if !up_destinations[destination] { - info!("[DEST#{}] destination is up", destination); - up_destinations[destination] = true; - drtio_routing::interconnect_enable(routing_table, 0, destination as u8); + if !destination_up(up_destinations, destination) { + destination_set_up(routing_table, up_destinations, destination, true); } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; - if up_destinations[destination] { + if destination_up(up_destinations, destination) { if link_up(linkno) { drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { - destination: destination as u8 + destination: destination }).unwrap(); match recv_aux_timeout(io, linkno, 200) { - Ok(drtioaux::Packet::DestinationDownReply) => { - info!("[DEST#{}] destination is down", destination); - up_destinations[destination] = false; - drtio_routing::interconnect_disable(destination as u8); - }, + Ok(drtioaux::Packet::DestinationDownReply) => + destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel), @@ -242,21 +259,17 @@ pub mod drtio { Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) } } else { - info!("[DEST#{}] destination is down", destination); - up_destinations[destination] = false; - drtio_routing::interconnect_disable(destination as u8); + destination_set_up(routing_table, up_destinations, destination, false); } } else { if link_up(linkno) { drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { - destination: destination as u8 + destination: destination }).unwrap(); match recv_aux_timeout(io, linkno, 200) { Ok(drtioaux::Packet::DestinationDownReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => { - info!("[DEST#{}] destination is up", destination); - up_destinations[destination] = true; - drtio_routing::interconnect_enable(routing_table, 0, destination as u8); + destination_set_up(routing_table, up_destinations, destination, true); init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -268,8 +281,8 @@ pub mod drtio { } } - pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { - let mut up_destinations = [false; drtio_routing::DEST_COUNT]; + pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>) { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -306,7 +319,7 @@ pub mod drtio { } } } - destination_survey(&io, routing_table, &mut up_destinations); + destination_survey(&io, routing_table, up_destinations); io.sleep(200).unwrap(); } } @@ -331,7 +344,8 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io, _routing_table: &Urc>) {} + pub fn startup(_io: &Io, _routing_table: &Urc>, + _up_destinations: &Urc>) {} pub fn init() {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -358,7 +372,8 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io, routing_table: &Urc>) { +pub fn startup(io: &Io, routing_table: &Urc>, + up_destinations: &Urc>) { #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -398,7 +413,7 @@ pub fn startup(io: &Io, routing_table: &Urc } } - drtio::startup(io, &routing_table); + drtio::startup(io, routing_table, up_destinations); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 4c081810e..e413e8749 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -324,7 +324,9 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn process_kern_message(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { @@ -343,7 +345,7 @@ fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, routing_table, request)? { + if kern_hwreq::process_kern_hwreq(io, routing_table, up_destinations, request)? { return Ok(false) } @@ -492,7 +494,9 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn host_kernel_worker(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -509,7 +513,9 @@ fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } if mailbox::receive() != 0 { - process_kern_message(io, routing_table, Some(stream), &mut session)?; + process_kern_message(io, + routing_table, up_destinations, + Some(stream), &mut session)?; } if session.kernel_state == KernelState::Running { @@ -528,7 +534,9 @@ fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } } -fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn flash_kernel_worker(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -551,7 +559,7 @@ fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } if mailbox::receive() != 0 { - if process_kern_message(io, routing_table, None, &mut session)? { + if process_kern_message(io, routing_table, up_destinations, None, &mut session)? { return Ok(()) } } @@ -583,7 +591,8 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io, routing_table: &Urc>) { +pub fn thread(io: Io, routing_table: &Urc>, + up_destinations: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -593,12 +602,13 @@ pub fn thread(io: Io, routing_table: &Urc>) let mut kernel_thread = None; { let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &routing_table, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -628,13 +638,14 @@ pub fn thread(io: Io, routing_table: &Urc>) info!("new connection from {}", stream.remote_endpoint()); let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &routing_table, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &routing_table, &up_destinations, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -653,11 +664,12 @@ pub fn thread(io: Io, routing_table: &Urc>) info!("no connection, starting idle kernel"); let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &routing_table, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 05a761493..5030d63d1 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -190,7 +190,7 @@ To flash the idle kernel: The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in the ``artiq_coremgmt`` command. -For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. +For DRTIO systems, the startup kernel should wait until the desired destinations (including local RTIO) are up, using :meth:`artiq.coredevice.Core.get_rtio_destination_status`. * (optional) Select the RTIO clock source From c33f74dabef9793f7847df2c15958d4243755f98 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 15 Sep 2018 15:24:31 +0000 Subject: [PATCH 77/92] firmware: derive Clone for Mutex. --- artiq/firmware/runtime/sched.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 4c027e895..770ac3f6c 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -265,6 +265,7 @@ impl<'a> Io<'a> { } } +#[derive(Clone)] pub struct Mutex(Urc>); impl Mutex { From 2b44786f73c7f0619ecf80d4e48a7d608187aa3f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 17 Sep 2018 23:45:27 +0800 Subject: [PATCH 78/92] drtio: add repeater input support --- artiq/gateware/drtio/rt_packet_repeater.py | 102 ++++++++++++++++-- .../test/drtio/test_rt_packet_repeater.py | 62 +++++++++++ 2 files changed, 158 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 7f709589f..150704f75 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -103,6 +103,61 @@ class RTPacketRepeater(Module): timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter + # Read + rb_chan_sel = Signal(24) + rb_timeout = Signal(64) + self.sync.rtio += If(self.cri.cmd == cri.commands["read"], + rb_chan_sel.eq(self.cri.chan_sel), + rb_timeout.eq(self.cri.timestamp)) + + read_not = Signal() + read_no_event = Signal() + read_is_overflow = Signal() + read_data = Signal(32) + read_timestamp = Signal(64) + rtio_read_not = Signal() + rtio_read_not_ack = Signal() + rtio_read_no_event = Signal() + rtio_read_is_overflow = Signal() + rtio_read_data = Signal(32) + rtio_read_timestamp = Signal(64) + self.submodules += CrossDomainNotification("rtio_rx", "rtio", + read_not, + Cat(read_no_event, read_is_overflow, read_data, read_timestamp), + + rtio_read_not, rtio_read_not_ack, + Cat(rtio_read_no_event, rtio_read_is_overflow, + rtio_read_data, rtio_read_timestamp)) + self.comb += [ + read_is_overflow.eq(rx_dp.packet_as["read_reply_noevent"].overflow), + read_data.eq(rx_dp.packet_as["read_reply"].data), + read_timestamp.eq(rx_dp.packet_as["read_reply"].timestamp) + ] + + # input status + i_status_wait_event = Signal() + i_status_overflow = Signal() + i_status_wait_status = Signal() + self.comb += self.cri.i_status.eq(Cat( + i_status_wait_event, i_status_overflow, i_status_wait_status)) + + load_read_reply = Signal() + self.sync.rtio += [ + If(load_read_reply, + i_status_wait_event.eq(0), + i_status_overflow.eq(0), + If(rtio_read_no_event, + If(rtio_read_is_overflow, + i_status_overflow.eq(1) + ).Else( + i_status_wait_event.eq(1) + ) + ), + self.cri.i_data.eq(rtio_read_data), + self.cri.i_timestamp.eq(rtio_read_timestamp) + ) + ] + # Missed commands cri_ready = Signal() self.sync.rtio += [ @@ -111,7 +166,7 @@ class RTPacketRepeater(Module): self.command_missed_cmd.eq(self.cri.cmd) ] - # TX FSM + # TX and CRI FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm @@ -126,9 +181,11 @@ class RTPacketRepeater(Module): ).Else( cri_ready.eq(1), If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), + If(self.cri.cmd == cri.commands["read"], NextState("READ")) ) ) + tx_fsm.act("SET_TIME", tx_dp.send("set_time", timestamp=tsc_value), If(tx_dp.packet_last, @@ -136,6 +193,7 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("WRITE", tx_dp.send("write", timestamp=wb_timestamp, @@ -158,26 +216,46 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("BUFFER_SPACE", tx_dp.send("buffer_space_request", destination=self.buffer_space_destination), If(tx_dp.packet_last, buffer_space_not_ack.eq(1), - NextState("WAIT_BUFFER_SPACE") + NextState("GET_BUFFER_SPACE_REPLY") ) ) - tx_fsm.act("WAIT_BUFFER_SPACE", + tx_fsm.act("GET_BUFFER_SPACE_REPLY", timeout_counter.wait.eq(1), If(timeout_counter.done, self.err_buffer_space_timeout.eq(1), - NextState("IDLE") + NextState("READY") ).Else( If(buffer_space_not, self.cri.o_buffer_space_valid.eq(1), - NextState("IDLE") + NextState("READY") ), ) ) + tx_fsm.act("READ", + i_status_wait_status.eq(1), + tx_dp.send("read_request", + chan_sel=rb_chan_sel, + timeout=rb_timeout), + rtio_read_not_ack.eq(1), + If(tx_dp.packet_last, + NextState("GET_READ_REPLY") + ) + ) + tx_fsm.act("GET_READ_REPLY", + i_status_wait_status.eq(1), + rtio_read_not_ack.eq(1), + If(rtio_read_not, + load_read_reply.eq(1), + NextState("READY") + ) + ) + # RX FSM rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) self.submodules += rx_fsm @@ -192,6 +270,8 @@ class RTPacketRepeater(Module): If(rx_dp.packet_last, Case(rx_dp.packet_type, { rx_plm.types["buffer_space_reply"]: NextState("BUFFER_SPACE"), + rx_plm.types["read_reply"]: NextState("READ_REPLY"), + rx_plm.types["read_reply_noevent"]: NextState("READ_REPLY_NOEVENT"), "default": self.err_unknown_packet_type.eq(1) }) ).Else( @@ -207,3 +287,13 @@ class RTPacketRepeater(Module): rx_buffer_space.eq(rx_dp.packet_as["buffer_space_reply"].space), NextState("INPUT") ) + rx_fsm.act("READ_REPLY", + read_not.eq(1), + read_no_event.eq(0), + NextState("INPUT") + ) + rx_fsm.act("READ_REPLY_NOEVENT", + read_not.eq(1), + read_no_event.eq(1), + NextState("INPUT") + ) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 70f25adb0..0bf80eb3d 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -128,3 +128,65 @@ class TestRepeater(unittest.TestCase): current_request = field_dict["destination"] run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) + + def test_input(self): + for nwords in range(1, 8): + pt, pr, ts, dut = create_dut(nwords) + + def read(chan_sel, timeout): + yield dut.cri.chan_sel.eq(chan_sel) + yield dut.cri.timestamp.eq(timeout) + yield dut.cri.cmd.eq(cri.commands["read"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + status = yield dut.cri.i_status + while status & 4: + yield + status = yield dut.cri.i_status + if status & 0x1: + return "timeout" + if status & 0x2: + return "overflow" + if status & 0x8: + return "destination unreachable" + return ((yield dut.cri.i_data), + (yield dut.cri.i_timestamp)) + + def send_requests(): + for timeout in range(20, 200000, 100000): + for chan_sel in range(3): + data, timestamp = yield from read(chan_sel, timeout) + self.assertEqual(data, chan_sel*2) + self.assertEqual(timestamp, timeout//2) + + i2 = yield from read(10, 400000) + self.assertEqual(i2, "timeout") + i3 = yield from read(11, 400000) + self.assertEqual(i3, "overflow") + + current_request = None + + @passive + def send_replies(): + nonlocal current_request + while True: + while current_request is None: + yield + chan_sel, timeout = current_request + if chan_sel == 10: + yield from pt.send("read_reply_noevent", overflow=0) + elif chan_sel == 11: + yield from pt.send("read_reply_noevent", overflow=1) + else: + yield from pt.send("read_reply", data=chan_sel*2, timestamp=timeout//2) + current_request = None + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(packet_type, "read_request") + self.assertEqual(trailer, []) + self.assertEqual(current_request, None) + current_request = (field_dict["chan_sel"], field_dict["timeout"]) + + run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) From eda15a596c2e40e2ae08855cef3b76260ce0fb6d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 18 Sep 2018 15:27:25 +0800 Subject: [PATCH 79/92] drtio: add buffering to repeater --- artiq/gateware/drtio/rt_packet_repeater.py | 104 +++++++++++++-------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 150704f75..1cbd45750 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -48,16 +48,57 @@ class RTPacketRepeater(Module): tsc_value_load = Signal() self.sync.rtio += If(tsc_value_load, tsc_value.eq(tsc.coarse_ts)) - # Write buffer and extra data count - wb_timestamp = Signal(64) - wb_chan_sel = Signal(24) - wb_address = Signal(16) - wb_data = Signal(512) - self.sync.rtio += If(self.cri.cmd == cri.commands["write"], - wb_timestamp.eq(self.cri.timestamp), - wb_chan_sel.eq(self.cri.chan_sel), - wb_address.eq(self.cri.o_address), - wb_data.eq(self.cri.o_data)) + # CRI buffer stage 1 + cb0_loaded = Signal() + cb0_ack = Signal() + + cb0_cmd = Signal(2) + cb0_timestamp = Signal(64) + cb0_chan_sel = Signal(24) + cb0_o_address = Signal(16) + cb0_o_data = Signal(512) + self.sync.rtio += [ + If(cb0_ack, + cb0_loaded.eq(0), + cb0_cmd.eq(cri.commands["nop"]) + ), + If(~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), + cb0_loaded.eq(1), + cb0_cmd.eq(self.cri.cmd), + cb0_timestamp.eq(self.cri.timestamp), + cb0_chan_sel.eq(self.cri.chan_sel), + cb0_o_address.eq(self.cri.o_address), + cb0_o_data.eq(self.cri.o_data) + ), + self.err_command_missed.eq(cb0_loaded & (self.cri.cmd != cri.commands["nop"])), + self.command_missed_chan_sel.eq(self.cri.chan_sel), + self.command_missed_cmd.eq(self.cri.cmd) + ] + + # CRI buffer stage 2 and write data slicer + cb_loaded = Signal() + cb_ack = Signal() + + cb_cmd = Signal(2) + cb_timestamp = Signal(64) + cb_chan_sel = Signal(24) + cb_o_address = Signal(16) + cb_o_data = Signal(512) + self.sync.rtio += [ + If(cb_ack, + cb_loaded.eq(0), + cb_cmd.eq(cri.commands["nop"]) + ), + If(~cb_loaded & cb0_loaded, + cb_loaded.eq(1), + cb_cmd.eq(cb0_cmd), + cb_timestamp.eq(cb0_timestamp), + cb_chan_sel.eq(cb0_chan_sel), + cb_o_address.eq(cb0_o_address), + cb_o_data.eq(cb0_o_data) + ) + ] + self.comb += cb0_ack.eq(~cb_loaded) wb_extra_data_cnt = Signal(8) short_data_len = tx_plm.field_length("write", "short_data") @@ -104,12 +145,6 @@ class RTPacketRepeater(Module): self.submodules += timeout_counter # Read - rb_chan_sel = Signal(24) - rb_timeout = Signal(64) - self.sync.rtio += If(self.cri.cmd == cri.commands["read"], - rb_chan_sel.eq(self.cri.chan_sel), - rb_timeout.eq(self.cri.timestamp)) - read_not = Signal() read_no_event = Signal() read_is_overflow = Signal() @@ -137,9 +172,8 @@ class RTPacketRepeater(Module): # input status i_status_wait_event = Signal() i_status_overflow = Signal() - i_status_wait_status = Signal() self.comb += self.cri.i_status.eq(Cat( - i_status_wait_event, i_status_overflow, i_status_wait_status)) + i_status_wait_event, i_status_overflow, cb0_loaded | cb_loaded)) load_read_reply = Signal() self.sync.rtio += [ @@ -158,14 +192,6 @@ class RTPacketRepeater(Module): ) ] - # Missed commands - cri_ready = Signal() - self.sync.rtio += [ - self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])), - self.command_missed_chan_sel.eq(self.cri.chan_sel), - self.command_missed_cmd.eq(self.cri.cmd) - ] - # TX and CRI FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm @@ -179,10 +205,9 @@ class RTPacketRepeater(Module): tsc_value_load.eq(1), NextState("SET_TIME") ).Else( - cri_ready.eq(1), - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), - If(self.cri.cmd == cri.commands["read"], NextState("READ")) + If(cb_cmd == cri.commands["write"], NextState("WRITE")), + If(cb_cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), + If(cb_cmd == cri.commands["read"], NextState("READ")) ) ) @@ -196,13 +221,14 @@ class RTPacketRepeater(Module): tx_fsm.act("WRITE", tx_dp.send("write", - timestamp=wb_timestamp, - chan_sel=wb_chan_sel, - address=wb_address, + timestamp=cb_timestamp, + chan_sel=cb_chan_sel, + address=cb_o_address, extra_data_cnt=wb_extra_data_cnt, - short_data=wb_data[:short_data_len]), + short_data=cb_o_data[:short_data_len]), If(tx_dp.packet_last, If(wb_extra_data_cnt == 0, + cb_ack.eq(1), NextState("IDLE") ).Else( NextState("WRITE_EXTRA") @@ -213,6 +239,7 @@ class RTPacketRepeater(Module): tx_dp.raw_stb.eq(1), extra_data_ce.eq(1), If(extra_data_last, + cb_ack.eq(1), NextState("IDLE") ) ) @@ -228,30 +255,31 @@ class RTPacketRepeater(Module): timeout_counter.wait.eq(1), If(timeout_counter.done, self.err_buffer_space_timeout.eq(1), + cb_ack.eq(1), NextState("READY") ).Else( If(buffer_space_not, self.cri.o_buffer_space_valid.eq(1), + cb_ack.eq(1), NextState("READY") ), ) ) tx_fsm.act("READ", - i_status_wait_status.eq(1), tx_dp.send("read_request", - chan_sel=rb_chan_sel, - timeout=rb_timeout), + chan_sel=cb_chan_sel, + timeout=cb_timestamp), rtio_read_not_ack.eq(1), If(tx_dp.packet_last, NextState("GET_READ_REPLY") ) ) tx_fsm.act("GET_READ_REPLY", - i_status_wait_status.eq(1), rtio_read_not_ack.eq(1), If(rtio_read_not, load_read_reply.eq(1), + cb_ack.eq(1), NextState("READY") ) ) From 970d1bf147ddcdcdda08c0b4d47c42e95986dc1a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 18 Sep 2018 15:27:52 +0800 Subject: [PATCH 80/92] drtio: add switching unittest --- artiq/gateware/test/drtio/test_switching.py | 165 ++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 artiq/gateware/test/drtio/test_switching.py diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py new file mode 100644 index 000000000..66a9c9e69 --- /dev/null +++ b/artiq/gateware/test/drtio/test_switching.py @@ -0,0 +1,165 @@ +import unittest +from types import SimpleNamespace +import random + +from migen import * + +from artiq.gateware.drtio import * +from artiq.gateware.drtio import rt_serializer, rt_packet_repeater +from artiq.gateware import rtio +from artiq.gateware.rtio import cri +from artiq.coredevice.exceptions import * +from artiq.gateware.test.drtio.packet_interface import PacketInterface + + +class DummyTransceiverPair: + def __init__(self, nwords): + a2b_k = [Signal() for _ in range(nwords)] + a2b_d = [Signal(8) for _ in range(nwords)] + b2a_k = [Signal() for _ in range(nwords)] + b2a_d = [Signal(8) for _ in range(nwords)] + + self.alice = SimpleNamespace( + encoder=SimpleNamespace(k=a2b_k, d=a2b_d), + decoders=[SimpleNamespace(k=k, d=d) for k, d in zip(b2a_k, b2a_d)], + rx_ready=1 + ) + self.bob = SimpleNamespace( + encoder=SimpleNamespace(k=b2a_k, d=b2a_d), + decoders=[SimpleNamespace(k=k, d=d) for k, d in zip(a2b_k, a2b_d)], + rx_ready=1 + ) + + +class DummyRXSynchronizer: + def resync(self, signal): + return signal + + +class DUT(Module): + def __init__(self, nwords): + self.transceivers = DummyTransceiverPair(nwords) + + self.submodules.tsc_master = rtio.TSC("async") + self.submodules.master = DRTIOMaster(self.tsc_master, + self.transceivers.alice) + self.master.rt_controller.csrs.link_up.storage.reset = 1 + + rx_synchronizer = DummyRXSynchronizer() + self.submodules.tsc_satellite = rtio.TSC("sync") + self.submodules.satellite = DRTIOSatellite( + self.tsc_satellite, self.transceivers.bob, rx_synchronizer) + self.satellite.reset.storage.reset = 0 + self.satellite.reset.storage_full.reset = 0 + self.satellite.reset_phy.storage.reset = 0 + self.satellite.reset_phy.storage_full.reset = 0 + + self.pt = PacketInterface("s2m", nwords*8) + self.pr = PacketInterface("m2s", nwords*8) + rep_if = SimpleNamespace( + rx_rt_frame=self.pt.frame, rx_rt_data=self.pt.data, + tx_rt_frame=self.pr.frame, tx_rt_data=self.pr.data) + self.submodules.repeater = rt_packet_repeater.RTPacketRepeater( + self.tsc_satellite, rep_if) + self.comb += self.satellite.cri.connect(self.repeater.cri) + + +class Testbench: + def __init__(self): + self.dut = DUT(2) + self.now = 0 + + def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) + while not (yield from self.dut.master.link_layer.rx_up.read()): + yield + yield from self.get_buffer_space() + + def get_buffer_space(self): + csrs = self.dut.master.rt_controller.csrs + yield from csrs.o_get_buffer_space.write(1) + yield + while (yield from csrs.o_wait.read()): + yield + r = (yield from csrs.o_dbg_buffer_space.read()) + return r + + def delay(self, dt): + self.now += dt + + def write(self, channel, data): + mcri = self.dut.master.cri + yield mcri.chan_sel.eq(channel) + yield mcri.timestamp.eq(self.now) + yield mcri.o_data.eq(data) + yield + yield mcri.cmd.eq(cri.commands["write"]) + yield + yield mcri.cmd.eq(cri.commands["nop"]) + yield + status = yield mcri.o_status + while status & 0x1: + yield + status = yield mcri.o_status + if status & 0x2: + return "underflow" + if status & 0x4: + return "destination unreachable" + + +class TestSwitching(unittest.TestCase): + clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, + "rio": 5, "rio_phy": 5, + "sys_with_rst": 8, "rtio_with_rst": 5} + + def test_switching(self): + tb = Testbench() + + def test(): + yield from tb.init() + tb.delay(200) + yield from tb.write(1, 20) + for _ in range(40): + yield + + current_request = None + + def get_request(): + nonlocal current_request + while current_request is None: + yield + r = current_request + current_request = None + return r + + def expect_buffer_space_request(destination, space): + packet_type, field_dict, trailer = yield from get_request() + self.assertEqual(packet_type, "buffer_space_request") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["destination"], destination) + yield from tb.dut.pt.send("buffer_space_reply", space=space) + + def expect_write(timestamp, channel, data): + packet_type, field_dict, trailer = yield from get_request() + self.assertEqual(packet_type, "write") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["timestamp"], timestamp) + self.assertEqual(field_dict["chan_sel"], channel) + self.assertEqual(field_dict["short_data"], data) + + @passive + def send_replies(): + yield from expect_buffer_space_request(0, 1) + yield from expect_write(200, 1, 20) + yield from expect_buffer_space_request(0, 1) + + unexpected = yield from get_request() + self.fail("unexpected packet: {}".format(unexpected)) + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(current_request, None) + current_request = (packet_type, field_dict, trailer) + + run_simulation(tb.dut, + {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) From 62642957cd9e36c6e87cd2ca4aabfba8c616d71b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 11:16:21 +0800 Subject: [PATCH 81/92] runtime: fix DRTIO aux channel race condition --- artiq/firmware/runtime/kern_hwreq.rs | 186 ++++++++++++++------------- artiq/firmware/runtime/main.rs | 9 +- artiq/firmware/runtime/moninj.rs | 66 ++++------ artiq/firmware/runtime/rtio_mgt.rs | 127 ++++++++++-------- artiq/firmware/runtime/sched.rs | 2 +- artiq/firmware/runtime/session.rs | 26 ++-- 6 files changed, 215 insertions(+), 201 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 631209923..aa4d21bcf 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,6 +1,6 @@ use core::cell::RefCell; use kernel_proto as kern; -use sched::{Io, Error as SchedError}; +use sched::{Io, Mutex, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; use urc::Urc; @@ -11,14 +11,20 @@ use board_artiq::spi as local_spi; #[cfg(has_drtio)] mod remote_i2c { use drtioaux; + use rtio_mgt::drtio; + use sched::{Io, Mutex}; - fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(linkno, None) { + pub fn start(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStartRequest { + destination: destination, + busno: busno + }); + match reply { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } - Ok(_) => { - error!("received unexpected aux packet"); + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); Err(()) } Err(e) => { @@ -28,49 +34,53 @@ mod remote_i2c { } } - pub fn start(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStartRequest { + pub fn restart(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cRestartRequest { destination: destination, busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) + }); + match reply { + Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { + if succeeded { Ok(()) } else { Err(()) } + } + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(()) + } } - basic_reply(linkno) } - pub fn restart(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cRestartRequest { + pub fn stop(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStopRequest { destination: destination, busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) + }); + match reply { + Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { + if succeeded { Ok(()) } else { Err(()) } + } + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(()) + } } - basic_reply(linkno) } - pub fn stop(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStopRequest { - destination: destination, - busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - basic_reply(linkno) - } - - pub fn write(linkno: u8, destination: u8, busno: u8, data: u8) -> Result { - let request = drtioaux::Packet::I2cWriteRequest { + pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u8) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cWriteRequest { destination: destination, busno: busno, data: data - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -85,16 +95,13 @@ mod remote_i2c { } } - pub fn read(linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { - let request = drtioaux::Packet::I2cReadRequest { + pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cReadRequest { destination: destination, busno: busno, ack: ack - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -113,14 +120,24 @@ mod remote_i2c { #[cfg(has_drtio)] mod remote_spi { use drtioaux; + use rtio_mgt::drtio; + use sched::{Io, Mutex}; - fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(linkno, None) { + pub fn set_config(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiSetConfigRequest { + destination: destination, + busno: busno, + flags: flags, + length: length, + div: div, + cs: cs + }); + match reply { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } - Ok(_) => { - error!("received unexpected aux packet"); + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); Err(()) } Err(e) => { @@ -130,47 +147,38 @@ mod remote_spi { } } - pub fn set_config(linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { - let request = drtioaux::Packet::SpiSetConfigRequest { - destination: destination, - busno: busno, - flags: flags, - length: length, - div: div, - cs: cs - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - basic_reply(linkno) - } - - pub fn write(linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { - let request = drtioaux::Packet::SpiWriteRequest { + pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiWriteRequest { destination: destination, busno: busno, data: data - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) + }); + match reply { + Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { + if succeeded { Ok(()) } else { Err(()) } + } + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(()) + } } - basic_reply(linkno) } - pub fn read(linkno: u8, destination: u8, busno: u8) -> Result { - let request = drtioaux::Packet::SpiReadRequest { + pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiReadRequest { destination: destination, busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } - Ok(_) => { - error!("received unexpected aux packet"); + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); Err(()) } Err(e) => { @@ -184,7 +192,7 @@ mod remote_spi { #[cfg(has_drtio)] macro_rules! dispatch { - ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ let destination = ($busno >> 16) as u8; let busno = $busno as u8; let hop = $routing_table.0[destination as usize][0]; @@ -192,27 +200,27 @@ macro_rules! dispatch { $mod_local::$func(busno, $($param, )*) } else { let linkno = hop - 1; - $mod_remote::$func(linkno, destination, busno, $($param, )*) + $mod_remote::$func($io, $aux_mutex, linkno, destination, busno, $($param, )*) } }} } #[cfg(not(has_drtio))] macro_rules! dispatch { - ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident,$mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ let busno = $busno as u8; $mod_local::$func(busno, $($param, )*) }} } -pub fn process_kern_hwreq(io: &Io, +pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, _up_destinations: &Urc>, request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { info!("resetting RTIO"); - rtio_mgt::init_core(false); + rtio_mgt::init_core(io, aux_mutex, false); kern_acknowledge() } @@ -228,42 +236,42 @@ pub fn process_kern_hwreq(io: &Io, } &kern::I2cStartRequest { busno } => { - let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); + let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cRestartRequest { busno } => { - let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); + let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cStopRequest { busno } => { - let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); + let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cWriteRequest { busno, data } => { - match dispatch!(local_i2c, remote_i2c, _routing_table, busno, write, data) { + match dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, write, data) { Ok(ack) => kern_send(io, &kern::I2cWriteReply { succeeded: true, ack: ack }), Err(_) => kern_send(io, &kern::I2cWriteReply { succeeded: false, ack: false }) } } &kern::I2cReadRequest { busno, ack } => { - match dispatch!(local_i2c, remote_i2c, _routing_table, busno, read, ack) { + match dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, read, ack) { Ok(data) => kern_send(io, &kern::I2cReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff }) } } &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { - let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, set_config, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, &kern::SpiWriteRequest { busno, data } => { - let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, write, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) } &kern::SpiReadRequest { busno } => { - match dispatch!(local_spi, remote_spi, _routing_table, busno, read) { + match dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, read) { Ok(data) => kern_send(io, &kern::SpiReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::SpiReadReply { succeeded: false, data: 0 }) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index fe7a26d91..d79de3b83 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -289,22 +289,25 @@ fn startup_ethernet() { drtio_routing::RoutingTable::default_empty())); let up_destinations = urc::Urc::new(RefCell::new( [false; drtio_routing::DEST_COUNT])); + let aux_mutex = sched::Mutex::new(); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io, &drtio_routing_table, &up_destinations); + rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations); io.spawn(4096, mgmt::thread); { + let aux_mutex = aux_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); let up_destinations = up_destinations.clone(); - io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table, &up_destinations) }); + io.spawn(16384, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { + let aux_mutex = aux_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); - io.spawn(4096, move |io| { moninj::thread(io, &drtio_routing_table) }); + io.spawn(4096, move |io| { moninj::thread(io, &aux_mutex, &drtio_routing_table) }); } #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 5ffaa96a0..8534376d5 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -3,7 +3,7 @@ use core::cell::RefCell; use io::Error as IoError; use moninj_proto::*; -use sched::{Io, TcpListener, TcpStream, Error as SchedError}; +use sched::{Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use urc::Urc; use board_misoc::clock; use board_artiq::drtio_routing; @@ -50,21 +50,16 @@ mod local_moninj { #[cfg(has_drtio)] mod remote_moninj { use drtioaux; + use rtio_mgt::drtio; + use sched::{Io, Mutex}; - pub fn read_probe(linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { - let request = drtioaux::Packet::MonitorRequest { + pub fn read_probe(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::MonitorRequest { destination: destination, channel: channel, probe: probe - }; - match drtioaux::send(linkno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::MonitorReply { value }) => return value, Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) @@ -72,33 +67,23 @@ mod remote_moninj { 0 } - pub fn inject(linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { - let request = drtioaux::Packet::InjectionRequest { + pub fn inject(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { + let _lock = aux_mutex.lock(io).unwrap(); + drtioaux::send(linkno, &drtioaux::Packet::InjectionRequest { destination: destination, channel: channel, overrd: overrd, value: value - }; - match drtioaux::send(linkno, &request) { - Ok(_) => (), - Err(e) => error!("aux packet error ({})", e) - } + }).unwrap(); } - pub fn read_injection_status(linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { - let request = drtioaux::Packet::InjectionStatusRequest { + pub fn read_injection_status(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::InjectionStatusRequest { destination: destination, channel: channel, overrd: overrd - }; - match drtioaux::send(linkno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) @@ -109,7 +94,7 @@ mod remote_moninj { #[cfg(has_drtio)] macro_rules! dispatch { - ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ let destination = ($channel >> 16) as u8; let channel = $channel as u16; let hop = $routing_table.0[destination as usize][0]; @@ -117,20 +102,20 @@ macro_rules! dispatch { local_moninj::$func(channel, $($param, )*) } else { let linkno = hop - 1; - remote_moninj::$func(linkno, destination, channel, $($param, )*) + remote_moninj::$func($io, $aux_mutex, linkno, destination, channel, $($param, )*) } }} } #[cfg(not(has_drtio))] macro_rules! dispatch { - ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ let channel = $channel as u16; local_moninj::$func(channel, $($param, )*) }} } -fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, +fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, mut stream: &mut TcpStream) -> Result<(), Error> { let mut probe_watch_list = BTreeMap::new(); let mut inject_watch_list = BTreeMap::new(); @@ -159,9 +144,9 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, let _ = inject_watch_list.remove(&(channel, overrd)); } }, - HostMessage::Inject { channel, overrd, value } => dispatch!(_routing_table, channel, inject, overrd, value), + HostMessage::Inject { channel, overrd, value } => dispatch!(io, _aux_mutex, _routing_table, channel, inject, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = dispatch!(_routing_table, channel, read_injection_status, overrd); + let value = dispatch!(io, _aux_mutex, _routing_table, channel, read_injection_status, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -178,7 +163,7 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, if clock::get_ms() > next_check { for (&(channel, probe), previous) in probe_watch_list.iter_mut() { - let current = dispatch!(_routing_table, channel, read_probe, probe); + let current = dispatch!(io, _aux_mutex, _routing_table, channel, read_probe, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, @@ -193,7 +178,7 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, } } for (&(channel, overrd), previous) in inject_watch_list.iter_mut() { - let current = dispatch!(_routing_table, channel, read_injection_status, overrd); + let current = dispatch!(io, _aux_mutex, _routing_table, channel, read_injection_status, overrd); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::InjectionStatus { channel: channel, @@ -214,17 +199,18 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, } } -pub fn thread(io: Io, routing_table: &Urc>) { +pub fn thread(io: Io, aux_mutex: &Mutex, routing_table: &Urc>) { let listener = TcpListener::new(&io, 2047); listener.listen(1383).expect("moninj: cannot listen"); loop { + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let stream = listener.accept().expect("moninj: cannot accept").into_handle(); io.spawn(16384, move |io| { let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match connection_worker(&io, &routing_table, &mut stream) { + match connection_worker(&io, &aux_mutex, &routing_table, &mut stream) { Ok(()) => {}, Err(err) => error!("moninj aborted: {}", err) } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index e3688fb57..69233dd60 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -7,6 +7,7 @@ use board_misoc::clock; use board_misoc::config; use board_artiq::drtio_routing; use sched::Io; +use sched::Mutex; #[cfg(has_rtio_crg)] pub mod crg { @@ -47,16 +48,18 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io, routing_table: &Urc>, + pub fn startup(io: &Io, aux_mutex: &Mutex, + routing_table: &Urc>, up_destinations: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); io.spawn(4096, move |io| { let routing_table = routing_table.borrow(); - link_thread(io, &routing_table, &up_destinations); + link_thread(io, &aux_mutex, &routing_table, &up_destinations); }); } @@ -87,26 +90,6 @@ pub mod drtio { } } - fn ping_remote(linkno: u8, io: &Io) -> u32 { - let mut count = 0; - loop { - if !link_rx_up(linkno) { - return 0 - } - count += 1; - if count > 200 { - return 0; - } - drtioaux::send(linkno, &drtioaux::Packet::EchoRequest).unwrap(); - io.sleep(100).unwrap(); - let pr = drtioaux::recv(linkno); - match pr { - Ok(Some(drtioaux::Packet::EchoReply)) => return count, - _ => {} - } - } - } - fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result { let max_time = clock::get_ms() + timeout as u64; loop { @@ -125,7 +108,35 @@ pub mod drtio { } } - fn sync_tsc(io: &Io, linkno: u8) -> Result<(), &'static str> { + pub fn aux_transact(io: &Io, aux_mutex: &Mutex, + linkno: u8, request: &drtioaux::Packet) -> Result { + let _lock = aux_mutex.lock(io).unwrap(); + drtioaux::send(linkno, request).unwrap(); + recv_aux_timeout(io, linkno, 200) + } + + fn ping_remote(io: &Io, aux_mutex: &Mutex, linkno: u8) -> u32 { + let mut count = 0; + loop { + if !link_rx_up(linkno) { + return 0 + } + count += 1; + if count > 100 { + return 0; + } + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::EchoRequest); + match reply { + Ok(drtioaux::Packet::EchoReply) => return count, + _ => {} + } + io.relinquish().unwrap(); + } + } + + fn sync_tsc(io: &Io, aux_mutex: &Mutex, linkno: u8) -> Result<(), &'static str> { + let _lock = aux_mutex.lock(io).unwrap(); + unsafe { (csr::DRTIO[linkno as usize].set_time_write)(1); while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {} @@ -140,14 +151,13 @@ pub mod drtio { } } - fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) + fn load_routing_table(io: &Io, aux_mutex: &Mutex, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { - drtioaux::send(linkno, &drtioaux::Packet::RoutingSetPath { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, hops: routing_table.0[i] - }).unwrap(); - let reply = recv_aux_timeout(io, linkno, 200)?; + })?; if reply != drtioaux::Packet::RoutingAck { return Err("unexpected reply"); } @@ -155,11 +165,10 @@ pub mod drtio { Ok(()) } - fn set_rank(io: &Io, linkno: u8, rank: u8) -> Result<(), &'static str> { - drtioaux::send(linkno, &drtioaux::Packet::RoutingSetRank { + fn set_rank(io: &Io, aux_mutex: &Mutex, linkno: u8, rank: u8) -> Result<(), &'static str> { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::RoutingSetRank { rank: rank - }).unwrap(); - let reply = recv_aux_timeout(io, linkno, 200)?; + })?; if reply != drtioaux::Packet::RoutingAck { return Err("unexpected reply"); } @@ -179,7 +188,8 @@ pub mod drtio { } } - fn process_unsolicited_aux(linkno: u8) { + fn process_unsolicited_aux(io: &Io, aux_mutex: &Mutex, linkno: u8) { + let _lock = aux_mutex.lock(io).unwrap(); match drtioaux::recv(linkno) { Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(None) => (), @@ -227,7 +237,7 @@ pub mod drtio { up_destinations[destination as usize] } - fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, + fn destination_survey(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; @@ -242,10 +252,10 @@ pub mod drtio { let linkno = hop - 1; if destination_up(up_destinations, destination) { if link_up(linkno) { - drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination - }).unwrap(); - match recv_aux_timeout(io, linkno, 200) { + }); + match reply { Ok(drtioaux::Packet::DestinationDownReply) => destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), @@ -263,10 +273,10 @@ pub mod drtio { } } else { if link_up(linkno) { - drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination - }).unwrap(); - match recv_aux_timeout(io, linkno, 200) { + }); + match reply { Ok(drtioaux::Packet::DestinationDownReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => { destination_set_up(routing_table, up_destinations, destination, true); @@ -281,7 +291,8 @@ pub mod drtio { } } - pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable, + pub fn link_thread(io: Io, aux_mutex: &Mutex, + routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>) { loop { for linkno in 0..csr::DRTIO.len() { @@ -289,7 +300,7 @@ pub mod drtio { if link_up(linkno) { /* link was previously up */ if link_rx_up(linkno) { - process_unsolicited_aux(linkno); + process_unsolicited_aux(&io, aux_mutex, linkno); process_local_errors(linkno); } else { info!("[LINK#{}] link is down", linkno); @@ -299,17 +310,17 @@ pub mod drtio { /* link was previously down */ if link_rx_up(linkno) { info!("[LINK#{}] link RX became up, pinging", linkno); - let ping_count = ping_remote(linkno, &io); + let ping_count = ping_remote(&io, aux_mutex, linkno); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); - if let Err(e) = sync_tsc(&io, linkno) { + if let Err(e) = sync_tsc(&io, aux_mutex, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } - if let Err(e) = load_routing_table(&io, linkno, routing_table) { + if let Err(e) = load_routing_table(&io, aux_mutex, linkno, routing_table) { error!("[LINK#{}] failed to load routing table ({})", linkno, e); } - if let Err(e) = set_rank(&io, linkno, 1) { + if let Err(e) = set_rank(&io, aux_mutex, linkno, 1) { error!("[LINK#{}] failed to set rank ({})", linkno, e); } info!("[LINK#{}] link initialization completed", linkno); @@ -319,18 +330,18 @@ pub mod drtio { } } } - destination_survey(&io, routing_table, up_destinations); + destination_survey(&io, aux_mutex, routing_table, up_destinations); io.sleep(200).unwrap(); } } - pub fn init() { + pub fn init(io: &Io, aux_mutex: &Mutex) { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; if link_up(linkno) { - drtioaux::send(linkno, - &drtioaux::Packet::ResetRequest { phy: false }).unwrap(); - match drtioaux::recv_timeout(linkno, None) { + let reply = aux_transact(io, aux_mutex, linkno, + &drtioaux::Packet::ResetRequest { phy: false }); + match reply { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) @@ -344,9 +355,10 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io, _routing_table: &Urc>, + pub fn startup(_io: &Io, _aux_mutex: &Mutex, + _routing_table: &Urc>, _up_destinations: &Urc>) {} - pub fn init() {} + pub fn init(_io: &Io, _aux_mutex: &Mutex) {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -372,7 +384,8 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io, routing_table: &Urc>, +pub fn startup(io: &Io, aux_mutex: &Mutex, + routing_table: &Urc>, up_destinations: &Urc>) { #[cfg(has_rtio_crg)] { @@ -413,17 +426,17 @@ pub fn startup(io: &Io, routing_table: &Urc } } - drtio::startup(io, routing_table, up_destinations); - init_core(true); + drtio::startup(io, aux_mutex, routing_table, up_destinations); + init_core(io, aux_mutex, true); io.spawn(4096, async_error_thread); } -pub fn init_core(phy: bool) { +pub fn init_core(io: &Io, aux_mutex: &Mutex, phy: bool) { unsafe { csr::rtio_core::reset_write(1); if phy { csr::rtio_core::reset_phy_write(1); } } - drtio::init() + drtio::init(io, aux_mutex) } diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 770ac3f6c..7a2a85723 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -273,7 +273,7 @@ impl Mutex { Mutex(Urc::new(Cell::new(false))) } - pub fn lock<'a>(&'a self, io: Io) -> Result, Error> { + pub fn lock<'a>(&'a self, io: &Io) -> Result, Error> { io.until(|| !self.0.get())?; self.0.set(true); Ok(MutexGuard(&*self.0)) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index e413e8749..ae23c3410 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -6,7 +6,7 @@ use io::{Read, Write, Error as IoError}; use board_misoc::{ident, cache, config}; use {mailbox, rpc_queue, kernel}; use urc::Urc; -use sched::{ThreadHandle, Io, TcpListener, TcpStream, Error as SchedError}; +use sched::{ThreadHandle, Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use rtio_mgt; use rtio_dma::Manager as DmaManager; use cache::Cache; @@ -324,7 +324,7 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, +fn process_kern_message(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, mut stream: Option<&mut TcpStream>, @@ -345,7 +345,7 @@ fn process_kern_message(io: &Io, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, routing_table, up_destinations, request)? { + if kern_hwreq::process_kern_hwreq(io, aux_mutex, routing_table, up_destinations, request)? { return Ok(false) } @@ -494,7 +494,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, +fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, stream: &mut TcpStream, @@ -513,7 +513,7 @@ fn host_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - process_kern_message(io, + process_kern_message(io, aux_mutex, routing_table, up_destinations, Some(stream), &mut session)?; } @@ -534,7 +534,7 @@ fn host_kernel_worker(io: &Io, } } -fn flash_kernel_worker(io: &Io, +fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, congress: &mut Congress, @@ -559,7 +559,7 @@ fn flash_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - if process_kern_message(io, routing_table, up_destinations, None, &mut session)? { + if process_kern_message(io, aux_mutex, routing_table, up_destinations, None, &mut session)? { return Ok(()) } } @@ -591,7 +591,8 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io, routing_table: &Urc>, +pub fn thread(io: Io, aux_mutex: &Mutex, + routing_table: &Urc>, up_destinations: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); @@ -601,6 +602,7 @@ pub fn thread(io: Io, routing_table: &Urc>, let mut kernel_thread = None; { + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); @@ -608,7 +610,7 @@ pub fn thread(io: Io, routing_table: &Urc>, let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -637,6 +639,7 @@ pub fn thread(io: Io, routing_table: &Urc>, } info!("new connection from {}", stream.remote_endpoint()); + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); @@ -645,7 +648,7 @@ pub fn thread(io: Io, routing_table: &Urc>, let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &routing_table, &up_destinations, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -663,13 +666,14 @@ pub fn thread(io: Io, routing_table: &Urc>, if kernel_thread.as_ref().map_or(true, |h| h.terminated()) { info!("no connection, starting idle kernel"); + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( From 142c952e3d24fba16c48df7c2e58ab78a5baf3c6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:03:15 +0800 Subject: [PATCH 82/92] drtio: implement per-destination underflow margins --- .../firmware/libboard_artiq/drtio_routing.rs | 12 ++++++++++ artiq/firmware/runtime/rtio_mgt.rs | 23 +++++++++++++++++++ artiq/gateware/drtio/rt_controller_master.py | 16 +++++++++++-- artiq/gateware/test/drtio/test_full_stack.py | 3 +-- artiq/gateware/test/drtio/test_switching.py | 1 - 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 562517342..6c8469ae2 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -30,6 +30,18 @@ impl RoutingTable { pub fn default_empty() -> RoutingTable { RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) } + + pub fn hop_count(&self, destination: u8) -> u8 { + let mut count = 0; + for i in 0..MAX_HOPS { + if self.0[destination as usize][i] == INVALID_HOP { + break; + } else { + count += 1; + } + } + count + } } impl fmt::Display for RoutingTable { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 69233dd60..95b43c586 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,6 +54,12 @@ pub mod drtio { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + + { + let routing_table = routing_table.borrow(); + program_underflow_margins(&routing_table); + } + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); @@ -63,6 +69,23 @@ pub mod drtio { }); } + fn program_underflow_margins(routing_table: &drtio_routing::RoutingTable) { + for destination in 0..drtio_routing::DEST_COUNT { + let hop_count = routing_table.hop_count(destination as u8); + if hop_count > 1 { + let underflow_margin = (hop_count as u16 - 1)*300; + info!("[DEST#{}] setting underflow margin to {}", destination, underflow_margin); + let linkno = (routing_table.0[destination][0] - 1) as usize; + unsafe { + (csr::DRTIO[linkno].destination_write)(destination as u8); + (csr::DRTIO[linkno].force_destination_write)(1); + (csr::DRTIO[linkno].set_underflow_margin_write)(underflow_margin); + (csr::DRTIO[linkno].force_destination_write)(0); + } + } + } + } + fn link_rx_up(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 40014dce0..3209f1739 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -17,11 +17,13 @@ class _CSRs(AutoCSR): self.protocol_error = CSR(3) self.set_time = CSR() - self.underflow_margin = CSRStorage(16, reset=300) self.force_destination = CSRStorage() self.destination = CSRStorage(8) + self.set_underflow_margin = CSRStorage(16) + self.dbg_underflow_margin = CSRStatus(16) + self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -116,9 +118,19 @@ class RTController(Module): timeout_counter = WaitTimer(8191) self.submodules += timeout_counter + underflow_margin = Memory(16, 256, init=[100]*256) + underflow_margin_port = underflow_margin.get_port(write_capable=True) + self.specials += underflow_margin, underflow_margin_port + self.comb += [ + underflow_margin_port.adr.eq(chan_sel[16:]), + underflow_margin_port.dat_w.eq(self.csrs.set_underflow_margin.storage), + underflow_margin_port.we.eq(self.csrs.set_underflow_margin.re), + self.csrs.dbg_underflow_margin.status.eq(underflow_margin_port.dat_r) + ] + cond_underflow = Signal() self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] - - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) + - underflow_margin_port.dat_r[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) # buffer space buffer_space = Memory(16, 256) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 579d78f9b..a4e239b99 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -89,7 +89,6 @@ class OutputsTestbench: self.now = 0 def init(self): - yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() @@ -228,7 +227,7 @@ class TestFullStack(unittest.TestCase): yield from tb.init() errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) - yield from csrs.underflow_margin.write(0) + yield from csrs.set_underflow_margin.write(0) tb.delay(100) yield from tb.write(42, 1) for i in range(12): diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 66a9c9e69..589115abe 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -70,7 +70,6 @@ class Testbench: self.now = 0 def init(self): - yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() From 3d965910f7e326467c84bc35d5ab68b7b5250025 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:05:48 +0800 Subject: [PATCH 83/92] Revert "drtio: implement per-destination underflow margins" This reverts commit 142c952e3d24fba16c48df7c2e58ab78a5baf3c6. --- .../firmware/libboard_artiq/drtio_routing.rs | 12 ---------- artiq/firmware/runtime/rtio_mgt.rs | 23 ------------------- artiq/gateware/drtio/rt_controller_master.py | 16 ++----------- artiq/gateware/test/drtio/test_full_stack.py | 3 ++- artiq/gateware/test/drtio/test_switching.py | 1 + 5 files changed, 5 insertions(+), 50 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 6c8469ae2..562517342 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -30,18 +30,6 @@ impl RoutingTable { pub fn default_empty() -> RoutingTable { RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) } - - pub fn hop_count(&self, destination: u8) -> u8 { - let mut count = 0; - for i in 0..MAX_HOPS { - if self.0[destination as usize][i] == INVALID_HOP { - break; - } else { - count += 1; - } - } - count - } } impl fmt::Display for RoutingTable { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 95b43c586..69233dd60 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,12 +54,6 @@ pub mod drtio { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } - - { - let routing_table = routing_table.borrow(); - program_underflow_margins(&routing_table); - } - let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); @@ -69,23 +63,6 @@ pub mod drtio { }); } - fn program_underflow_margins(routing_table: &drtio_routing::RoutingTable) { - for destination in 0..drtio_routing::DEST_COUNT { - let hop_count = routing_table.hop_count(destination as u8); - if hop_count > 1 { - let underflow_margin = (hop_count as u16 - 1)*300; - info!("[DEST#{}] setting underflow margin to {}", destination, underflow_margin); - let linkno = (routing_table.0[destination][0] - 1) as usize; - unsafe { - (csr::DRTIO[linkno].destination_write)(destination as u8); - (csr::DRTIO[linkno].force_destination_write)(1); - (csr::DRTIO[linkno].set_underflow_margin_write)(underflow_margin); - (csr::DRTIO[linkno].force_destination_write)(0); - } - } - } - } - fn link_rx_up(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 3209f1739..40014dce0 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -17,13 +17,11 @@ class _CSRs(AutoCSR): self.protocol_error = CSR(3) self.set_time = CSR() + self.underflow_margin = CSRStorage(16, reset=300) self.force_destination = CSRStorage() self.destination = CSRStorage(8) - self.set_underflow_margin = CSRStorage(16) - self.dbg_underflow_margin = CSRStatus(16) - self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -118,19 +116,9 @@ class RTController(Module): timeout_counter = WaitTimer(8191) self.submodules += timeout_counter - underflow_margin = Memory(16, 256, init=[100]*256) - underflow_margin_port = underflow_margin.get_port(write_capable=True) - self.specials += underflow_margin, underflow_margin_port - self.comb += [ - underflow_margin_port.adr.eq(chan_sel[16:]), - underflow_margin_port.dat_w.eq(self.csrs.set_underflow_margin.storage), - underflow_margin_port.we.eq(self.csrs.set_underflow_margin.re), - self.csrs.dbg_underflow_margin.status.eq(underflow_margin_port.dat_r) - ] - cond_underflow = Signal() self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] - - underflow_margin_port.dat_r[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) + - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) # buffer space buffer_space = Memory(16, 256) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index a4e239b99..579d78f9b 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -89,6 +89,7 @@ class OutputsTestbench: self.now = 0 def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() @@ -227,7 +228,7 @@ class TestFullStack(unittest.TestCase): yield from tb.init() errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) - yield from csrs.set_underflow_margin.write(0) + yield from csrs.underflow_margin.write(0) tb.delay(100) yield from tb.write(42, 1) for i in range(12): diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 589115abe..66a9c9e69 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -70,6 +70,7 @@ class Testbench: self.now = 0 def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() From 08be1763690ed1e8453b34e356f3f446919cada6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:50:18 +0800 Subject: [PATCH 84/92] drtio: fix satellite i_status handling --- artiq/gateware/drtio/rt_packet_satellite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 49ea2c3d0..a045c020d 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -201,8 +201,8 @@ class RTPacketSatellite(Module): tx_fsm.act("IDLE", If(echo_req, NextState("ECHO")), If(buffer_space_req, NextState("BUFFER_SPACE")), - If(read_request_pending, - If(~self.cri.i_status[2], NextState("READ")), + If(read_request_pending & ~self.cri.i_status[2], + NextState("READ"), If(self.cri.i_status[0], NextState("READ_TIMEOUT")), If(self.cri.i_status[1], NextState("READ_OVERFLOW")) ) From b86b6dcc0965698c673cc22f1586aaa9d05b517f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:50:29 +0800 Subject: [PATCH 85/92] drtio: add switching input test --- artiq/gateware/test/drtio/test_switching.py | 90 ++++++++++++++++++++- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 66a9c9e69..2d3330484 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -69,11 +69,12 @@ class Testbench: self.dut = DUT(2) self.now = 0 - def init(self): + def init(self, with_buffer_space=True): yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield - yield from self.get_buffer_space() + if with_buffer_space: + yield from self.get_buffer_space() def get_buffer_space(self): csrs = self.dut.master.rt_controller.csrs @@ -106,13 +107,35 @@ class Testbench: if status & 0x4: return "destination unreachable" + def read(self, channel, timeout): + mcri = self.dut.master.cri + yield mcri.chan_sel.eq(channel) + yield mcri.timestamp.eq(timeout) + yield + yield mcri.cmd.eq(cri.commands["read"]) + yield + yield mcri.cmd.eq(cri.commands["nop"]) + yield + status = yield mcri.i_status + while status & 0x4: + yield + status = yield mcri.i_status + if status & 0x1: + return "timeout" + if status & 0x2: + return "overflow" + if status & 0x8: + return "destination unreachable" + return ((yield mcri.i_timestamp), + (yield mcri.i_data)) + class TestSwitching(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, "rio": 5, "rio_phy": 5, "sys_with_rst": 8, "rtio_with_rst": 5} - def test_switching(self): + def test_outputs(self): tb = Testbench() def test(): @@ -163,3 +186,64 @@ class TestSwitching(unittest.TestCase): run_simulation(tb.dut, {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) + + + def test_inputs(self): + tb = Testbench() + + def test(): + yield from tb.init(with_buffer_space=False) + reply = yield from tb.read(19, 145) + self.assertEqual(reply, (333, 23)) + reply = yield from tb.read(20, 146) + self.assertEqual(reply, (334, 24)) + reply = yield from tb.read(10, 34) + self.assertEqual(reply, "timeout") + reply = yield from tb.read(1, 20) + self.assertEqual(reply, "overflow") + reply = yield from tb.read(21, 147) + self.assertEqual(reply, (335, 25)) + for _ in range(40): + yield + + current_request = None + + def get_request(): + nonlocal current_request + while current_request is None: + yield + r = current_request + current_request = None + return r + + def expect_read(chan_sel, timeout, reply): + packet_type, field_dict, trailer = yield from get_request() + self.assertEqual(packet_type, "read_request") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["chan_sel"], chan_sel) + self.assertEqual(field_dict["timeout"], timeout) + if reply == "timeout": + yield from tb.dut.pt.send("read_reply_noevent", overflow=0) + elif reply == "overflow": + yield from tb.dut.pt.send("read_reply_noevent", overflow=1) + else: + timestamp, data = reply + yield from tb.dut.pt.send("read_reply", timestamp=timestamp, data=data) + + @passive + def send_replies(): + yield from expect_read(19, 145, (333, 23)) + yield from expect_read(20, 146, (334, 24)) + yield from expect_read(10, 34, "timeout") + yield from expect_read(1, 20, "overflow") + yield from expect_read(21, 147, (335, 25)) + unexpected = yield from get_request() + self.fail("unexpected packet: {}".format(unexpected)) + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(current_request, None) + current_request = (packet_type, field_dict, trailer) + + run_simulation(tb.dut, + {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) From 251d90c3d5c44e301a588c82c0dc0527da7b4cf1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 08:53:45 +0800 Subject: [PATCH 86/92] drtio: clear read request in satellite only after reply has been fully sent Otherwise, chan_sel become invalid before the end of the packet, which can cause the interconnect to invalidate i_timestamp and i_data which results in corruption of the end of the packet. --- artiq/gateware/drtio/rt_packet_satellite.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index a045c020d..557640749 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -227,16 +227,14 @@ class RTPacketSatellite(Module): tx_fsm.act("READ_OVERFLOW", tx_dp.send("read_reply_noevent", overflow=1), clear_read_request.eq(1), - If(tx_dp.packet_last, - NextState("IDLE") - ) + If(tx_dp.packet_last, NextState("IDLE")) ) tx_fsm.act("READ", tx_dp.send("read_reply", timestamp=self.cri.i_timestamp, data=self.cri.i_data), - clear_read_request.eq(1), If(tx_dp.packet_last, + clear_read_request.eq(1), NextState("IDLE") ) ) From 53a979e74d8ed11a4d6078f467e7d204246e2ac4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 10:58:38 +0800 Subject: [PATCH 87/92] rtio: cleanup resets --- artiq/firmware/runtime/kern_hwreq.rs | 2 +- artiq/firmware/runtime/main.rs | 3 +- artiq/firmware/runtime/rtio_mgt.rs | 64 ++++++++----------- artiq/firmware/satman/main.rs | 1 + artiq/firmware/satman/repeater.rs | 8 +++ artiq/gateware/drtio/rt_controller_master.py | 26 ++------ .../gateware/drtio/rt_controller_repeater.py | 4 ++ artiq/gateware/drtio/rt_packet_master.py | 2 +- artiq/gateware/drtio/rt_packet_repeater.py | 13 ++-- artiq/gateware/test/drtio/test_full_stack.py | 4 +- artiq/gateware/test/drtio/test_switching.py | 4 +- 11 files changed, 61 insertions(+), 70 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index aa4d21bcf..008a3e9ec 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -220,7 +220,7 @@ pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex, match request { &kern::RtioInitRequest => { info!("resetting RTIO"); - rtio_mgt::init_core(io, aux_mutex, false); + rtio_mgt::reset(io, aux_mutex); kern_acknowledge() } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index d79de3b83..b3e2bbb94 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,5 +1,6 @@ #![feature(lang_items, alloc, try_from, nonzero, asm, - panic_implementation, panic_info_message)] + panic_implementation, panic_info_message, + const_slice_len)] #![no_std] extern crate eh; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 69233dd60..cedfb8686 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -70,26 +70,6 @@ pub mod drtio { } } - pub fn link_up(linkno: u8) -> bool { - let linkno = linkno as usize; - /* This function may be called by kernels with arbitrary - * linkno values. - */ - if linkno >= csr::DRTIO.len() { - return false; - } - unsafe { - (csr::DRTIO[linkno].link_up_read)() == 1 - } - } - - fn set_link_up(linkno: u8, up: bool) { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].link_up_write)(if up { 1 } else { 0 }); - } - } - fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result { let max_time = clock::get_ms() + timeout as u64; loop { @@ -238,6 +218,7 @@ pub mod drtio { } fn destination_survey(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, + up_links: &[bool], up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; @@ -251,7 +232,7 @@ pub mod drtio { } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; if destination_up(up_destinations, destination) { - if link_up(linkno) { + if up_links[linkno as usize] { let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination }); @@ -272,7 +253,7 @@ pub mod drtio { destination_set_up(routing_table, up_destinations, destination, false); } } else { - if link_up(linkno) { + if up_links[linkno as usize] { let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination }); @@ -294,17 +275,18 @@ pub mod drtio { pub fn link_thread(io: Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>) { + let mut up_links = [false; csr::DRTIO.len()]; loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if link_up(linkno) { + if up_links[linkno as usize] { /* link was previously up */ if link_rx_up(linkno) { process_unsolicited_aux(&io, aux_mutex, linkno); process_local_errors(linkno); } else { info!("[LINK#{}] link is down", linkno); - set_link_up(linkno, false); + up_links[linkno as usize] = false; } } else { /* link was previously down */ @@ -313,7 +295,7 @@ pub mod drtio { let ping_count = ping_remote(&io, aux_mutex, linkno); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); - set_link_up(linkno, true); + up_links[linkno as usize] = true; if let Err(e) = sync_tsc(&io, aux_mutex, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } @@ -330,15 +312,27 @@ pub mod drtio { } } } - destination_survey(&io, aux_mutex, routing_table, up_destinations); + destination_survey(&io, aux_mutex, routing_table, &up_links, up_destinations); io.sleep(200).unwrap(); } } - pub fn init(io: &Io, aux_mutex: &Mutex) { + pub fn reset(io: &Io, aux_mutex: &Mutex) { + for linkno in 0..csr::DRTIO.len() { + unsafe { + (csr::DRTIO[linkno].reset_write)(1); + } + } + io.sleep(1).unwrap(); + for linkno in 0..csr::DRTIO.len() { + unsafe { + (csr::DRTIO[linkno].reset_write)(0); + } + } + for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if link_up(linkno) { + if link_rx_up(linkno) { let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::ResetRequest { phy: false }); match reply { @@ -358,8 +352,7 @@ pub mod drtio { pub fn startup(_io: &Io, _aux_mutex: &Mutex, _routing_table: &Urc>, _up_destinations: &Urc>) {} - pub fn init(_io: &Io, _aux_mutex: &Mutex) {} - pub fn link_up(_linkno: u8) -> bool { false } + pub fn reset(_io: &Io, _aux_mutex: &Mutex) {} } fn async_error_thread(io: Io) { @@ -425,18 +418,17 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, } } } + unsafe { + csr::rtio_core::reset_phy_write(1); + } drtio::startup(io, aux_mutex, routing_table, up_destinations); - init_core(io, aux_mutex, true); io.spawn(4096, async_error_thread); } -pub fn init_core(io: &Io, aux_mutex: &Mutex, phy: bool) { +pub fn reset(io: &Io, aux_mutex: &Mutex) { unsafe { csr::rtio_core::reset_write(1); - if phy { - csr::rtio_core::reset_phy_write(1); - } } - drtio::init(io, aux_mutex) + drtio::reset(io, aux_mutex) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1e69111b2..bc12bccfd 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -82,6 +82,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtiosat_reset_phy(false); } else { drtiosat_reset(true); + clock::spin_us(100); drtiosat_reset(false); } for rep in _repeaters.iter() { diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index d5b04a94f..ca0531ac5 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -243,9 +243,17 @@ impl Repeater { } pub fn rtio_reset(&self, phy: bool) -> Result<(), drtioaux::Error> { + let repno = self.repno as usize; + if !phy { + unsafe { (csr::DRTIOREP[repno].reset_write)(1); } + clock::spin_us(100); + unsafe { (csr::DRTIOREP[repno].reset_write)(0); } + } + if self.state != RepeaterState::Up { return Ok(()); } + drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest { phy: phy }).unwrap(); diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 40014dce0..0126184c6 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -3,7 +3,6 @@ from migen import * from migen.genlib.cdc import MultiReg from migen.genlib.misc import WaitTimer -from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * @@ -12,7 +11,7 @@ from artiq.gateware.rtio import cri class _CSRs(AutoCSR): def __init__(self): - self.link_up = CSRStorage() + self.reset = CSRStorage() self.protocol_error = CSR(3) @@ -33,25 +32,12 @@ class RTController(Module): self.csrs = _CSRs() self.cri = cri.Interface() - # reset - local_reset = Signal(reset=1) - self.sync += local_reset.eq(~self.csrs.link_up.storage) - local_reset.attr.add("no_retiming") - self.clock_domains.cd_sys_with_rst = ClockDomain() - self.clock_domains.cd_rtio_with_rst = ClockDomain() - self.comb += [ - self.cd_sys_with_rst.clk.eq(ClockSignal()), - self.cd_sys_with_rst.rst.eq(local_reset) - ] - self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) - self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) - # protocol errors err_unknown_packet_type = Signal() err_packet_truncated = Signal() signal_buffer_space_timeout = Signal() err_buffer_space_timeout = Signal() - self.sync.sys_with_rst += [ + self.sync += [ If(self.csrs.protocol_error.re, If(self.csrs.protocol_error.r[0], err_unknown_packet_type.eq(0)), If(self.csrs.protocol_error.r[1], err_packet_truncated.eq(0)), @@ -106,7 +92,7 @@ class RTController(Module): self.csrs.o_wait.status.eq(o_status_wait) ] o_underflow_set = Signal() - self.sync.sys_with_rst += [ + self.sync += [ If(self.cri.cmd == cri.commands["write"], o_status_underflow.eq(0) ), @@ -145,7 +131,7 @@ class RTController(Module): i_status_wait_event, i_status_overflow, i_status_wait_status)) load_read_reply = Signal() - self.sync.sys_with_rst += [ + self.sync += [ If(load_read_reply, i_status_wait_event.eq(0), i_status_overflow.eq(0), @@ -162,7 +148,7 @@ class RTController(Module): ] # FSM - fsm = ClockDomainsRenamer("sys_with_rst")(FSM()) + fsm = FSM() self.submodules += fsm fsm.act("IDLE", @@ -226,7 +212,7 @@ class RTController(Module): fsm.act("GET_READ_REPLY", i_status_wait_status.eq(1), rt_packet.read_not_ack.eq(1), - If(rt_packet.read_not, + If(self.csrs.reset.storage | rt_packet.read_not, load_read_reply.eq(1), NextState("IDLE") ) diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index b877700b1..4cd192054 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -1,4 +1,5 @@ from migen import * +from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * @@ -8,12 +9,15 @@ from artiq.gateware.drtio.cdc import CrossDomainRequest class RTController(Module, AutoCSR): def __init__(self, rt_packet): + self.reset = CSRStorage() self.set_time = CSR() self.protocol_error = CSR(4) self.command_missed_cmd = CSRStatus(2) self.command_missed_chan_sel = CSRStatus(24) self.buffer_space_timeout_dest = CSRStatus(8) + self.specials += MultiReg(self.reset.storage, rt_packet.reset, "rtio") + set_time_stb = Signal() set_time_ack = Signal() self.submodules += CrossDomainRequest("rtio", diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 42370a09d..f91ac7667 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -84,7 +84,7 @@ class RTPacketMaster(Module): self.submodules += rx_dp # Write FIFO and extra data count - sr_fifo = ClockDomainsRenamer({"write": "sys_with_rst", "read": "rtio_with_rst"})( + sr_fifo = ClockDomainsRenamer({"write": "sys", "read": "rtio"})( AsyncFIFO(1+64+24+16+512, sr_fifo_depth)) self.submodules += sr_fifo sr_notwrite_d = Signal() diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 1cbd45750..4788283f9 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -10,6 +10,9 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketRepeater(Module): def __init__(self, tsc, link_layer): + # in rtio domain + self.reset = Signal() + # CRI target interface in rtio domain self.cri = cri.Interface() @@ -58,11 +61,11 @@ class RTPacketRepeater(Module): cb0_o_address = Signal(16) cb0_o_data = Signal(512) self.sync.rtio += [ - If(cb0_ack, + If(self.reset | cb0_ack, cb0_loaded.eq(0), cb0_cmd.eq(cri.commands["nop"]) ), - If(~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), + If(~self.reset & ~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), cb0_loaded.eq(1), cb0_cmd.eq(self.cri.cmd), cb0_timestamp.eq(self.cri.timestamp), @@ -85,11 +88,11 @@ class RTPacketRepeater(Module): cb_o_address = Signal(16) cb_o_data = Signal(512) self.sync.rtio += [ - If(cb_ack, + If(self.reset | cb_ack, cb_loaded.eq(0), cb_cmd.eq(cri.commands["nop"]) ), - If(~cb_loaded & cb0_loaded, + If(~self.reset & ~cb_loaded & cb0_loaded, cb_loaded.eq(1), cb_cmd.eq(cb0_cmd), cb_timestamp.eq(cb0_timestamp), @@ -277,7 +280,7 @@ class RTPacketRepeater(Module): ) tx_fsm.act("GET_READ_REPLY", rtio_read_not_ack.eq(1), - If(rtio_read_not, + If(self.reset | rtio_read_not, load_read_reply.eq(1), cb_ack.eq(1), NextState("READY") diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 579d78f9b..e9bc6160a 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -57,7 +57,6 @@ class DUT(Module): self.transceivers.alice) self.submodules.master_ki = rtio.KernelInitiator(self.tsc_master, self.master.cri) - self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() self.submodules.phy0 = ttl_simple.Output(self.ttl0) @@ -146,8 +145,7 @@ class OutputsTestbench: class TestFullStack(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, - "rio": 5, "rio_phy": 5, - "sys_with_rst": 8, "rtio_with_rst": 5} + "rio": 5, "rio_phy": 5} def test_pulses(self): tb = OutputsTestbench() diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 2d3330484..eb691fcf7 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -43,7 +43,6 @@ class DUT(Module): self.submodules.tsc_master = rtio.TSC("async") self.submodules.master = DRTIOMaster(self.tsc_master, self.transceivers.alice) - self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() self.submodules.tsc_satellite = rtio.TSC("sync") @@ -132,8 +131,7 @@ class Testbench: class TestSwitching(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, - "rio": 5, "rio_phy": 5, - "sys_with_rst": 8, "rtio_with_rst": 5} + "rio": 5, "rio_phy": 5} def test_outputs(self): tb = Testbench() From 1b7f403a4b832a312fc3ef76f23e1844753867a6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 11:10:32 +0800 Subject: [PATCH 88/92] drtio: remove remote RTIO PHY resets --- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 12 ++++-------- artiq/firmware/runtime/rtio_mgt.rs | 4 ++-- artiq/firmware/satman/main.rs | 15 +++++---------- artiq/firmware/satman/repeater.rs | 16 ++++++---------- 4 files changed, 17 insertions(+), 30 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 3d526734d..64e279614 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -18,7 +18,7 @@ impl From> for Error { pub enum Packet { EchoRequest, EchoReply, - ResetRequest { phy: bool }, + ResetRequest, ResetAck, TSCAck, @@ -62,9 +62,7 @@ impl Packet { Ok(match reader.read_u8()? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, - 0x02 => Packet::ResetRequest { - phy: reader.read_bool()? - }, + 0x02 => Packet::ResetRequest, 0x03 => Packet::ResetAck, 0x04 => Packet::TSCAck, @@ -192,10 +190,8 @@ impl Packet { writer.write_u8(0x00)?, Packet::EchoReply => writer.write_u8(0x01)?, - Packet::ResetRequest { phy } => { - writer.write_u8(0x02)?; - writer.write_bool(phy)?; - }, + Packet::ResetRequest => + writer.write_u8(0x02)?, Packet::ResetAck => writer.write_u8(0x03)?, Packet::TSCAck => diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index cedfb8686..726edc886 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -334,7 +334,7 @@ pub mod drtio { let linkno = linkno as u8; if link_rx_up(linkno) { let reply = aux_transact(io, aux_mutex, linkno, - &drtioaux::Packet::ResetRequest { phy: false }); + &drtioaux::Packet::ResetRequest); match reply { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), @@ -419,7 +419,7 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, } } unsafe { - csr::rtio_core::reset_phy_write(1); + csr::rtio_core::reset_phy_write(1); } drtio::startup(io, aux_mutex, routing_table, up_destinations); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index bc12bccfd..22fb5cd75 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -75,18 +75,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], match packet { drtioaux::Packet::EchoRequest => drtioaux::send(0, &drtioaux::Packet::EchoReply), - drtioaux::Packet::ResetRequest { phy } => { + drtioaux::Packet::ResetRequest => { info!("resetting RTIO"); - if phy { - drtiosat_reset_phy(true); - drtiosat_reset_phy(false); - } else { - drtiosat_reset(true); - clock::spin_us(100); - drtiosat_reset(false); - } + drtiosat_reset(true); + clock::spin_us(100); + drtiosat_reset(false); for rep in _repeaters.iter() { - if let Err(e) = rep.rtio_reset(phy) { + if let Err(e) = rep.rtio_reset() { error!("failed to issue RTIO reset ({})", e); } } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index ca0531ac5..f51d413aa 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -242,21 +242,17 @@ impl Repeater { Ok(()) } - pub fn rtio_reset(&self, phy: bool) -> Result<(), drtioaux::Error> { + pub fn rtio_reset(&self) -> Result<(), drtioaux::Error> { let repno = self.repno as usize; - if !phy { - unsafe { (csr::DRTIOREP[repno].reset_write)(1); } - clock::spin_us(100); - unsafe { (csr::DRTIOREP[repno].reset_write)(0); } - } + unsafe { (csr::DRTIOREP[repno].reset_write)(1); } + clock::spin_us(100); + unsafe { (csr::DRTIOREP[repno].reset_write)(0); } if self.state != RepeaterState::Up { return Ok(()); } - drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest { - phy: phy - }).unwrap(); + drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::ResetAck { return Err(drtioaux::Error::UnexpectedReply); @@ -278,5 +274,5 @@ impl Repeater { pub fn sync_tsc(&self) -> Result<(), drtioaux::Error> { Ok(()) } - pub fn rtio_reset(&self, _phy: bool) -> Result<(), drtioaux::Error> { Ok(()) } + pub fn rtio_reset(&self) -> Result<(), drtioaux::Error> { Ok(()) } } From 73f0de7c79a34e07235de861663e4e6960a1c034 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 11:15:45 +0800 Subject: [PATCH 89/92] sayma: DRTIO master fixes --- artiq/gateware/targets/sayma_amc.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 0c731002a..499cd55ca 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -314,6 +314,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtio", drtio_csr_group) self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) @@ -379,8 +380,11 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri) + [self.rtio_core.cri] + drtio_cri, + enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) @@ -469,6 +473,7 @@ class Master(MiniSoC, AMPSoC): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtio", drtio_csr_group) self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) @@ -532,8 +537,11 @@ class Master(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri) + [self.rtio_core.cri] + drtio_cri, + enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") class Satellite(BaseSoC, RTMCommon): From 212892d92f4fcb1c46823f86e1ed3401e73b7f89 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Sep 2018 10:13:33 +0800 Subject: [PATCH 90/92] style --- artiq/gateware/targets/kasli.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9c37c2220..cbe9645cc 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -27,8 +27,8 @@ from artiq.build_soc import * class _RTIOCRG(Module, AutoCSR): def __init__(self, platform): - self._pll_reset = CSRStorage(reset=1) - self._pll_locked = CSRStatus() + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) @@ -60,7 +60,7 @@ class _RTIOCRG(Module, AutoCSR): # VCO @ 1GHz when using 125MHz input p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, i_CLKFBIN=self.cd_rtio.clk, - i_RST=self._pll_reset.storage, + i_RST=self.pll_reset.storage, o_CLKFBOUT=rtio_clk, @@ -70,7 +70,7 @@ class _RTIOCRG(Module, AutoCSR): Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self._pll_locked.status) + MultiReg(pll_locked, self.pll_locked.status) ] From b92350b0f6cce35c16138329bad6e8fde2bd3ee2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Sep 2018 10:52:08 +0800 Subject: [PATCH 91/92] drtio: monitor RTIOClockMultiplier PLL (#1155) Debugging by Tom Harty --- artiq/firmware/runtime/rtio_mgt.rs | 5 ++++- artiq/firmware/satman/main.rs | 18 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 18 +++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 726edc886..00f9cc3ef 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -380,6 +380,10 @@ fn async_error_thread(io: Io) { pub fn startup(io: &Io, aux_mutex: &Mutex, routing_table: &Urc>, up_destinations: &Urc>) { + // The RTIO CRG may depend on the DRTIO transceiver clock. + // Initialize DRTIO first to bring up transceiver clocking. + drtio::startup(io, aux_mutex, routing_table, up_destinations); + #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -422,7 +426,6 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, csr::rtio_core::reset_phy_write(1); } - drtio::startup(io, aux_mutex, routing_table, up_destinations); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 22fb5cd75..89efeef68 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -351,6 +351,23 @@ fn drtiosat_process_errors() { } } + +#[cfg(has_rtio_crg)] +fn init_rtio_crg() { + unsafe { + csr::rtio_crg::pll_reset_write(0); + } + clock::spin_us(150); + let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 }; + if !locked { + error!("RTIO clock failed"); + } +} + +#[cfg(not(has_rtio_crg))] +fn init_rtio_crg() { } + + #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -388,6 +405,7 @@ pub extern fn main() -> i32 { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + init_rtio_crg(); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index cbe9645cc..00c2d68b8 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -592,19 +592,23 @@ class Tester(_StandaloneBase): self.add_rtio(self.rtio_channels) -class _RTIOClockMultiplier(Module): +class _RTIOClockMultiplier(Module, AutoCSR): def __init__(self, rtio_clk_freq): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) # See "Global Clock Network Deskew Using Two BUFGs" in ug472. clkfbout = Signal() clkfbin = Signal() rtiox4_clk = Signal() + pll_locked = Signal() self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio"), - i_RST=ResetSignal("rtio"), + i_RST=self.pll_reset.storage, + o_LOCKED=pll_locked, p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, @@ -613,7 +617,9 @@ class _RTIOClockMultiplier(Module): p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, ), Instance("BUFG", i_I=clkfbout, o_O=clkfbin), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk) + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + MultiReg(pll_locked, self.pll_locked.status) ] @@ -710,7 +716,8 @@ class _MasterBase(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): @@ -888,7 +895,8 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): From 9f96b6bcda7d998ba9555d6cc912f55839d38bb9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 4 Oct 2018 10:41:01 +0800 Subject: [PATCH 92/92] kasli: use 125MHz DRTIO freq for testing --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 8fbaa0ec1..904464cbf 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -685,7 +685,7 @@ class _MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq=125e6, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -834,7 +834,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq=125e6, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon",