forked from M-Labs/artiq
drtio: more reliable link layer init
This commit is contained in:
parent
c92ccd3b5b
commit
863934c4fa
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue