1
0
Fork 0

cxp GW: add cxp phys & gtx csr

cxp GW: cleanup doc

cxp GW: move receiver path into downconn interface

cxp GW: add rx memory
This commit is contained in:
morgan 2024-09-30 15:04:14 +08:00
parent 12ac59a757
commit 44246c293d
1 changed files with 188 additions and 37 deletions

View File

@ -1,36 +1,154 @@
from migen import * from migen import *
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
from cxp_downconn import CXP_DownConn_PHY from cxp_downconn import CXP_DownConn_PHYS
from cxp_upconn import CXP_UpConn_PHY from cxp_upconn import CXP_UpConn_PHYS
from cxp_pipeline import * 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() @FullMemoryWE()
class CXP(Module, AutoCSR): class CXP_Interface(Module, AutoCSR):
def __init__(self, refclk, downconn_pads, upconn_pads, sys_clk_freq, debug_sma, pmod_pads): def __init__(self, upconn_phy, downconn_phy, debug_sma, pmod_pads):
self.submodules.upconn = UpConn_Interface(upconn_pads, sys_clk_freq, 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) self.submodules.downconn = DownConn_Interface(downconn_phy, debug_sma, pmod_pads)
# TODO: support the option high speed upconn
# TODO: add link layer
def get_tx_port(self): def get_tx_port(self):
return self.upconn.command.mem.get_port(write_capable=True) 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): def get_loopback_tx_port(self):
return self.downconn.command.mem.get_port(write_capable=True) return self.downconn.command.mem.get_port(write_capable=True)
def get_mem_size(self): def get_mem_size(self):
return buffer_depth*downconn_dw return buffer_depth*word_dw
class DownConn_Interface(Module, AutoCSR): 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) gtx = phy.gtx
self.gtxs = phy.gtxs
# 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 # DEBUG: TX pipeline
self.submodules.command = command = TX_Command_Packet() self.submodules.command = command = TX_Command_Packet()
@ -49,45 +167,80 @@ class DownConn_Interface(Module, AutoCSR):
mux.sel.eq(self.mux_sel.storage), 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:]): for s, d in zip(tx_pipeline, tx_pipeline[1:]):
self.comb += s.source.connect(d.sink) 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.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] self.trig_ack = Signal()
for s, d in zip(rx_pipeline, rx_pipeline[1:]): self.trig_clr = Signal()
self.comb += s.source.connect(d.sink)
# 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.packet_type = CSRStatus(8)
self.decoder_error = CSRStatus() self.decoder_error = CSR()
self.test_error = CSRStatus() self.test_error = CSR()
self.comb += [ # self.read_pointer = CSR()
self.packet_type.status.eq(recv_path.packet_type),
self.decoder_error.status.eq(recv_path.decoder_err), self.comb += self.packet_type.status.eq(packet_decoder.packet_type_rx),
self.test_error.status.eq(recv_path.test_err), 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 # DEBUG: CSR
self.trig_ack = CSRStatus() self.trigger_ack = CSR()
self.trig_clr = CSR() self.sync += [
self.comb += [ self.trig_clr.eq(self.trigger_ack.re),
self.trig_ack.status.eq(recv_path.trig_ack), self.trigger_ack.w.eq(self.trig_ack),
recv_path.trig_clr.eq(self.trig_clr.re),
] ]
pak_start = Signal() pak_start = Signal()
self.sync += [ self.sync += [
pak_start.eq(recv_path.packet_decoder.sink.data == 0xFBFBFBFB), pak_start.eq(packet_decoder.sink.data == 0xFBFBFBFB),
] ]
self.specials += [ self.specials += [
# # pmod 0-7 pin # # 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=pak_start, o_O=pmod_pads[1]),
# Instance("OBUF", i_I=fifo_in.source.ack, o_O=pmod_pads[2]), # 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]), # 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): 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.clk_reset = CSRStorage(reset=1)
self.bitrate2x_enable = CSRStorage() self.bitrate2x_enable = CSRStorage()
self.tx_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 += [ self.sync += [
phy.bitrate2x_enable.eq(self.bitrate2x_enable.storage), phy.bitrate2x_enable.eq(self.bitrate2x_enable.storage),
phy.tx_enable.eq(self.tx_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 # trigger > trigger ack > idle > test/data packet
# To maintain the trigger performance, idle word should not be inserted into trigger or trigger ack. # 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 @ char boundary: Trigger packets
# Insertion @ word boundary: Trigger ack & IDLE 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 # The 32 bit part of the pipeline handles the word boundary insertion while the 8 bit part handles the char boundary insertion