From 82af01350f76c670f6c9de8d6be25d2dd6720128 Mon Sep 17 00:00:00 2001 From: morgan Date: Fri, 14 Jun 2024 17:17:56 +0800 Subject: [PATCH] cxp: add upconn, downconn & crc cxp: add crc32 for cxp cxp: add upconn & downconn --- src/gateware/cxp.py | 185 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/gateware/cxp.py diff --git a/src/gateware/cxp.py b/src/gateware/cxp.py new file mode 100644 index 0000000..8c7baaf --- /dev/null +++ b/src/gateware/cxp.py @@ -0,0 +1,185 @@ +from migen import * +from misoc.interconnect.csr import * +from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine + +from artiq.gateware.drtio.core import ChannelInterface + +from cxp_downconn import CXP_DownConn +from cxp_upconn import CXP_UpConn + +class CXP(Module, AutoCSR): + def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads): + nchannels = len(pads) + self.rx_start_init = CSRStorage() + self.rx_restart = CSRStatus() + self.rx_bypass_clk_alignment = CSRStorage() + + self.tx_start_init = CSRStorage() + self.tx_restart = CSRStorage() + + self.loopback_mode = CSRStorage(3) + + self.txinit_phaligndone = CSRStatus() + self.rxinit_phaligndone = CSRStatus() + self.rx_ready = CSRStatus() + + self.data_0 = CSRStorage(8) + self.data_1 = CSRStorage(8) + self.control_bit_0 = CSRStorage() + self.control_bit_1 = CSRStorage() + self.encoded_0 = CSRStatus(10) + self.encoded_1 = CSRStatus(10) + + self.rxdata_0 = CSRStatus(10) + self.rxdata_1 = CSRStatus(10) + self.decoded_data_0 = CSRStatus(8) + self.decoded_data_1 = CSRStatus(8) + self.decoded_k_0 = CSRStatus() + self.decoded_k_1 = CSRStatus() + + # # # + + self.submodules.crc = CXP_CRC(8) + + # FIFOs with transmission priority + # 0: Trigger packet + # 1: IO acknowledgment for trigger packet + # 2: All other packets + + self.submodules.upconn = CXP_UpConn(debug_sma, sys_clk_freq, pmod_pads) + + + # single & master tx_mode can lock with rx in loopback + self.submodules.gtx = gtx = CXP_DownConn(refclk, pads, sys_clk_freq, tx_mode="single", rx_mode="single") + + # DEBUG:loopback + self.sync += gtx.loopback_mode.eq(self.loopback_mode.storage) + + # # ! debug sma + # self.specials += [ + # Instance("OBUF", i_I=gtx.rxoutclk, o_O=debug_sma.p_tx), + # Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx) + # ] + + self.comb += [ + self.txinit_phaligndone.status.eq(self.gtx.tx_init.Xxphaligndone), + self.rxinit_phaligndone.status.eq(self.gtx.rx_init.Xxphaligndone), + self.rx_ready.status.eq(self.gtx.rx_ready), + ] + + self.sync.cxp_gtx_tx += [ + self.gtx.encoder.d[0].eq(self.data_0.storage), + self.gtx.encoder.k[0].eq(self.control_bit_0.storage), + self.encoded_0.status.eq(self.gtx.encoder.output[0]), + + self.gtx.encoder.d[1].eq(self.data_1.storage), + self.gtx.encoder.k[1].eq(self.control_bit_1.storage), + self.encoded_1.status.eq(self.gtx.encoder.output[1]), + ] + self.sync.cxp_gtx_rx += [ + self.rxdata_0.status.eq(self.gtx.decoders[0].input), + self.decoded_data_0.status.eq(self.gtx.decoders[0].d), + self.decoded_k_0.status.eq(self.gtx.decoders[0].k), + + self.rxdata_1.status.eq(self.gtx.decoders[1].input), + self.decoded_data_1.status.eq(self.gtx.decoders[1].d), + self.decoded_k_1.status.eq(self.gtx.decoders[1].k), + ] + + # TODO: rip encoder & rx clockalignment out of CXP_GTX + + # TODO: use expose encoder & decoder from CXP + # encoder.k = 1 if sending control bit, different calculation + # encoder.d = data 8 bit + + + + channel_interface = ChannelInterface(gtx.encoder, gtx.decoders) + self.comb += channel_interface.rx_ready.eq(gtx.rx_ready) + channel_interfaces = [] + channel_interfaces.append(channel_interface) + + # TransceiverInterface, just adding cxp_rx_ + self.stable_clkin = CSRStorage() + self.txenable = CSRStorage(len(channel_interfaces)) + for i in range(len(channel_interfaces)): + name = "cxp_gtx_rx" + str(i) + setattr(self.clock_domains, "cd_"+name, ClockDomain(name=name)) + self.channels = channel_interfaces + + + # TODO: add tx_phase_alignment for multi CXP + # The TX phase alignment will fail with a wrong TXUSRCLK frequency + + + self.comb += [ + gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage), + + gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage), + gtx.txenable.eq(self.txenable.storage[0]), + gtx.tx_restart.eq(self.tx_restart.storage), + ] + + # TODO: Connect multilane cxp_tx + + # TODO: Connect slave i's `cxp_gtx_rx` clock to `cxp_gtx_rxi` clock + self.comb += [ + getattr(self, "cd_cxp_gtx_rx" + str(0)).clk.eq(self.gtx.cd_cxp_gtx_rx.clk), + getattr(self, "cd_cxp_gtx_rx" + str(0)).rst.eq(self.gtx.cd_cxp_gtx_rx.rst) + ] + +class CXP_CRC(Module, AutoCSR): + width = 32 + polynom = 0x04C11DB7 + seed = 2**width-1 + def __init__(self, data_width): + self.d = Signal(data_width) + self.stb = Signal() + self.reset = Signal() + self.val = Signal(self.width, reset=self.seed) + + self.data = CSR(data_width) + self.en = CSR() + self.value = CSRStatus(self.width) + self.processed = CSRStatus(self.width) + + # # # + + self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom) + + self.sync += [ + self.val.eq(self.engine.next), + If(self.stb, + self.engine.data.eq(self.d), + + If(self.reset, + self.engine.last.eq(self.seed), + # clear reset bit + self.reset.eq(0), + ).Else( + self.engine.last.eq(self.val), + ) + ), + ] + + # DEBUG: remove those csr + # TODO: do char bit reverse outside of this submodule + + p0 = Signal(8) + p1 = Signal(8) + p2 = Signal(8) + p3 = Signal(8) + self.comb += [ + p3.eq(self.engine.next[:8][::-1]), + p2.eq(self.engine.next[8:16][::-1]), + p1.eq(self.engine.next[16:24][::-1]), + p0.eq(self.engine.next[24:32][::-1]), + ] + self.sync += [ + self.d.eq(self.data.r), + self.stb.eq(self.data.re), + If(self.en.re, self.reset.eq(1)), + + self.value.status.eq(self.engine.next), + self.processed.status.eq(Cat(p3, p2, p1, p0)), + ]