diff --git a/src/gateware/cxp_downconn.py b/src/gateware/cxp_downconn.py index 638ccfe..4631f1c 100644 --- a/src/gateware/cxp_downconn.py +++ b/src/gateware/cxp_downconn.py @@ -26,6 +26,7 @@ class CXP_DownConn(Module, AutoCSR): self.qpll_reset = CSR() self.qpll_locked = CSRStatus() + self.gtxs = [] # # # self.submodules.qpll = qpll = QPLL(refclk, sys_clk_freq) @@ -34,31 +35,25 @@ class CXP_DownConn(Module, AutoCSR): self.qpll_locked.status.eq(qpll.lock), ] - # TODO: add extension gtx connections - # single & master tx_mode can lock with rx in loopback - self.submodules.gtx = gtx = GTX(self.qpll, pads[0], sys_clk_freq, tx_mode="single", rx_mode="single") + nconn = len(pads) + + for i in range(nconn): + if i != 0: + break + gtx = GTX(self.qpll, pads[i], sys_clk_freq, tx_mode="single", rx_mode="single") + self.gtxs.append(gtx) + setattr(self.submodules, "gtx"+str(i), gtx) + + # TODO: add extension gtx connections + # TODO: add connection interface - # NOTE: No need to connect cxp_gtx_tx, we don't use tx anyway (just for loopback) # TODO: Connect slave cxp_gtx_rx clock tgt # checkout channel interfaces & drtio_gtx - # checkout GTPTXPhaseAlignement for inspiration + # GTPTXPhaseAlignement for inspiration - self.sync += [ - # GTX - self.txinit_phaligndone.status.eq(gtx.tx_init.Xxphaligndone), - self.rxinit_phaligndone.status.eq(gtx.rx_init.Xxphaligndone), - self.rx_ready.status.eq(gtx.rx_ready), - - gtx.txenable.eq(self.txenable.storage[0]), - gtx.tx_restart.eq(self.tx_restart.re), - gtx.rx_restart.eq(self.rx_restart.re), - gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage), - gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage), - ] - - # GTX Channels DRP + # Connect all GTX connections' DRP self.tx_div = CSRStorage(3) self.rx_div = CSRStorage(3) @@ -70,30 +65,46 @@ class CXP_DownConn(Module, AutoCSR): self.gtx_dout = CSRStatus(16) self.gtx_dready = CSR() - self.comb += gtx.dclk.eq(ClockSignal("sys")) - self.sync += [ - gtx.tx_rate.eq(self.tx_div.storage), - gtx.rx_rate.eq(self.rx_div.storage), + for gtx in self.gtxs: + self.sync += [ + self.txinit_phaligndone.status.eq(gtx.tx_init.Xxphaligndone), + self.rxinit_phaligndone.status.eq(gtx.rx_init.Xxphaligndone), + self.rx_ready.status.eq(gtx.rx_ready), + + gtx.txenable.eq(self.txenable.storage[0]), + gtx.tx_restart.eq(self.tx_restart.re), + gtx.rx_restart.eq(self.rx_restart.re), + gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage), + gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage), + ] + + self.comb += gtx.dclk.eq(ClockSignal("sys")) + self.sync += [ + gtx.tx_rate.eq(self.tx_div.storage), + gtx.rx_rate.eq(self.rx_div.storage), + + 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), + ), + ] + + - 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 DRG @@ -108,88 +119,90 @@ class CXP_DownConn(Module, AutoCSR): 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), + for n, gtx in enumerate(self.gtxs): + 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.txpll_locked.status.eq(gtx.txpll_locked), - self.pll_dout.status.eq(gtx.pll_dout), - self.pll_dready.status.eq(gtx.pll_dready), - ] + 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:loopback - self.loopback_mode = CSRStorage(3) - self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage) + # DEBUG:loopback + self.loopback_mode = CSRStorage(3) + self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage) - # DEBUG: IO SMA & PMOD - self.specials += [ - Instance("OBUF", i_I=gtx.cd_cxp_gtx_rx.clk, o_O=debug_sma.p_tx), - Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx), + # DEBUG: IO SMA & PMOD + if n == 0: + self.specials += [ + Instance("OBUF", i_I=gtx.cd_cxp_gtx_rx.clk, o_O=debug_sma.p_tx), + 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=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]), + # 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=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]), - # Instance("OBUF", i_I=gtx.dclk, o_O=pmod_pads[0]), - # Instance("OBUF", i_I=gtx.den, o_O=pmod_pads[1]), - # Instance("OBUF", i_I=gtx.dwen, o_O=pmod_pads[2]), - # Instance("OBUF", i_I=gtx.dready, o_O=pmod_pads[3]), - ] + # Instance("OBUF", i_I=gtx.dclk, o_O=pmod_pads[0]), + # Instance("OBUF", i_I=gtx.den, o_O=pmod_pads[1]), + # Instance("OBUF", i_I=gtx.dwen, o_O=pmod_pads[2]), + # Instance("OBUF", i_I=gtx.dready, o_O=pmod_pads[3]), + ] - # DEBUG: datain + # DEBUG: datain - self.sync.cxp_gtx_tx += [ - self.gtx.encoder.d[0].eq(0xBC), - self.gtx.encoder.k[0].eq(1), - self.gtx.encoder.d[1].eq(0x3C), - self.gtx.encoder.k[1].eq(1), - self.gtx.encoder.d[2].eq(0x3C), - self.gtx.encoder.k[2].eq(1), - self.gtx.encoder.d[3].eq(0xB5), - self.gtx.encoder.k[3].eq(0), - ] + 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), + ] - self.rxdata_0 = CSRStatus(10) - self.rxdata_1 = CSRStatus(10) - self.rxdata_2 = CSRStatus(10) - self.rxdata_3 = CSRStatus(10) - self.decoded_data_0 = CSRStatus(8) - self.decoded_data_1 = CSRStatus(8) - self.decoded_data_2 = CSRStatus(8) - self.decoded_data_3 = CSRStatus(8) - self.decoded_k_0 = CSRStatus() - self.decoded_k_1 = CSRStatus() - self.decoded_k_2 = CSRStatus() - self.decoded_k_3 = CSRStatus() + self.rxdata_0 = CSRStatus(10) + self.rxdata_1 = CSRStatus(10) + self.rxdata_2 = CSRStatus(10) + self.rxdata_3 = CSRStatus(10) + self.decoded_data_0 = CSRStatus(8) + self.decoded_data_1 = CSRStatus(8) + self.decoded_data_2 = CSRStatus(8) + self.decoded_data_3 = CSRStatus(8) + self.decoded_k_0 = CSRStatus() + self.decoded_k_1 = CSRStatus() + self.decoded_k_2 = CSRStatus() + self.decoded_k_3 = CSRStatus() - 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.sync.cxp_gtx_rx += [ + self.rxdata_0.status.eq(gtx.decoders[0].input), + self.decoded_data_0.status.eq(gtx.decoders[0].d), + self.decoded_k_0.status.eq(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), + self.rxdata_1.status.eq(gtx.decoders[1].input), + self.decoded_data_1.status.eq(gtx.decoders[1].d), + self.decoded_k_1.status.eq(gtx.decoders[1].k), - self.rxdata_2.status.eq(self.gtx.decoders[2].input), - self.decoded_data_2.status.eq(self.gtx.decoders[2].d), - self.decoded_k_2.status.eq(self.gtx.decoders[2].k), + self.rxdata_2.status.eq(gtx.decoders[2].input), + self.decoded_data_2.status.eq(gtx.decoders[2].d), + self.decoded_k_2.status.eq(gtx.decoders[2].k), - self.rxdata_3.status.eq(self.gtx.decoders[3].input), - self.decoded_data_3.status.eq(self.gtx.decoders[3].d), - self.decoded_k_3.status.eq(self.gtx.decoders[3].k), - ] + self.rxdata_3.status.eq(gtx.decoders[3].input), + self.decoded_data_3.status.eq(gtx.decoders[3].d), + self.decoded_k_3.status.eq(gtx.decoders[3].k), + ] class QPLL(Module, AutoCSR):