1
0
Fork 0

cxp: add upconn interface, downconn PHY & crc

testing: add CSR control for tx trigger & trigger ack
upconn: connect trigger, trigger ack & command_packet to UpConnPHY
downconn: add GTX PHY
This commit is contained in:
morgan 2024-06-14 17:17:56 +08:00
parent 2ce9aeb45e
commit 22aa9555c5
1 changed files with 230 additions and 0 deletions

230
src/gateware/cxp.py Normal file
View File

@ -0,0 +1,230 @@
from migen import *
from misoc.interconnect.csr import *
from cxp_downconn import CXP_DownConn_PHY
from cxp_upconn import CXP_UpConn_PHY
from cxp_pipeline import *
buffer_depth = 128
@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)
self.submodules.downconn = DownConn_Interface(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads)
# TODO: support the option high speed upconn
self.submodules.transmitter = Transmitter()
# TODO: add link layer
def get_tx_port(self):
return self.transmitter.mem.get_port(write_capable=True)
def get_mem_size(self):
return buffer_depth*downconn_dw
@FullMemoryWE()
class Transmitter(Module, AutoCSR):
def __init__(self):
self.cxp_tx_word_len = CSRStorage(bits_for(buffer_depth))
self.cxp_tx = CSR()
# # #
self.specials.mem = mem = Memory(downconn_dw, buffer_depth)
self.specials.mem_port = mem_port = mem.get_port()
self.source = stream.Endpoint(downconn_layout)
tx_done = Signal()
addr_next = Signal(bits_for(buffer_depth))
addr = Signal.like(addr_next)
addr_rst = Signal()
addr_inc = Signal()
# increment addr in the same cycle the moment addr_inc is rise
# since memory takes one cycle to shift to the correct addr
self.sync += [
addr.eq(addr_next),
If(self.cxp_tx.re, self.cxp_tx.w.eq(1)),
If(tx_done, self.cxp_tx.w.eq(0)),
]
self.comb += [
addr_next.eq(addr),
If(addr_rst,
addr_next.eq(addr_next.reset),
).Elif(addr_inc,
addr_next.eq(addr + 1),
),
mem_port.adr.eq(addr_next),
self.source.data.eq(mem_port.dat_r)
]
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
addr_rst.eq(1),
If(self.cxp_tx.re, NextState("TRANSMIT"))
)
fsm.act("TRANSMIT",
self.source.stb.eq(1),
If(self.source.ack,
addr_inc.eq(1),
),
If(addr_next == self.cxp_tx_word_len.storage,
tx_done.eq(1),
NextState("IDLE")
)
)
self.submodules.debug_out = debug_out = RX_Debug_Buffer()
self.comb += self.source.connect(debug_out.sink)
class DownConn_Interface(Module, AutoCSR):
def __init__(self, refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads):
# # #
self.submodules.phy = phy = CXP_DownConn_PHY(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads)
self.gtxs = phy.gtxs
# DEBUG: TX pipeline
self.submodules.debug_src = debug_src = TX_Command_Packet()
self.submodules.trig_ack = trig_ack = Trigger_ACK()
self.submodules.testseq = testseq = TX_Test_Packet()
self.submodules.mux = mux = stream.Multiplexer(upconn_layout, 3)
self.submodules.conv = conv = stream.StrideConverter(upconn_layout, downconn_layout)
self.ack = CSR()
self.mux_sel = CSRStorage(4)
self.sync += trig_ack.ack.eq(self.ack.re),
self.comb += [
debug_src.source.connect(mux.sink0),
trig_ack.source.connect(mux.sink1),
testseq.source.connect(mux.sink2),
mux.sel.eq(self.mux_sel.storage)
]
tx_pipeline = [mux , conv, phy.sinks[0]]
for s, d in zip(tx_pipeline, tx_pipeline[1:]):
self.comb += s.source.connect(d.sink)
# NOTE: RX pipeline
self.submodules.debug_out = debug_out = RX_Debug_Buffer()
self.submodules.recv_path = recv_path = Receiver_Path()
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.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),
]
# 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),
]
pak_start = Signal()
self.sync += [
pak_start.eq(recv_path.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=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]),
# Instance("OBUF", i_I=gtx.comma_checker.check_reset, o_O=pmod_pads[4]),
# Instance("OBUF", i_I=gtx.comma_checker.has_comma, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=gtx.comma_checker.has_error, o_O=pmod_pads[6]),
# Instance("OBUF", i_I=gtx.comma_checker.ready_sys, o_O=pmod_pads[7]),
]
class UpConn_Interface(Module, AutoCSR):
def __init__(self, upconn_pads, sys_clk_freq, debug_sma, pmod_pads):
self.clk_reset = CSRStorage(reset=1)
self.bitrate2x_enable = CSRStorage()
self.tx_enable = CSRStorage()
self.tx_busy = CSRStatus()
self.tx_testmode_en = CSRStorage()
# # #
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),
phy.clk_reset.eq(self.clk_reset.re),
self.tx_busy.status.eq(phy.tx_busy),
]
# TODO: rewrite the transmite path into pipeline
#
# test pak ----+
# from gw | 32 32 8
# |---/---> mux -----> trig ack -----> idle word ---/--> conv ---/---> trig -----> PHY
# | inserter inserter inserter
# data pak ----+
# from fw
# Packet FIFOs with transmission priority
# 0: Trigger packet
self.submodules.trig = trig = TX_Trigger()
self.comb += trig.source.connect(phy.sinks[0])
# DEBUG: INPUT
self.trig_stb = CSR()
self.trig_delay = CSRStorage(8)
self.linktrigger = CSRStorage(2)
self.sync += [
trig.trig_stb.eq(self.trig_stb.re),
trig.delay.eq(self.trig_delay.storage),
trig.linktrig_mode.eq(self.linktrigger.storage),
]
# 1: IO acknowledgment for trigger packet
self.submodules.trig_ack = trig_ack = Trigger_ACK()
self.comb += trig_ack.source.connect(phy.sinks[1])
# DEBUG: INPUT
self.ack = CSR()
self.sync += trig_ack.ack.eq(self.ack.re),
# 2: All other packets
# Control is not timing dependent, all the link layer is done in firmware
self.submodules.command = command = TX_Command_Packet()
self.submodules.testseq = testseq = TX_Test_Packet()
self.submodules.mux = mux = stream.Multiplexer(upconn_layout, 2)
self.comb += [
command.source.connect(mux.sink0),
testseq.source.connect(mux.sink1),
mux.sel.eq(self.tx_testmode_en.storage),
mux.source.connect(phy.sinks[2])
]