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"
else:
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)
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])
class Receiver(Module):
def __init__(self, qpll, pad, sys_clk_freq, tx_mode, rx_mode, debug_sma, pmod_pads):
self.submodules.gtx = gtx = GTX(qpll, pad, sys_clk_freq, tx_mode, rx_mode)
def __init__(self, qpll, pad, sys_clk_freq, rx_mode):
self.submodules.gtx = gtx = GTX(qpll, pad, sys_clk_freq, None, rx_mode)
self.source = stream.Endpoint(word_layout)
@ -294,13 +294,21 @@ class Comma_Aligner(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"]
assert rx_mode in ["single", "master", "slave"]
"""
A reconfigurable linerate GTX with QPLL
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.rx_manual_restart = Signal()
@ -318,9 +326,6 @@ class GTX(Module):
self.dout = Signal(16)
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
@ -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)
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_realigned = Signal()
comma_det = Signal()
@ -383,17 +399,17 @@ class GTX(Module):
# TX Startup/Reset
i_TXPHDLYRESET=0,
i_TXDLYBYPASS=0,
i_TXPHALIGNEN=1 if tx_mode != "single" else 0,
i_GTTXRESET=tx_init.gtXxreset,
o_TXRESETDONE=tx_init.Xxresetdone,
i_TXDLYSRESET=tx_init.Xxdlysreset,
o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone,
i_TXPHINIT=tx_init.txphinit if tx_mode != "single" else 0,
o_TXPHINITDONE=tx_init.txphinitdone if tx_mode != "single" else Signal(),
i_TXPHALIGN=tx_init.Xxphalign if tx_mode != "single" else 0,
i_TXDLYEN=tx_init.Xxdlyen if tx_mode != "single" else 0,
o_TXPHALIGNDONE=tx_init.Xxphaligndone,
i_TXUSERRDY=tx_init.Xxuserrdy,
i_TXPHALIGNEN=1 if tx_mode in ["master", "slave"] else 0,
i_GTTXRESET=tx_init.gtXxreset if tx_mode else 0,
o_TXRESETDONE=tx_init.Xxresetdone if tx_mode else 0,
i_TXDLYSRESET=tx_init.Xxdlysreset if tx_mode else 0,
o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone if tx_mode else 0,
i_TXPHINIT=tx_init.txphinit if tx_mode in ["master", "slave"] else 0,
o_TXPHINITDONE=tx_init.txphinitdone if tx_mode in ["master", "slave"] else Signal(),
i_TXPHALIGN=tx_init.Xxphalign if tx_mode in ["master", "slave"] else 0,
i_TXDLYEN=tx_init.Xxdlyen if tx_mode in ["master", "slave"] else 0,
o_TXPHALIGNDONE=tx_init.Xxphaligndone if tx_mode else 0,
i_TXUSERRDY=tx_init.Xxuserrdy if tx_mode else 0,
p_TXPMARESET_TIME=1,
p_TXPCSRESET_TIME=1,
i_TXINHIBIT=~self.txenable,
@ -404,8 +420,8 @@ class GTX(Module):
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]),
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_TXUSRCLK=ClockSignal("cxp_gtx_tx"),
i_TXUSRCLK2=ClockSignal("cxp_gtx_tx"),
i_TXUSRCLK=ClockSignal("cxp_gtx_tx") if tx_mode else 0,
i_TXUSRCLK2=ClockSignal("cxp_gtx_tx") if tx_mode else 0,
# TX electrical
i_TXBUFDIFFCTRL=0b100,
@ -414,15 +430,15 @@ class GTX(Module):
# RX Startup/Reset
i_RXPHDLYRESET=0,
i_RXDLYBYPASS=0,
i_RXPHALIGNEN=1 if rx_mode != "single" else 0,
i_GTRXRESET=rx_init.gtXxreset,
o_RXRESETDONE=rx_init.Xxresetdone,
i_RXDLYSRESET=rx_init.Xxdlysreset,
o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone,
i_RXPHALIGN=rx_init.Xxphalign if rx_mode != "single" else 0,
i_RXDLYEN=rx_init.Xxdlyen if rx_mode != "single" else 0,
o_RXPHALIGNDONE=rx_init.Xxphaligndone,
i_RXUSERRDY=rx_init.Xxuserrdy,
i_RXPHALIGNEN=1 if rx_mode in ["master", "slave"] else 0,
i_GTRXRESET=rx_init.gtXxreset if rx_mode else 0,
o_RXRESETDONE=rx_init.Xxresetdone if rx_mode else 0,
i_RXDLYSRESET=rx_init.Xxdlysreset if rx_mode else 0,
o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone if rx_mode else 0,
i_RXPHALIGN=rx_init.Xxphalign if rx_mode in ["master", "slave"] else 0,
i_RXDLYEN=rx_init.Xxdlyen if rx_mode in ["master", "slave"] else 0,
o_RXPHALIGNDONE=rx_init.Xxphaligndone if rx_mode else 0,
i_RXUSERRDY=rx_init.Xxuserrdy if rx_mode else 0,
p_RXPMARESET_TIME=1,
p_RXPCSRESET_TIME=1,
@ -454,8 +470,8 @@ class GTX(Module):
# i_RXSYSCLKSEL=0b00,
i_RXOUTCLKSEL=0b010,
o_RXOUTCLK=self.rxoutclk,
i_RXUSRCLK=ClockSignal("cxp_gtx_rx"),
i_RXUSRCLK2=ClockSignal("cxp_gtx_rx"),
i_RXUSRCLK=ClockSignal("cxp_gtx_rx") if rx_mode else 0,
i_RXUSRCLK2=ClockSignal("cxp_gtx_rx") if rx_mode else 0,
# RX Clock Correction Attributes
p_CLK_CORRECT_USE="FALSE",
@ -545,7 +561,7 @@ class GTX(Module):
o_DRPDO=self.dout,
o_DRPRDY=self.dready,
# ! loopback for debugging
# Nearend Loopback
i_LOOPBACK = self.loopback_mode,
p_TX_LOOPBACK_DRIVE_HIZ = "FALSE",
p_RXPRBS_ERR_LOOPBACK = 0b0,
@ -565,52 +581,58 @@ class GTX(Module):
# TX clocking
# A PLL is used to generate the correct frequency for TXUSRCLK (UG476 Equation 3-1)
self.clock_domains.cd_cxp_gtx_tx = ClockDomain()
txpll_fb_clk = Signal()
txoutclk_buf = Signal()
txpll_clkout = Signal()
# As TX buffer is bypass, freq txoutclk_buf == refclk
# To match the require frequency TXUSRCLK = linerate/datewidth (UG476 Equation 3-1)
# A PLL need to be used to generate the correct frequency for TXUSRCLK
if tx_mode:
self.clock_domains.cd_cxp_gtx_tx = ClockDomain()
txpll_fb_clk = Signal()
txoutclk_buf = Signal()
txpll_clkout = Signal()
self.txpll_reset = Signal()
self.pll_daddr = Signal(7)
self.pll_dclk = Signal()
self.pll_den = Signal()
self.pll_din = Signal(16)
self.pll_dwen = Signal()
self.txpll_reset = Signal()
self.pll_daddr = Signal(7)
self.pll_dclk = Signal()
self.pll_den = Signal()
self.pll_din = Signal(16)
self.pll_dwen = Signal()
self.txpll_locked = Signal()
self.pll_dout = Signal(16)
self.pll_dready = Signal()
self.specials += [
Instance("PLLE2_ADV",
p_BANDWIDTH="HIGH",
o_LOCKED=self.txpll_locked,
i_RST=self.txpll_reset,
self.txpll_locked = Signal()
self.pll_dout = Signal(16)
self.pll_dready = Signal()
pll_fbout_mult = 8
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,
p_CLKIN1_PERIOD=1e9/sys_clk_freq, # ns
i_CLKIN1=txoutclk_buf,
p_CLKIN1_PERIOD=1e9/sys_clk_freq, # ns
i_CLKIN1=txoutclk_buf,
# VCO @ 1.25GHz
p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk,
# VCO @ 1.25GHz
p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk,
# frequency = linerate/40
p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout,
# frequency = linerate/40
p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout,
# Dynamic Reconfiguration Ports
i_DADDR = self.pll_daddr,
i_DCLK = self.pll_dclk,
i_DEN = self.pll_den,
i_DI = self.pll_din,
i_DWE = self.pll_dwen,
o_DO = self.pll_dout,
o_DRDY = self.pll_dready,
),
Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_buf),
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)
# Dynamic Reconfiguration Ports
i_DADDR = self.pll_daddr,
i_DCLK = self.pll_dclk,
i_DEN = self.pll_den,
i_DI = self.pll_din,
i_DWE = self.pll_dwen,
o_DO = self.pll_dout,
o_DRDY = self.pll_dready,
),
Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_buf),
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
# 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)
# 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.comb += [
comma_aligner.data.eq(rxdata),