drtio: more reliable link layer init

This commit is contained in:
Sebastien Bourdeauducq 2016-11-09 22:03:47 +08:00
parent c92ccd3b5b
commit 863934c4fa
4 changed files with 44 additions and 18 deletions

View File

@ -6,9 +6,10 @@ from artiq.gateware.drtio import link_layer, rt_packets, iot, rt_controller
class DRTIOSatellite(Module): 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( self.submodules.link_layer = link_layer.LinkLayer(
transceiver.encoder, transceiver.decoders) transceiver.encoder, transceiver.decoders, ll_rx_ready_confirm)
self.comb += [ self.comb += [
transceiver.rx_reset.eq(self.link_layer.rx_reset), transceiver.rx_reset.eq(self.link_layer.rx_reset),
self.link_layer.rx_ready.eq(transceiver.rx_ready) self.link_layer.rx_ready.eq(transceiver.rx_ready)
@ -45,9 +46,9 @@ class DRTIOSatellite(Module):
class DRTIOMaster(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( self.submodules.link_layer = link_layer.LinkLayer(
transceiver.encoder, transceiver.decoders) transceiver.encoder, transceiver.decoders, ll_rx_ready_confirm)
self.comb += [ self.comb += [
transceiver.rx_reset.eq(self.link_layer.rx_reset), transceiver.rx_reset.eq(self.link_layer.rx_reset),
self.link_layer.rx_ready.eq(transceiver.rx_ready) self.link_layer.rx_ready.eq(transceiver.rx_ready)

View File

@ -4,6 +4,7 @@ from operator import xor, or_
from migen import * from migen import *
from migen.genlib.fsm import * from migen.genlib.fsm import *
from migen.genlib.cdc import MultiReg, BusSynchronizer from migen.genlib.cdc import MultiReg, BusSynchronizer
from migen.genlib.misc import WaitTimer
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
@ -212,7 +213,7 @@ class LinkLayerRX(Module):
class LinkLayer(Module, AutoCSR): class LinkLayer(Module, AutoCSR):
def __init__(self, encoder, decoders): def __init__(self, encoder, decoders, rx_ready_confirm_cycles):
self.link_status = CSRStatus(3) self.link_status = CSRStatus(3)
# control signals, in rtio clock domain # control signals, in rtio clock domain
@ -272,6 +273,12 @@ class LinkLayer(Module, AutoCSR):
self.submodules += link_status self.submodules += link_status
self.comb += self.link_status.status.eq(link_status.o) 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", fsm.act("RESET_RX",
link_status.i.eq(0), link_status.i.eq(0),
tx.link_init.eq(1), tx.link_init.eq(1),
@ -281,24 +288,40 @@ class LinkLayer(Module, AutoCSR):
fsm.act("WAIT_LOCAL_RX_READY", fsm.act("WAIT_LOCAL_RX_READY",
link_status.i.eq(1), link_status.i.eq(1),
tx.link_init.eq(1), tx.link_init.eq(1),
If(self.rx_ready, If(self.rx_ready, NextState("CONFIRM_LOCAL_RX_READY"))
NextState("WAIT_REMOTE_RX_READY")
)
) )
fsm.act("WAIT_REMOTE_RX_READY", fsm.act("CONFIRM_LOCAL_RX_READY",
link_status.i.eq(2), link_status.i.eq(2),
tx.link_init.eq(1), 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), tx.signal_rx_ready.eq(1),
If(rx_remote_rx_ready, If(rx_remote_rx_ready, NextState("ENSURE_SIGNAL_RX_READY"))
NextState("WAIT_REMOTE_LINK_UP") )
) # 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", fsm.act("WAIT_REMOTE_LINK_UP",
link_status.i.eq(3), link_status.i.eq(4),
If(~rx_link_init, NextState("READY")) If(~rx_link_init, NextState("READY"))
) )
fsm.act("READY", fsm.act("READY",
link_status.i.eq(4), link_status.i.eq(5),
If(rx_link_init, NextState("RESET_RX")), If(rx_link_init, NextState("RESET_RX")), # TODO: remove this, link deinit should be detected at upper layer
self.ready.eq(1) self.ready.eq(1)
) )

View File

@ -3,7 +3,7 @@ use sched::{Waiter, Spawner};
fn drtio_link_is_up() -> bool { fn drtio_link_is_up() -> bool {
unsafe { unsafe {
csr::drtio::link_status_read() == 4 csr::drtio::link_status_read() == 5
} }
} }

View File

@ -41,7 +41,8 @@ class DUT(Module):
self.ttl1 = Signal() self.ttl1 = Signal()
self.transceivers = DummyTransceiverPair(nwords) 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() rx_synchronizer = DummyRXSynchronizer()
self.submodules.phy0 = ttl_simple.Output(self.ttl0) self.submodules.phy0 = ttl_simple.Output(self.ttl0)
@ -51,7 +52,8 @@ class DUT(Module):
rtio.Channel.from_phy(self.phy1, ofifo_depth=4) rtio.Channel.from_phy(self.phy1, ofifo_depth=4)
] ]
self.submodules.satellite = DRTIOSatellite( 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): class TestFullStack(unittest.TestCase):