forked from M-Labs/artiq-zynq
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:
parent
12ac59a757
commit
44246c293d
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue