From 44246c293db3b7493c6b4f7335f37519b42dc2a4 Mon Sep 17 00:00:00 2001 From: morgan Date: Mon, 30 Sep 2024 15:04:14 +0800 Subject: [PATCH] cxp GW: add cxp phys & gtx csr cxp GW: cleanup doc cxp GW: move receiver path into downconn interface cxp GW: add rx memory --- src/gateware/cxp.py | 225 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 188 insertions(+), 37 deletions(-) diff --git a/src/gateware/cxp.py b/src/gateware/cxp.py index 583ba30..fdccef3 100644 --- a/src/gateware/cxp.py +++ b/src/gateware/cxp.py @@ -1,36 +1,154 @@ from migen import * from misoc.interconnect.csr import * -from cxp_downconn import CXP_DownConn_PHY -from cxp_upconn import CXP_UpConn_PHY +from cxp_downconn import CXP_DownConn_PHYS +from cxp_upconn import CXP_UpConn_PHYS from cxp_pipeline import * +class CXP_PHYS(Module, AutoCSR): + def __init__(self, refclk, upconn_pads, downconn_pads, sys_clk_freq, debug_sma, pmod_pads): + assert len(upconn_pads) == len(downconn_pads) + self.submodules.upconn = CXP_UpConn_PHYS(upconn_pads, sys_clk_freq, debug_sma, pmod_pads) + self.submodules.downconn = CXP_DownConn_PHYS(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads) + @FullMemoryWE() -class CXP(Module, AutoCSR): - def __init__(self, refclk, downconn_pads, upconn_pads, sys_clk_freq, debug_sma, pmod_pads): - self.submodules.upconn = UpConn_Interface(upconn_pads, sys_clk_freq, debug_sma, pmod_pads) +class CXP_Interface(Module, AutoCSR): + def __init__(self, upconn_phy, downconn_phy, debug_sma, pmod_pads): + # TODO: move all transceiver csr into a transceiver interface submodule + + self.submodules.upconn = UpConn_Interface(upconn_phy, debug_sma, pmod_pads) - self.submodules.downconn = DownConn_Interface(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads) - # TODO: support the option high speed upconn - - # TODO: add link layer + self.submodules.downconn = DownConn_Interface(downconn_phy, debug_sma, pmod_pads) def get_tx_port(self): return self.upconn.command.mem.get_port(write_capable=True) + def get_rx_port(self): + return self.downconn.packet_decoder.mem.get_port(write_capable=False) + def get_loopback_tx_port(self): return self.downconn.command.mem.get_port(write_capable=True) def get_mem_size(self): - return buffer_depth*downconn_dw + return buffer_depth*word_dw class DownConn_Interface(Module, AutoCSR): - def __init__(self, refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads): + def __init__(self, phy, debug_sma, pmod_pads): + self.rx_start_init = CSRStorage() + self.rx_restart = CSR() + self.rx_ready = CSRStatus() + # # # - self.submodules.phy = phy = CXP_DownConn_PHY(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads) - self.gtxs = phy.gtxs + gtx = phy.gtx + + # GTX Control + self.sync += [ + gtx.rx_restart.eq(self.rx_restart.re), + gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage), + self.rx_ready.status.eq(gtx.rx_ready), + ] + + + # DEBUG: tx control + self.tx_start_init = CSRStorage() + self.tx_restart = CSR() + self.txenable = CSRStorage() + self.sync += [ + gtx.txenable.eq(self.txenable.storage), + gtx.tx_restart.eq(self.tx_restart.re), + gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage), + ] + + # DEBUG: loopback control + self.loopback_mode = CSRStorage(3) + self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage) + + + # DEBUG: init status + self.txinit_phaligndone = CSRStatus() + self.rxinit_phaligndone = CSRStatus() + self.comb += [ + self.txinit_phaligndone.status.eq(gtx.tx_init.Xxphaligndone), + self.rxinit_phaligndone.status.eq(gtx.rx_init.Xxphaligndone), + ] + + # Connect all GTX connections' DRP + self.gtx_daddr = CSRStorage(9) + self.gtx_dread = CSR() + self.gtx_din_stb = CSR() + self.gtx_din = CSRStorage(16) + + self.gtx_dout = CSRStatus(16) + self.gtx_dready = CSR() + + self.comb += gtx.dclk.eq(ClockSignal("sys")) + self.sync += [ + gtx.den.eq(0), + gtx.dwen.eq(0), + If(self.gtx_dread.re, + gtx.den.eq(1), + gtx.daddr.eq(self.gtx_daddr.storage), + ).Elif(self.gtx_din_stb.re, + gtx.den.eq(1), + gtx.dwen.eq(1), + gtx.daddr.eq(self.gtx_daddr.storage), + gtx.din.eq(self.gtx_din.storage), + ), + If(gtx.dready, + self.gtx_dready.w.eq(1), + self.gtx_dout.status.eq(gtx.dout), + ), + If(self.gtx_dready.re, + self.gtx_dready.w.eq(0), + ), + ] + + + # DEBUG: txusrclk PLL DRP + + self.txpll_reset = CSRStorage() + self.pll_daddr = CSRStorage(7) + self.pll_dclk = CSRStorage() + self.pll_den = CSRStorage() + self.pll_din = CSRStorage(16) + self.pll_dwen = CSRStorage() + + self.txpll_locked = CSRStatus() + self.pll_dout = CSRStatus(16) + self.pll_dready = CSRStatus() + + self.comb += [ + gtx.txpll_reset.eq(self.txpll_reset.storage), + gtx.pll_daddr.eq(self.pll_daddr.storage), + gtx.pll_dclk.eq(self.pll_dclk.storage), + gtx.pll_den.eq(self.pll_den.storage), + gtx.pll_din.eq(self.pll_din.storage), + gtx.pll_dwen.eq(self.pll_dwen.storage), + + self.txinit_phaligndone.status.eq(gtx.tx_init.Xxphaligndone), + self.rxinit_phaligndone.status.eq(gtx.rx_init.Xxphaligndone), + self.txpll_locked.status.eq(gtx.txpll_locked), + self.pll_dout.status.eq(gtx.pll_dout), + self.pll_dready.status.eq(gtx.pll_dready), + ] + + + # DEBUG: tx loopback fifo control + self.tx_stb = CSRStorage() + self.sync += phy.tx_stb_sys.eq(self.tx_stb.storage) + + + # DEBUG: Transmission Pipeline + # + # test pak ----+ + # from gw | 32 32 + # |---/---> mux -----> packet -----> trigger ack ---/---> PHY + # | wrapper inserter + # data pak ----+ + # from fw + # DEBUG: TX pipeline self.submodules.command = command = TX_Command_Packet() @@ -49,45 +167,80 @@ class DownConn_Interface(Module, AutoCSR): mux.sel.eq(self.mux_sel.storage), ] - tx_pipeline = [mux , pak_wrp, trig_ack, phy.sinks[0]] + tx_pipeline = [mux , pak_wrp, trig_ack, phy] for s, d in zip(tx_pipeline, tx_pipeline[1:]): self.comb += s.source.connect(d.sink) - # NOTE: RX pipeline + + + + # Receiver Pipeline WIP + # + # 32 32 + # PHY ---/---> CDC FIFO ---/---> trigger ack ------> packet ------> debug buffer + # checker decoder + # self.submodules.debug_out = debug_out = RX_Debug_Buffer() - self.submodules.recv_path = recv_path = Receiver_Path() + self.submodules.trig_ack_checker = trig_ack_checker = CXP_Trig_Ack_Checker() + self.submodules.packet_decoder = packet_decoder = CXP_Data_Packet_Decode() - rx_pipeline = [phy.sources[0], recv_path, debug_out] - for s, d in zip(rx_pipeline, rx_pipeline[1:]): - self.comb += s.source.connect(d.sink) + self.trig_ack = Signal() + self.trig_clr = Signal() + # Error are latched + self.sync += [ + If(trig_ack_checker.ack, + self.trig_ack.eq(1), + ).Elif(self.trig_clr, + self.trig_ack.eq(0), + ), + ] self.packet_type = CSRStatus(8) - self.decoder_error = CSRStatus() - self.test_error = CSRStatus() - self.comb += [ - self.packet_type.status.eq(recv_path.packet_type), - self.decoder_error.status.eq(recv_path.decoder_err), - self.test_error.status.eq(recv_path.test_err), + self.decoder_error = CSR() + self.test_error = CSR() + # self.read_pointer = CSR() + + self.comb += self.packet_type.status.eq(packet_decoder.packet_type_rx), + self.sync += [ + If(packet_decoder.decode_err_rx, + self.decoder_error.w.eq(1), + ).Elif(self.decoder_error.re, + self.decoder_error.w.eq(0), + ), + If(packet_decoder.test_err_rx, + self.test_error.w.eq(1), + ).Elif(self.test_error.re, + self.test_error.w.eq(0), + ), + # FIXME: this cannot be routed + # self.read_pointer.w.eq(packet_decoder.read_ptr_rx), + # If(self.read_pointer.re, + # packet_decoder.read_ptr_rx.eq(packet_decoder.read_ptr_rx + 1), + # ), + ] + + # TODO: move the rx pipeline to cxp_gtx_rx clockdomain + rx_pipeline = [phy, trig_ack_checker, packet_decoder, debug_out] + for s, d in zip(rx_pipeline, rx_pipeline[1:]): + self.comb += s.source.connect(d.sink) # DEBUG: CSR - self.trig_ack = CSRStatus() - self.trig_clr = CSR() - self.comb += [ - self.trig_ack.status.eq(recv_path.trig_ack), - recv_path.trig_clr.eq(self.trig_clr.re), + self.trigger_ack = CSR() + self.sync += [ + self.trig_clr.eq(self.trigger_ack.re), + self.trigger_ack.w.eq(self.trig_ack), ] pak_start = Signal() self.sync += [ - pak_start.eq(recv_path.packet_decoder.sink.data == 0xFBFBFBFB), - + pak_start.eq(packet_decoder.sink.data == 0xFBFBFBFB), ] self.specials += [ # # pmod 0-7 pin - Instance("OBUF", i_I=recv_path.packet_decoder.test_err, o_O=pmod_pads[0]), + Instance("OBUF", i_I=packet_decoder.test_err_rx, o_O=pmod_pads[0]), Instance("OBUF", i_I=pak_start, o_O=pmod_pads[1]), # Instance("OBUF", i_I=fifo_in.source.ack, o_O=pmod_pads[2]), # Instance("OBUF", i_I=gtx.comma_checker.aligner_en, o_O=pmod_pads[3]), @@ -99,7 +252,7 @@ class DownConn_Interface(Module, AutoCSR): class UpConn_Interface(Module, AutoCSR): - def __init__(self, upconn_pads, sys_clk_freq, debug_sma, pmod_pads): + def __init__(self, phy, debug_sma, pmod_pads): self.clk_reset = CSRStorage(reset=1) self.bitrate2x_enable = CSRStorage() self.tx_enable = CSRStorage() @@ -111,8 +264,6 @@ class UpConn_Interface(Module, AutoCSR): # # # - self.submodules.phy = phy = CXP_UpConn_PHY(upconn_pads, sys_clk_freq, debug_sma, pmod_pads) - self.sync += [ phy.bitrate2x_enable.eq(self.bitrate2x_enable.storage), phy.tx_enable.eq(self.tx_enable.storage), @@ -133,7 +284,7 @@ class UpConn_Interface(Module, AutoCSR): # trigger > trigger ack > idle > test/data packet # To maintain the trigger performance, idle word should not be inserted into trigger or trigger ack. # - # In low speed serial, the higher priority packet can be inserted in two types of boundary + # In low speed CoaXpress, the higher priority packet can be inserted in two types of boundary # Insertion @ char boundary: Trigger packets # Insertion @ word boundary: Trigger ack & IDLE packets # The 32 bit part of the pipeline handles the word boundary insertion while the 8 bit part handles the char boundary insertion