1
0
Fork 0

Compare commits

...

3 Commits

Author SHA1 Message Date
morgan 1f8ef6bf96 cxp downconn: use auto aligner
cxp downconn: fix autoaligner checking
2024-08-09 15:37:45 +08:00
morgan 0e69c5d5ba cxp downconn: refactor bruteforce aligner 2024-08-09 15:37:22 +08:00
morgan dbce74d831 cxp downconn: cleanup & use bruteforce aligner 2024-08-09 15:37:22 +08:00
1 changed files with 100 additions and 65 deletions

View File

@ -1,4 +1,6 @@
from migen import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer
from migen.genlib.misc import WaitTimer
from migen.genlib.resetsync import AsyncResetSynchronizer
from misoc.cores.code_8b10b import Encoder, Decoder
@ -6,8 +8,8 @@ from misoc.interconnect.csr import *
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
from operator import add
from functools import reduce
from operator import add
class CXP_DownConn(Module, AutoCSR):
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
@ -99,13 +101,12 @@ class CXP_DownConn(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.clk_aligner.rxslide, o_O=pmod_pads[0]),
Instance("OBUF", i_I=gtx.clk_aligner.ready, o_O=pmod_pads[1]),
# Instance("OBUF", i_I=gtx.tx_init.Xxdlysresetdone , o_O=pmod_pads[2]),
# Instance("OBUF", i_I=gtx.tx_init.Xxphaligndone , o_O=pmod_pads[3]),
# Instance("OBUF", i_I=, o_O=pmod_pads[4]),
# Instance("OBUF", i_I=, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=, o_O=pmod_pads[6]),
Instance("OBUF", i_I=gtx.comma_det.aligner_en_rxclk, o_O=pmod_pads[0]),
Instance("OBUF", i_I=gtx.comma_det.rxinit_done, o_O=pmod_pads[1]),
Instance("OBUF", i_I=gtx.comma_det.restart, o_O=pmod_pads[2]),
Instance("OBUF", i_I=gtx.comma_det.comma_aligned, o_O=pmod_pads[3]),
Instance("OBUF", i_I=gtx.comma_det.ready, o_O=pmod_pads[4]),
Instance("OBUF", i_I=gtx.comma_det.valid_data, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=, o_O=pmod_pads[7]),
]
@ -131,6 +132,8 @@ class CXP_DownConn(Module, AutoCSR):
self.decoded_k_0 = CSRStatus()
self.decoded_k_1 = CSRStatus()
self.shifted = CSRStatus(9)
self.sync.cxp_gtx_tx += [
If(counter == 0,
@ -158,6 +161,9 @@ class CXP_DownConn(Module, AutoCSR):
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),
# If(self.gtx.clk_aligner.comma_det.detected,
# self.shifted.status.eq(self.gtx.clk_aligner.comma_det.bitshift),
# )
]
@ -253,77 +259,108 @@ class QPLL(Module):
)
]
# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped
# compared to the usual 8b10b binary representation.
class Manual_Aligner(Module):
def __init__(self, comma, check_cycles=20000):
self.rxslide = Signal()
self.rxdata = Signal(20)
class Comma_Detector(Module):
def __init__(self, comma, check_period=50_000, width=20):
self.data = Signal(width)
self.rxinit_done = Signal()
self.aligner_en_rxclk = Signal()
self.ready = Signal()
self.restart = Signal()
# # #
checks_reset = Signal()
error_seen = Signal()
comma_seen = Signal()
rx1cnt = Signal(max=11)
self.comma_aligned = Signal()
self.valid_data = Signal()
self.submodules.recheck_ps = recheck_ps = PulseSynchronizer("sys", "cxp_gtx_rx")
aligned = Signal()
self.specials += MultiReg(self.comma_aligned, aligned)
valid_data = Signal()
self.specials += MultiReg(self.valid_data, valid_data)
comma_n = ~comma & 0b1111111111
rx1cnt = Signal(max=11)
self.sync.cxp_gtx_rx += [
rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])),
If(checks_reset,
error_seen.eq(0)
).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6),
error_seen.eq(1)
rx1cnt.eq(reduce(add, [self.data[i] for i in range(10)])),
If(recheck_ps.o,
self.comma_aligned.eq(0)
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
self.comma_aligned.eq(1)
),
If(checks_reset,
comma_seen.eq(0)
).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n),
comma_seen.eq(1)
If(recheck_ps.o,
self.valid_data.eq(0)
).Elif((rx1cnt == 4) | (rx1cnt == 5) | (rx1cnt == 6),
self.valid_data.eq(1)
),
]
check_counter = Signal(reset=check_period-1, max=check_period)
check = Signal()
aligner_en_sys = Signal()
self.specials += MultiReg(aligner_en_sys, self.aligner_en_rxclk, odomain="cxp_gtx_rx")
self.sync += [
check.eq(0),
If(check_counter == 0,
check_counter.eq(check_counter.reset),
check.eq(1),
).Else(
check_counter.eq(check_counter - 1),
)
]
# minimum of 32 RXUSRCLK2 cycles are required between two RXSLIDE pulses
slide_timer = ClockDomainsRenamer("cxp_gtx_rx")(WaitTimer(64))
self.submodules += slide_timer
counter = Signal(reset=check_cycles-1, max=check_cycles)
fsm = ClockDomainsRenamer("cxp_gtx_rx")(FSM(reset_state="IDLE"))
self.submodules += fsm
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
slide_timer.wait.eq(1),
If(slide_timer.done,
If(comma_seen,
NextState("READY"),
aligner_en_sys.eq(1),
If(check,
recheck_ps.i.eq(1),
If(aligned,
NextState("WAIT_NO_ERROR"),
).Else(
NextState("SLIDING")
self.restart.eq(1),
)
)
)
fsm.act("SLIDING",
self.rxslide.eq(1),
checks_reset.eq(1),
NextState("IDLE")
fsm.act("WAIT_NO_ERROR",
aligner_en_sys.eq(1),
If(check,
recheck_ps.i.eq(1),
If(aligned & valid_data,
NextState("READY"),
).Else(
self.restart.eq(1),
NextState("IDLE"),
)
)
)
fsm.act("READY",
self.ready.eq(1),
If(counter == 0,
NextValue(counter, check_cycles - 1),
If(error_seen,
If(check,
recheck_ps.i.eq(1),
If(~(aligned & valid_data),
self.restart.eq(1),
NextState("IDLE"),
)
).Else(
NextValue(counter, counter - 1),
)
)
class GTX(Module):
# Settings:
# * GTX reference clock @ 125MHz
@ -364,7 +401,7 @@ class GTX(Module):
# TX generates cxp_tx clock, init must be in system domain
# FIXME: 500e6 is used to fix Xx reset by holding gtxXxreset for a couple cycle more
self.submodules.tx_init = tx_init = GTXInit(500e6, False, mode=tx_mode)
self.submodules.rx_init = rx_init = GTXInit(500e6, True, mode=rx_mode)
self.submodules.rx_init = rx_init = GTXInit(sys_clk_freq, True, mode=rx_mode)
# RX receives restart commands from txusrclk domain
# self.submodules.rx_init = rx_init = ClockDomainsRenamer("cxp_gtx_tx")(GTXInit(500e6, True, mode=rx_mode))
@ -377,7 +414,7 @@ class GTX(Module):
txdata = Signal(20)
rxdata = Signal(20)
rxslide = Signal()
comma_align_en = Signal()
# Note: the following parameters were set after consulting AR45360
self.specials += \
Instance("GTXE2_CHANNEL",
@ -469,7 +506,7 @@ class GTX(Module):
i_RXDFEXYDEN=1,
i_RXDFEXYDHOLD=0,
i_RXDFEXYDOVRDEN=0,
i_RXLPMEN=0, # RXLPMEN = 0: DFE mode is enabled
i_RXLPMEN=0, # RXLPMEN = 0: DFE mode is enabled for non scramble data
p_RX_DFE_GAIN_CFG=0x0207EA,
p_RX_DFE_VP_CFG=0b00011111100000011,
p_RX_DFE_UT_CFG=0b10001000000000000,
@ -507,21 +544,18 @@ class GTX(Module):
# RX Byte and Word Alignment Attributes
p_ALIGN_COMMA_DOUBLE="FALSE",
p_ALIGN_COMMA_ENABLE=0b1111111111,
p_ALIGN_COMMA_WORD=2,
p_ALIGN_MCOMMA_DET="FALSE",
p_ALIGN_COMMA_WORD=2, # allow rxslide to shift 20 times
p_ALIGN_MCOMMA_DET="TRUE",
p_ALIGN_MCOMMA_VALUE=0b1010000011,
p_ALIGN_PCOMMA_DET="FALSE",
p_ALIGN_PCOMMA_DET="TRUE",
p_ALIGN_PCOMMA_VALUE=0b0101111100,
p_SHOW_REALIGN_COMMA="FALSE",
p_RXSLIDE_AUTO_WAIT=7,
p_RXSLIDE_MODE="PCS",
p_RXSLIDE_MODE="OFF",
p_RX_SIG_VALID_DLY=10,
# Manual Word Alignment
i_RXPCOMMAALIGNEN=0,
i_RXMCOMMAALIGNEN=0,
i_RXCOMMADETEN=1, # enable word alignment, but breaks rxrestart if gtxXxreset hold too short
i_RXSLIDE=rxslide,
i_RXPCOMMAALIGNEN=comma_align_en,
i_RXMCOMMAALIGNEN=comma_align_en,
i_RXCOMMADETEN=1, # enable auto word alignment
# RX 8B/10B Decoder Attributes
p_RX_DISPERR_SEQ_MATCH="FALSE",
@ -648,12 +682,13 @@ class GTX(Module):
]
self.submodules.clk_aligner = clk_aligner = Manual_Aligner(0b0101111100)
self.submodules.comma_det = comma_det = Comma_Detector(0b0101111100)
self.comb += [
clk_aligner.rxdata.eq(rxdata),
rxslide.eq(clk_aligner.rxslide),
self.rx_ready.eq(clk_aligner.ready),
comma_det.data.eq(rxdata),
comma_det.rxinit_done.eq(rx_init.done),
comma_align_en.eq(comma_det.aligner_en_rxclk),
self.rx_ready.eq(comma_det.ready),
rx_init.restart.eq(self.rx_restart),
rx_init.restart.eq(self.rx_restart | comma_det.restart),
tx_init.restart.eq(self.tx_restart),
]