diff --git a/src/gateware/cxp_downconn.py b/src/gateware/cxp_downconn.py index 350e6d5..aceeea1 100644 --- a/src/gateware/cxp_downconn.py +++ b/src/gateware/cxp_downconn.py @@ -4,8 +4,10 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.cores.code_8b10b import Encoder, Decoder from misoc.interconnect.csr import * +from misoc.interconnect import stream from artiq.gateware.drtio.transceiver.gtx_7series_init import * +from cxp_pipeline import downconn_layout from functools import reduce from operator import add @@ -45,7 +47,6 @@ class CXP_DownConn_PHY(Module, AutoCSR): # TODO: add extension gtx connections # TODO: add connection interface - # TODO: Connect slave cxp_gtx_rx clock tgt # checkout channel interfaces & drtio_gtx @@ -99,9 +100,35 @@ class CXP_DownConn_PHY(Module, AutoCSR): ), ] + self.sources = [] + + for n, gtx in enumerate(self.gtxs): + + # gtx rx -> fifo out -> cdc out + + fifo_out = stream.SyncFIFO(downconn_layout, 128) + self.submodules += ClockDomainsRenamer("cxp_gtx_rx")(fifo_out) + + cdc_out = stream.AsyncFIFO(downconn_layout, 128) + self.submodules += ClockDomainsRenamer({"write": "cxp_gtx_rx", "read": "sys"})(cdc_out) + self.sources.append(cdc_out) + self.comb += fifo_out.source.connect(cdc_out.sink) + for i in range(4): + self.sync.cxp_gtx_rx += [ + fifo_out.sink.stb.eq(0), + # don't store idle word in fifo + If(gtx.rx_ready & fifo_out.sink.ack & (gtx.decoders[0].d != 0xBC), + fifo_out.sink.stb.eq(1), + fifo_out.sink.data[i*8:(i*8)+8].eq(gtx.decoders[i].d), + fifo_out.sink.k[i].eq(gtx.decoders[i].k), + ), + ] + + + # DEBUG: tx of gtx is not used in CXP # DEBUG: txusrclk PLL DRG self.txpll_reset = CSRStorage() @@ -118,6 +145,9 @@ class CXP_DownConn_PHY(Module, AutoCSR): self.txinit_phaligndone = CSRStatus() self.rxinit_phaligndone = CSRStatus() + self.tx_stb = CSRStorage() + self.sinks = [] + for n, gtx in enumerate(self.gtxs): self.comb += [ gtx.txpll_reset.eq(self.txpll_reset.storage), @@ -137,6 +167,47 @@ class CXP_DownConn_PHY(Module, AutoCSR): self.loopback_mode = CSRStorage(3) self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage) + # DEBUG: datain + # fw -> fifo (sys) -> cdc fifo -> fifo in -> gtx tx + + fifo_in = stream.AsyncFIFO(downconn_layout, 128) + self.submodules += ClockDomainsRenamer({"write": "sys", "read": "cxp_gtx_tx"})(fifo_in) + self.sinks.append(fifo_in) + + # TODO: why there this send an extra 0xFB word + txstb = Signal() + self.specials += MultiReg(self.tx_stb.storage, txstb, odomain="cxp_gtx_tx") + + self.sync.cxp_gtx_tx += [ + fifo_in.source.ack.eq(0), + If(fifo_in.source.stb & txstb, + fifo_in.source.ack.eq(1), + ) + ] + + self.comb += [ + If(fifo_in.source.stb & fifo_in.source.ack, + gtx.encoder.d[0].eq(fifo_in.source.data[:8]), + gtx.encoder.d[1].eq(fifo_in.source.data[8:16]), + gtx.encoder.d[2].eq(fifo_in.source.data[16:24]), + gtx.encoder.d[3].eq(fifo_in.source.data[24:]), + gtx.encoder.k[0].eq(fifo_in.source.k[0]), + gtx.encoder.k[1].eq(fifo_in.source.k[1]), + gtx.encoder.k[2].eq(fifo_in.source.k[2]), + gtx.encoder.k[3].eq(fifo_in.source.k[3]), + ).Else( + # NOTE: IDLE WORD + gtx.encoder.d[0].eq(0xBC), + gtx.encoder.k[0].eq(1), + gtx.encoder.d[1].eq(0x3C), + gtx.encoder.k[1].eq(1), + gtx.encoder.d[2].eq(0x3C), + gtx.encoder.k[2].eq(1), + gtx.encoder.d[3].eq(0xB5), + gtx.encoder.k[3].eq(0), + ) + ] + # DEBUG: IO SMA & PMOD if n == 0: self.specials += [ @@ -144,9 +215,9 @@ class CXP_DownConn_PHY(Module, AutoCSR): # Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx), # # pmod 0-7 pin - # Instance("OBUF", i_I=gtx.comma_checker.comma_aligned, o_O=pmod_pads[0]), - # Instance("OBUF", i_I=gtx.comma_checker.comma_det, o_O=pmod_pads[1]), - # Instance("OBUF", i_I=gtx.comma_checker.restart_sys, o_O=pmod_pads[2]), + Instance("OBUF", i_I=txstb, o_O=pmod_pads[0]), + Instance("OBUF", i_I=fifo_in.source.stb, 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]), @@ -159,43 +230,6 @@ class CXP_DownConn_PHY(Module, AutoCSR): # Instance("OBUF", i_I=gtx.dready, o_O=pmod_pads[3]), ] - # DEBUG: datain - - - self.sync.cxp_gtx_tx += [ - gtx.encoder.d[0].eq(0xBC), - gtx.encoder.k[0].eq(1), - gtx.encoder.d[1].eq(0x3C), - gtx.encoder.k[1].eq(1), - gtx.encoder.d[2].eq(0x3C), - gtx.encoder.k[2].eq(1), - gtx.encoder.d[3].eq(0xB5), - gtx.encoder.k[3].eq(0), - ] - - for i in range(4): - gtx.decoders[i].input.attr.add("no_retiming") - gtx.decoders[i].d.attr.add("no_retiming") - gtx.decoders[i].k.attr.add("no_retiming") - - rxdata_name = "rxdata_" + str(i) - rxdata_csr = CSRStatus(10, name=rxdata_name) - setattr(self, rxdata_name, rxdata_csr) - - decoded_name = "decoded_data_" + str(i) - decoded_csr = CSRStatus(8, name=decoded_name) - setattr(self, decoded_name, decoded_csr) - - k_name = "rxdata_" + str(i) - k_csr = CSRStatus(1, name=k_name) - setattr(self, k_name, k_csr) - - self.sync.cxp_gtx_rx += [ - rxdata_csr.status.eq(gtx.decoders[i].input), - decoded_csr.status.eq(gtx.decoders[i].d), - k_csr.status.eq(gtx.decoders[i].k), - ] - class QPLL(Module, AutoCSR): def __init__(self, refclk, sys_clk_freq): self.clk = Signal()