diff --git a/artiq/gateware/drtio/link_layer.py b/artiq/gateware/drtio/link_layer.py index 24d325f9c..52af15b4a 100644 --- a/artiq/gateware/drtio/link_layer.py +++ b/artiq/gateware/drtio/link_layer.py @@ -3,7 +3,7 @@ from operator import xor, or_ from migen import * from migen.genlib.fsm import * -from migen.genlib.cdc import MultiReg +from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.misc import WaitTimer from misoc.interconnect.csr import * @@ -223,10 +223,8 @@ class LinkLayerRX(Module): class LinkLayer(Module, AutoCSR): def __init__(self, encoder, decoders): self.link_status = CSRStatus() + self.link_reset = CSR() - # control signals, in rtio clock domain - self.reset = Signal() - self.ready = Signal() # pulsed to reset receiver, rx_ready must immediately go low self.rx_reset = Signal() # receiver locked including comma alignment @@ -252,37 +250,46 @@ class LinkLayer(Module, AutoCSR): # # # - ready_r = Signal() + ready = Signal() + reset_ps = PulseSynchronizer("sys", "rtio") + done_ps = PulseSynchronizer("rtio", "sys") + self.submodules += reset_ps, done_ps + self.comb += reset_ps.i.eq(self.link_reset.re) + self.sync += [ + If(done_ps.o, ready.eq(1)), + If(reset_ps.i, ready.eq(0)), + ] + self.comb += self.link_status.status.eq(ready) + ready_rx = Signal() - self.sync.rtio += ready_r.eq(self.ready) - ready_r.attr.add("no_retiming") - self.specials += MultiReg(ready_r, ready_rx, "rtio_rx") + ready.attr.add("no_retiming") + self.specials += MultiReg(ready, ready_rx, "rtio_rx") self.comb += [ self.rx_aux_frame.eq(rx.aux_frame & ready_rx), self.rx_rt_frame.eq(rx.rt_frame & ready_rx), ] - self.specials += MultiReg(ready_r, self.link_status.status) - wait_scrambler = WaitTimer(15) + wait_scrambler = ClockDomainsRenamer("rtio")(WaitTimer(15)) self.submodules += wait_scrambler - fsm = ClockDomainsRenamer("rtio")( - ResetInserter()(FSM(reset_state="RESET_RX"))) + fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="RESET_RX")) self.submodules += fsm - self.comb += fsm.reset.eq(self.reset) - fsm.act("RESET_RX", self.rx_reset.eq(1), NextState("WAIT_RX_READY") ) fsm.act("WAIT_RX_READY", - If(self.rx_ready, NextState("WAIT_SCRAMBLER_SYNC")) + If(self.rx_ready, NextState("WAIT_SCRAMBLER_SYNC")), + If(reset_ps.o, NextState("RESET_RX")) ) fsm.act("WAIT_SCRAMBLER_SYNC", wait_scrambler.wait.eq(1), - If(wait_scrambler.done, NextState("READY")), + If(wait_scrambler.done, + done_ps.i.eq(1), + NextState("READY") + ), ) fsm.act("READY", - self.ready.eq(1) + If(reset_ps.o, NextState("RESET_RX")) ) diff --git a/artiq/runtime.rs/src/drtio.rs b/artiq/runtime.rs/src/drtio.rs index 089dd55b4..618a9f7dd 100644 --- a/artiq/runtime.rs/src/drtio.rs +++ b/artiq/runtime.rs/src/drtio.rs @@ -7,6 +7,12 @@ fn drtio_link_is_up() -> bool { } } +fn drtio_reset_link() { + unsafe { + csr::drtio::link_reset_write(1) + } +} + fn drtio_sync_tsc() { unsafe { csr::drtio::set_time_write(1); @@ -33,7 +39,7 @@ pub fn link_thread(waiter: Waiter, _spawner: Spawner) { waiter.until(drtio_link_is_up).unwrap(); info!("link RX is up"); - waiter.sleep(300); + waiter.sleep(300).unwrap(); info!("wait for remote side done"); drtio_sync_tsc(); @@ -48,23 +54,24 @@ pub fn link_thread(waiter: Waiter, _spawner: Spawner) { } } -fn drtio_error_present() -> bool { +fn drtio_packet_error_present() -> bool { unsafe { - csr::drtio::err_present_read() != 0 + csr::drtio::packet_err_present_read() != 0 } } -fn drtio_get_error() -> u8 { +fn drtio_get_packet_error() -> u8 { unsafe { - let err = csr::drtio::err_code_read(); - csr::drtio::err_present_write(1); + let err = csr::drtio::packet_err_code_read(); + csr::drtio::packet_err_present_write(1); err } } pub fn error_thread(waiter: Waiter, _spawner: Spawner) { loop { - waiter.until(drtio_error_present).unwrap(); - error!("DRTIO error {}", drtio_get_error()); + waiter.until(drtio_packet_error_present).unwrap(); + error!("DRTIO packet error {}", drtio_get_packet_error()); + drtio_reset_link(); } }