diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f481b04ad..bc03eac5d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,11 +54,10 @@ pub mod drtio { } } - fn reset_phy(linkno: u8) { + fn link_reset(linkno: u8) { let linkno = linkno as usize; unsafe { - (csr::DRTIO[linkno].reset_phy_write)(1); - while (csr::DRTIO[linkno].o_wait_read)() == 1 {} + (csr::DRTIO[linkno].reset_write)(1); } } @@ -70,12 +69,9 @@ pub mod drtio { } } - fn init_link(linkno: u8) { + fn init_buffer_space(linkno: u8) { let linkidx = linkno as usize; unsafe { - (csr::DRTIO[linkidx].reset_write)(1); - while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} - (csr::DRTIO[linkidx].o_get_buffer_space_write)(1); while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} info!("[LINK#{}] buffer space is {}", @@ -83,12 +79,6 @@ pub mod drtio { } } - pub fn init() { - for linkno in 0..csr::DRTIO.len() { - init_link(linkno as u8); - } - } - fn ping_remote(linkno: u8, io: &Io) -> u32 { let mut count = 0; loop { @@ -114,7 +104,7 @@ pub mod drtio { (csr::DRTIO[linkidx].protocol_error_write)(errors); } if errors != 0 { - error!("[LINK#{}] found error(s)", linkno); + error!("[LINK#{}] error(s) found (0x{:02x}):", linkno, errors); if errors & 1 != 0 { error!("[LINK#{}] received packet of an unknown type", linkno); } @@ -148,34 +138,40 @@ pub mod drtio { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if !link_up[linkno as usize] { + if link_up[linkno as usize] { + /* link was previously up */ + if link_rx_up(linkno) { + process_local_errors(linkno); + process_aux_errors(linkno); + } else { + info!("[LINK#{}] link is down", linkno); + link_up[linkno as usize] = false; + } + } else { + /* link was previously down */ if link_rx_up(linkno) { info!("[LINK#{}] link RX became up, pinging", linkno); + link_reset(linkno); let ping_count = ping_remote(linkno, &io); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); - init_link(linkno); // clear all FIFOs first - reset_phy(linkno); + init_buffer_space(linkno); sync_tsc(linkno); info!("[LINK#{}] link initialization completed", linkno); link_up[linkno as usize] = true; } else { info!("[LINK#{}] ping failed", linkno); } - } else { - if link_rx_up(linkno) { - process_local_errors(linkno); - process_aux_errors(linkno); - } else { - info!("[LINK#{}] link is down", linkno); - link_up[linkno as usize] = false; - } } } } io.sleep(200).unwrap(); } } + + pub fn init() { + // TODO: send reset commands (over aux) to every link that is up + } } #[cfg(not(has_drtio))] diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index a2c155085..77c63f0ef 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -193,6 +193,14 @@ fn drtio_link_is_up() -> bool { } } +fn drtio_reset(reset: bool) { + let reset = if reset { 1 } else { 0 }; + unsafe { + (csr::DRTIO[0].reset_write)(reset); + (csr::DRTIO[0].reset_phy_write)(reset); + } +} + fn startup() { board::clock::init(); info!("ARTIQ satellite manager starting..."); @@ -216,10 +224,12 @@ fn startup() { } info!("link is up, switching to recovered clock"); si5324::select_ext_input(true).expect("failed to switch clocks"); + drtio_reset(false); while drtio_link_is_up() { process_errors(); process_aux_packets(); } + drtio_reset(true); info!("link is down, switching to local crystal clock"); si5324::select_ext_input(false).expect("failed to switch clocks"); } diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 06ced73d6..507b93a7e 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -2,6 +2,7 @@ from types import SimpleNamespace from migen import * from migen.genlib.cdc import ElasticBuffer +from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * from artiq.gateware.rtio.sed.core import * @@ -54,14 +55,36 @@ class GenericRXSynchronizer(Module): class DRTIOSatellite(Module): def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, lane_count=8, fifo_depth=128): - if rx_synchronizer is None: - rx_synchronizer = GenericRXSynchronizer() - self.submodules += rx_synchronizer + self.reset = CSRStorage(reset=1) + self.reset_phy = CSRStorage(reset=1) + + self.clock_domains.cd_rio = ClockDomain() + self.clock_domains.cd_rio_phy = ClockDomain() + self.comb += [ + self.cd_rio.clk.eq(ClockSignal("rtio")), + self.cd_rio_phy.clk.eq(ClockSignal("rtio")) + ] + reset = Signal() + reset_phy = Signal() + reset.attr.add("no_retiming") + reset_phy.attr.add("no_retiming") + self.sync += [ + reset.eq(self.reset.storage), + reset_phy.eq(self.reset_phy.storage) + ] + self.specials += [ + AsyncResetSynchronizer(self.cd_rio, reset), + AsyncResetSynchronizer(self.cd_rio_phy, reset_phy) + ] self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) + if rx_synchronizer is None: + rx_synchronizer = GenericRXSynchronizer() + self.submodules += rx_synchronizer + link_layer_sync = SimpleNamespace( tx_aux_frame=self.link_layer.tx_aux_frame, tx_aux_data=self.link_layer.tx_aux_data, @@ -80,6 +103,7 @@ 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)) + self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) coarse_ts = Signal(64 - fine_ts_width) self.sync.rtio += \ @@ -106,20 +130,12 @@ class DRTIOSatellite(Module): self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( self.rt_packet, self.outputs) - self.clock_domains.cd_rio = ClockDomain() - self.clock_domains.cd_rio_phy = ClockDomain() - self.comb += [ - self.cd_rio.clk.eq(ClockSignal("rtio")), - self.cd_rio.rst.eq(self.rt_packet.reset), - self.cd_rio_phy.clk.eq(ClockSignal("rtio")), - self.cd_rio_phy.rst.eq(self.rt_packet.reset_phy), - ] - 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() + + return ([self.reset, self.reset_phy] + + self.link_layer.get_csrs() + self.link_stats.get_csrs() + self.rt_errors.get_csrs() + self.aux_controller.get_csrs()) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 12683db01..cb2fcdab6 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -13,14 +13,14 @@ from artiq.gateware.rtio import cri class _CSRs(AutoCSR): def __init__(self): + self.reset = CSR() + self.protocol_error = CSR(3) self.tsc_correction = CSRStorage(64) self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=200) - self.reset = CSR() - self.reset_phy = CSR() self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) @@ -51,6 +51,19 @@ class RTController(Module): self.csrs = _CSRs() self.cri = cri.Interface() + # reset + local_reset = Signal(reset=1) + self.sync += local_reset.eq(self.csrs.reset.re) + 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() @@ -85,31 +98,6 @@ class RTController(Module): If(self.csrs.set_time.re, rt_packet.set_time_stb.eq(1)) ] - # reset - self.sync += [ - If(rt_packet.reset_ack, rt_packet.reset_stb.eq(0)), - If(self.csrs.reset.re, - rt_packet.reset_stb.eq(1), - rt_packet.reset_phy.eq(0) - ), - If(self.csrs.reset_phy.re, - rt_packet.reset_stb.eq(1), - rt_packet.reset_phy.eq(1) - ), - ] - - local_reset = Signal(reset=1) - self.sync += local_reset.eq(self.csrs.reset.re) - 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) - # common packet fields chan_sel = self.cri.chan_sel[:16] rt_packet_buffer_request = Signal() diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 94dea3944..2e07dcbc7 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -111,11 +111,6 @@ class RTPacketMaster(Module): # a set_time request pending self.tsc_value = Signal(64) - # reset interface - self.reset_stb = Signal() - self.reset_ack = Signal() - self.reset_phy = Signal() - # rx errors self.err_unknown_packet_type = Signal() self.err_packet_truncated = Signal() @@ -221,13 +216,6 @@ class RTPacketMaster(Module): self.set_time_stb, self.set_time_ack, None, set_time_stb, set_time_ack, None) - reset_stb = Signal() - reset_ack = Signal() - reset_phy = Signal() - self.submodules += _CrossDomainRequest("rtio", - self.reset_stb, self.reset_ack, self.reset_phy, - reset_stb, reset_ack, reset_phy) - echo_stb = Signal() echo_ack = Signal() self.submodules += _CrossDomainRequest("rtio", @@ -287,8 +275,6 @@ class RTPacketMaster(Module): ).Elif(set_time_stb, tsc_value_load.eq(1), NextState("SET_TIME") - ).Elif(reset_stb, - NextState("RESET") ) ) ) @@ -344,13 +330,6 @@ class RTPacketMaster(Module): NextState("IDLE") ) ) - tx_fsm.act("RESET", - tx_dp.send("reset", phy=reset_phy), - If(tx_dp.packet_last, - reset_ack.eq(1), - NextState("IDLE") - ) - ) # RX FSM rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 47b9a1d55..02a5a98b1 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -9,15 +9,14 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketSatellite(Module): def __init__(self, link_layer): + self.reset = Signal() + self.unknown_packet_type = Signal() self.packet_truncated = Signal() self.tsc_load = Signal() self.tsc_load_value = Signal(64) - self.reset = Signal(reset=1) - self.reset_phy = Signal(reset=1) - self.cri = cri.Interface() # # # @@ -97,13 +96,6 @@ class RTPacketSatellite(Module): Cat(rx_dp.packet_as["write"].short_data, write_data_buffer)), ] - reset = Signal() - reset_phy = Signal() - self.sync += [ - self.reset.eq(reset), - self.reset_phy.eq(reset_phy) - ] - rx_fsm = FSM(reset_state="INPUT") self.submodules += rx_fsm @@ -120,7 +112,6 @@ class RTPacketSatellite(Module): # mechanism rx_plm.types["echo_request"]: echo_req.eq(1), rx_plm.types["set_time"]: NextState("SET_TIME"), - rx_plm.types["reset"]: NextState("RESET"), rx_plm.types["write"]: NextState("WRITE"), rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"), rx_plm.types["read_request"]: NextState("READ_REQUEST"), @@ -138,14 +129,6 @@ class RTPacketSatellite(Module): self.tsc_load.eq(1), NextState("INPUT") ) - rx_fsm.act("RESET", - If(rx_dp.packet_as["reset"].phy, - reset_phy.eq(1) - ).Else( - reset.eq(1) - ), - NextState("INPUT") - ) rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 8ba5668fc..00a46299f 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -47,7 +47,6 @@ def get_m2s_layouts(alignment): plm.add_type("echo_request") plm.add_type("set_time", ("timestamp", 64)) - plm.add_type("reset", ("phy", 1)) plm.add_type("write", ("timestamp", 64), ("channel", 16),