downconn GW: update to add none for tx/rxmode

This commit is contained in:
morgan 2025-01-16 10:49:41 +08:00
parent edb7c62d4a
commit 635c62b8e6

View File

@ -36,7 +36,7 @@ class CXP_RXPHYs(Module, AutoCSR):
rx_mode = "single" rx_mode = "single"
else: else:
rx_mode = "master" if i == master else "slave" rx_mode = "master" if i == master else "slave"
rx = Receiver(qpll, pad, sys_clk_freq, "single", rx_mode, debug_sma, pmod_pads) rx = Receiver(qpll, pad, sys_clk_freq, rx_mode)
self.phys.append(rx) self.phys.append(rx)
setattr(self.submodules, "rx"+str(i), rx) setattr(self.submodules, "rx"+str(i), rx)
@ -52,8 +52,8 @@ class CXP_RXPHYs(Module, AutoCSR):
self.submodules.rx_phase_alignment = GTXInitPhaseAlignment([rx_phy.gtx.rx_init for rx_phy in self.phys]) self.submodules.rx_phase_alignment = GTXInitPhaseAlignment([rx_phy.gtx.rx_init for rx_phy in self.phys])
class Receiver(Module): class Receiver(Module):
def __init__(self, qpll, pad, sys_clk_freq, tx_mode, rx_mode, debug_sma, pmod_pads): def __init__(self, qpll, pad, sys_clk_freq, rx_mode):
self.submodules.gtx = gtx = GTX(qpll, pad, sys_clk_freq, tx_mode, rx_mode) self.submodules.gtx = gtx = GTX(qpll, pad, sys_clk_freq, None, rx_mode)
self.source = stream.Endpoint(word_layout) self.source = stream.Endpoint(word_layout)
@ -294,13 +294,21 @@ class Comma_Aligner(Module):
class GTX(Module): class GTX(Module):
def __init__(self, qpll, pads, sys_clk_freq, tx_mode="single", rx_mode="single"): """
assert tx_mode in ["single", "master", "slave"] A reconfigurable linerate GTX with QPLL
assert rx_mode in ["single", "master", "slave"] Designed for 12.5, 10, 6.25, 5, 3.125, 2.5, 1.25Gpbs
To change the linerate:
1) Change the VCO frequency
- 12.5, 6.25, 3.125Gbps: QPLL VCO @ 12.5GHz,
- 10, 6.25, 5, 2.5, 1.25Gbps: QPLL VCO @ 10GHz
2) Update the xXOUT_DIV and TXUSRCLK frequency if using tx
3) Reset the entire rx and tx
"""
def __init__(self, qpll, pads, sys_clk_freq, tx_mode="single", rx_mode="single"):
assert tx_mode in ["single", "master", "slave", None]
assert rx_mode in ["single", "master", "slave", None]
# linerate = USRCLK * datawidth
pll_fbout_mult = 8
txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq
self.tx_restart = Signal() self.tx_restart = Signal()
self.rx_manual_restart = Signal() self.rx_manual_restart = Signal()
@ -318,9 +326,6 @@ class GTX(Module):
self.dout = Signal(16) self.dout = Signal(16)
self.dready = Signal() self.dready = Signal()
self.submodules.encoder = ClockDomainsRenamer("cxp_gtx_tx")(Encoder(4, True))
self.submodules.decoders = [ClockDomainsRenamer("cxp_gtx_rx")(
(Decoder(True))) for _ in range(4)]
# transceiver direct clock outputs # transceiver direct clock outputs
@ -330,18 +335,29 @@ class GTX(Module):
# # # # # #
# TX generates cxp_tx clock, init must be in system domain
self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode)
self.submodules.rx_init = rx_init = GTXInit(sys_clk_freq, True, mode=rx_mode)
self.comb += [
tx_init.cplllock.eq(qpll.lock),
rx_init.cplllock.eq(qpll.lock)
]
txdata = Signal(40) txdata = Signal(40)
rxdata = Signal(40) rxdata = Signal(40)
if tx_mode:
self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode)
self.comb += tx_init.cplllock.eq(qpll.lock),
self.submodules.encoder = ClockDomainsRenamer("cxp_gtx_tx")(Encoder(4, True))
self.comb += txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1], self.encoder.output[2], self.encoder.output[3])),
if rx_mode:
self.submodules.rx_init = rx_init = GTXInit(sys_clk_freq, True, mode=rx_mode)
self.comb += rx_init.cplllock.eq(qpll.lock)
self.submodules.decoders = [ClockDomainsRenamer("cxp_gtx_rx")(
(Decoder(True))) for _ in range(4)]
self.comb += [
self.decoders[0].input.eq(rxdata[:10]),
self.decoders[1].input.eq(rxdata[10:20]),
self.decoders[2].input.eq(rxdata[20:30]),
self.decoders[3].input.eq(rxdata[30:]),
]
comma_aligned = Signal() comma_aligned = Signal()
comma_realigned = Signal() comma_realigned = Signal()
comma_det = Signal() comma_det = Signal()
@ -383,17 +399,17 @@ class GTX(Module):
# TX Startup/Reset # TX Startup/Reset
i_TXPHDLYRESET=0, i_TXPHDLYRESET=0,
i_TXDLYBYPASS=0, i_TXDLYBYPASS=0,
i_TXPHALIGNEN=1 if tx_mode != "single" else 0, i_TXPHALIGNEN=1 if tx_mode in ["master", "slave"] else 0,
i_GTTXRESET=tx_init.gtXxreset, i_GTTXRESET=tx_init.gtXxreset if tx_mode else 0,
o_TXRESETDONE=tx_init.Xxresetdone, o_TXRESETDONE=tx_init.Xxresetdone if tx_mode else 0,
i_TXDLYSRESET=tx_init.Xxdlysreset, i_TXDLYSRESET=tx_init.Xxdlysreset if tx_mode else 0,
o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone if tx_mode else 0,
i_TXPHINIT=tx_init.txphinit if tx_mode != "single" else 0, i_TXPHINIT=tx_init.txphinit if tx_mode in ["master", "slave"] else 0,
o_TXPHINITDONE=tx_init.txphinitdone if tx_mode != "single" else Signal(), o_TXPHINITDONE=tx_init.txphinitdone if tx_mode in ["master", "slave"] else Signal(),
i_TXPHALIGN=tx_init.Xxphalign if tx_mode != "single" else 0, i_TXPHALIGN=tx_init.Xxphalign if tx_mode in ["master", "slave"] else 0,
i_TXDLYEN=tx_init.Xxdlyen if tx_mode != "single" else 0, i_TXDLYEN=tx_init.Xxdlyen if tx_mode in ["master", "slave"] else 0,
o_TXPHALIGNDONE=tx_init.Xxphaligndone, o_TXPHALIGNDONE=tx_init.Xxphaligndone if tx_mode else 0,
i_TXUSERRDY=tx_init.Xxuserrdy, i_TXUSERRDY=tx_init.Xxuserrdy if tx_mode else 0,
p_TXPMARESET_TIME=1, p_TXPMARESET_TIME=1,
p_TXPCSRESET_TIME=1, p_TXPCSRESET_TIME=1,
i_TXINHIBIT=~self.txenable, i_TXINHIBIT=~self.txenable,
@ -404,8 +420,8 @@ class GTX(Module):
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]), i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]),
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18], txdata[28], txdata[38]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18], txdata[28], txdata[38]),
i_TXDATA=Cat(txdata[:8], txdata[10:18], txdata[20:28], txdata[30:38]), i_TXDATA=Cat(txdata[:8], txdata[10:18], txdata[20:28], txdata[30:38]),
i_TXUSRCLK=ClockSignal("cxp_gtx_tx"), i_TXUSRCLK=ClockSignal("cxp_gtx_tx") if tx_mode else 0,
i_TXUSRCLK2=ClockSignal("cxp_gtx_tx"), i_TXUSRCLK2=ClockSignal("cxp_gtx_tx") if tx_mode else 0,
# TX electrical # TX electrical
i_TXBUFDIFFCTRL=0b100, i_TXBUFDIFFCTRL=0b100,
@ -414,15 +430,15 @@ class GTX(Module):
# RX Startup/Reset # RX Startup/Reset
i_RXPHDLYRESET=0, i_RXPHDLYRESET=0,
i_RXDLYBYPASS=0, i_RXDLYBYPASS=0,
i_RXPHALIGNEN=1 if rx_mode != "single" else 0, i_RXPHALIGNEN=1 if rx_mode in ["master", "slave"] else 0,
i_GTRXRESET=rx_init.gtXxreset, i_GTRXRESET=rx_init.gtXxreset if rx_mode else 0,
o_RXRESETDONE=rx_init.Xxresetdone, o_RXRESETDONE=rx_init.Xxresetdone if rx_mode else 0,
i_RXDLYSRESET=rx_init.Xxdlysreset, i_RXDLYSRESET=rx_init.Xxdlysreset if rx_mode else 0,
o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone, o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone if rx_mode else 0,
i_RXPHALIGN=rx_init.Xxphalign if rx_mode != "single" else 0, i_RXPHALIGN=rx_init.Xxphalign if rx_mode in ["master", "slave"] else 0,
i_RXDLYEN=rx_init.Xxdlyen if rx_mode != "single" else 0, i_RXDLYEN=rx_init.Xxdlyen if rx_mode in ["master", "slave"] else 0,
o_RXPHALIGNDONE=rx_init.Xxphaligndone, o_RXPHALIGNDONE=rx_init.Xxphaligndone if rx_mode else 0,
i_RXUSERRDY=rx_init.Xxuserrdy, i_RXUSERRDY=rx_init.Xxuserrdy if rx_mode else 0,
p_RXPMARESET_TIME=1, p_RXPMARESET_TIME=1,
p_RXPCSRESET_TIME=1, p_RXPCSRESET_TIME=1,
@ -454,8 +470,8 @@ class GTX(Module):
# i_RXSYSCLKSEL=0b00, # i_RXSYSCLKSEL=0b00,
i_RXOUTCLKSEL=0b010, i_RXOUTCLKSEL=0b010,
o_RXOUTCLK=self.rxoutclk, o_RXOUTCLK=self.rxoutclk,
i_RXUSRCLK=ClockSignal("cxp_gtx_rx"), i_RXUSRCLK=ClockSignal("cxp_gtx_rx") if rx_mode else 0,
i_RXUSRCLK2=ClockSignal("cxp_gtx_rx"), i_RXUSRCLK2=ClockSignal("cxp_gtx_rx") if rx_mode else 0,
# RX Clock Correction Attributes # RX Clock Correction Attributes
p_CLK_CORRECT_USE="FALSE", p_CLK_CORRECT_USE="FALSE",
@ -545,7 +561,7 @@ class GTX(Module):
o_DRPDO=self.dout, o_DRPDO=self.dout,
o_DRPRDY=self.dready, o_DRPRDY=self.dready,
# ! loopback for debugging # Nearend Loopback
i_LOOPBACK = self.loopback_mode, i_LOOPBACK = self.loopback_mode,
p_TX_LOOPBACK_DRIVE_HIZ = "FALSE", p_TX_LOOPBACK_DRIVE_HIZ = "FALSE",
p_RXPRBS_ERR_LOOPBACK = 0b0, p_RXPRBS_ERR_LOOPBACK = 0b0,
@ -565,52 +581,58 @@ class GTX(Module):
# TX clocking # TX clocking
# A PLL is used to generate the correct frequency for TXUSRCLK (UG476 Equation 3-1) # As TX buffer is bypass, freq txoutclk_buf == refclk
self.clock_domains.cd_cxp_gtx_tx = ClockDomain() # To match the require frequency TXUSRCLK = linerate/datewidth (UG476 Equation 3-1)
txpll_fb_clk = Signal() # A PLL need to be used to generate the correct frequency for TXUSRCLK
txoutclk_buf = Signal() if tx_mode:
txpll_clkout = Signal() self.clock_domains.cd_cxp_gtx_tx = ClockDomain()
txpll_fb_clk = Signal()
txoutclk_buf = Signal()
txpll_clkout = Signal()
self.txpll_reset = Signal() self.txpll_reset = Signal()
self.pll_daddr = Signal(7) self.pll_daddr = Signal(7)
self.pll_dclk = Signal() self.pll_dclk = Signal()
self.pll_den = Signal() self.pll_den = Signal()
self.pll_din = Signal(16) self.pll_din = Signal(16)
self.pll_dwen = Signal() self.pll_dwen = Signal()
self.txpll_locked = Signal() self.txpll_locked = Signal()
self.pll_dout = Signal(16) self.pll_dout = Signal(16)
self.pll_dready = Signal() self.pll_dready = Signal()
self.specials += [
Instance("PLLE2_ADV",
p_BANDWIDTH="HIGH",
o_LOCKED=self.txpll_locked,
i_RST=self.txpll_reset,
p_CLKIN1_PERIOD=1e9/sys_clk_freq, # ns pll_fbout_mult = 8
i_CLKIN1=txoutclk_buf, txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq
self.specials += [
Instance("PLLE2_ADV",
p_BANDWIDTH="HIGH",
o_LOCKED=self.txpll_locked,
i_RST=self.txpll_reset,
# VCO @ 1.25GHz p_CLKIN1_PERIOD=1e9/sys_clk_freq, # ns
p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1, i_CLKIN1=txoutclk_buf,
i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk,
# frequency = linerate/40 # VCO @ 1.25GHz
p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout, p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk,
# Dynamic Reconfiguration Ports # frequency = linerate/40
i_DADDR = self.pll_daddr, p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout,
i_DCLK = self.pll_dclk,
i_DEN = self.pll_den, # Dynamic Reconfiguration Ports
i_DI = self.pll_din, i_DADDR = self.pll_daddr,
i_DWE = self.pll_dwen, i_DCLK = self.pll_dclk,
o_DO = self.pll_dout, i_DEN = self.pll_den,
o_DRDY = self.pll_dready, i_DI = self.pll_din,
), i_DWE = self.pll_dwen,
Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_buf), o_DO = self.pll_dout,
Instance("BUFG", i_I=txpll_clkout, o_O=self.cd_cxp_gtx_tx.clk), o_DRDY = self.pll_dready,
AsyncResetSynchronizer(self.cd_cxp_gtx_tx, ~self.txpll_locked & ~tx_init.done) ),
] Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_buf),
self.comb += tx_init.restart.eq(self.tx_restart) Instance("BUFG", i_I=txpll_clkout, o_O=self.cd_cxp_gtx_tx.clk),
AsyncResetSynchronizer(self.cd_cxp_gtx_tx, ~self.txpll_locked & ~tx_init.done)
]
self.comb += tx_init.restart.eq(self.tx_restart)
# RX clocking # RX clocking
# the CDR matches the required frequency for RXUSRCLK, no need for PLL # the CDR matches the required frequency for RXUSRCLK, no need for PLL
@ -624,15 +646,6 @@ class GTX(Module):
self.comb += rx_init.restart.eq(self.rx_manual_restart) self.comb += rx_init.restart.eq(self.rx_manual_restart)
# 8b10b Encoder/Decoder
self.comb += [
txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1], self.encoder.output[2], self.encoder.output[3])),
self.decoders[0].input.eq(rxdata[:10]),
self.decoders[1].input.eq(rxdata[10:20]),
self.decoders[2].input.eq(rxdata[20:30]),
self.decoders[3].input.eq(rxdata[30:]),
]
self.submodules.comma_aligner = comma_aligner = Comma_Aligner(0b0101111100) self.submodules.comma_aligner = comma_aligner = Comma_Aligner(0b0101111100)
self.comb += [ self.comb += [
comma_aligner.data.eq(rxdata), comma_aligner.data.eq(rxdata),