From 863934c4fab346d8b1a805d9eafc7550db4731b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 Nov 2016 22:03:47 +0800 Subject: [PATCH] drtio: more reliable link layer init --- artiq/gateware/drtio/core.py | 9 ++-- artiq/gateware/drtio/link_layer.py | 45 +++++++++++++++----- artiq/runtime.rs/src/drtio.rs | 2 +- artiq/test/gateware/drtio/test_full_stack.py | 6 ++- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index ca852726d..71334a13f 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -6,9 +6,10 @@ from artiq.gateware.drtio import link_layer, rt_packets, iot, rt_controller class DRTIOSatellite(Module): - def __init__(self, transceiver, rx_synchronizer, channels, fine_ts_width=3, full_ts_width=63): + def __init__(self, transceiver, rx_synchronizer, channels, fine_ts_width=3, full_ts_width=63, + ll_rx_ready_confirm=1000): self.submodules.link_layer = link_layer.LinkLayer( - transceiver.encoder, transceiver.decoders) + transceiver.encoder, transceiver.decoders, ll_rx_ready_confirm) self.comb += [ transceiver.rx_reset.eq(self.link_layer.rx_reset), self.link_layer.rx_ready.eq(transceiver.rx_ready) @@ -45,9 +46,9 @@ class DRTIOSatellite(Module): class DRTIOMaster(Module): - def __init__(self, transceiver, channel_count=1024, fine_ts_width=3): + def __init__(self, transceiver, channel_count=1024, fine_ts_width=3, ll_rx_ready_confirm=1000): self.submodules.link_layer = link_layer.LinkLayer( - transceiver.encoder, transceiver.decoders) + transceiver.encoder, transceiver.decoders, ll_rx_ready_confirm) self.comb += [ transceiver.rx_reset.eq(self.link_layer.rx_reset), self.link_layer.rx_ready.eq(transceiver.rx_ready) diff --git a/artiq/gateware/drtio/link_layer.py b/artiq/gateware/drtio/link_layer.py index 0a1cca493..59f286732 100644 --- a/artiq/gateware/drtio/link_layer.py +++ b/artiq/gateware/drtio/link_layer.py @@ -4,6 +4,7 @@ from operator import xor, or_ from migen import * from migen.genlib.fsm import * from migen.genlib.cdc import MultiReg, BusSynchronizer +from migen.genlib.misc import WaitTimer from misoc.interconnect.csr import * @@ -212,7 +213,7 @@ class LinkLayerRX(Module): class LinkLayer(Module, AutoCSR): - def __init__(self, encoder, decoders): + def __init__(self, encoder, decoders, rx_ready_confirm_cycles): self.link_status = CSRStatus(3) # control signals, in rtio clock domain @@ -272,6 +273,12 @@ class LinkLayer(Module, AutoCSR): self.submodules += link_status self.comb += self.link_status.status.eq(link_status.o) + wait_confirm = ClockDomainsRenamer("rtio")( + WaitTimer(rx_ready_confirm_cycles)) + self.submodules += wait_confirm + signal_rx_ready_margin = ClockDomainsRenamer("rtio")(WaitTimer(15)) + self.submodules += signal_rx_ready_margin + fsm.act("RESET_RX", link_status.i.eq(0), tx.link_init.eq(1), @@ -281,24 +288,40 @@ class LinkLayer(Module, AutoCSR): fsm.act("WAIT_LOCAL_RX_READY", link_status.i.eq(1), tx.link_init.eq(1), - If(self.rx_ready, - NextState("WAIT_REMOTE_RX_READY") - ) + If(self.rx_ready, NextState("CONFIRM_LOCAL_RX_READY")) ) - fsm.act("WAIT_REMOTE_RX_READY", + fsm.act("CONFIRM_LOCAL_RX_READY", link_status.i.eq(2), tx.link_init.eq(1), + wait_confirm.wait.eq(1), + If(wait_confirm.done, NextState("WAIT_REMOTE_RX_READY")), + If(~rx_link_init, NextState("RESET_RX")) + ) + fsm.act("WAIT_REMOTE_RX_READY", + link_status.i.eq(3), + tx.link_init.eq(1), tx.signal_rx_ready.eq(1), - If(rx_remote_rx_ready, - NextState("WAIT_REMOTE_LINK_UP") - ) + If(rx_remote_rx_ready, NextState("ENSURE_SIGNAL_RX_READY")) + ) + # If the transceiver transmits one character per RTIO cycle, + # we may be unlucky and signal_rx_ready will transmit a comma + # on the first cycle instead of a "RX ready" character. + # Further, we need to ensure the rx.remote_rx_ready + # gets through MultiReg to rx_remote_rx_ready at the receiver. + # So transmit the "RX ready" pattern for several cycles. + fsm.act("ENSURE_SIGNAL_RX_READY", + link_status.i.eq(3), + tx.link_init.eq(1), + tx.signal_rx_ready.eq(1), + signal_rx_ready_margin.wait.eq(1), + If(signal_rx_ready_margin.done, NextState("WAIT_REMOTE_LINK_UP")) ) fsm.act("WAIT_REMOTE_LINK_UP", - link_status.i.eq(3), + link_status.i.eq(4), If(~rx_link_init, NextState("READY")) ) fsm.act("READY", - link_status.i.eq(4), - If(rx_link_init, NextState("RESET_RX")), + link_status.i.eq(5), + If(rx_link_init, NextState("RESET_RX")), # TODO: remove this, link deinit should be detected at upper layer self.ready.eq(1) ) diff --git a/artiq/runtime.rs/src/drtio.rs b/artiq/runtime.rs/src/drtio.rs index 8ee5dfc23..214295697 100644 --- a/artiq/runtime.rs/src/drtio.rs +++ b/artiq/runtime.rs/src/drtio.rs @@ -3,7 +3,7 @@ use sched::{Waiter, Spawner}; fn drtio_link_is_up() -> bool { unsafe { - csr::drtio::link_status_read() == 4 + csr::drtio::link_status_read() == 5 } } diff --git a/artiq/test/gateware/drtio/test_full_stack.py b/artiq/test/gateware/drtio/test_full_stack.py index ae0ce7290..eea0c2256 100644 --- a/artiq/test/gateware/drtio/test_full_stack.py +++ b/artiq/test/gateware/drtio/test_full_stack.py @@ -41,7 +41,8 @@ class DUT(Module): self.ttl1 = Signal() self.transceivers = DummyTransceiverPair(nwords) - self.submodules.master = DRTIOMaster(self.transceivers.alice) + self.submodules.master = DRTIOMaster(self.transceivers.alice, + ll_rx_ready_confirm=15) rx_synchronizer = DummyRXSynchronizer() self.submodules.phy0 = ttl_simple.Output(self.ttl0) @@ -51,7 +52,8 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1, ofifo_depth=4) ] self.submodules.satellite = DRTIOSatellite( - self.transceivers.bob, rx_synchronizer, rtio_channels) + self.transceivers.bob, rx_synchronizer, rtio_channels, + ll_rx_ready_confirm=15) class TestFullStack(unittest.TestCase):