diff --git a/src/gateware/cxp_downconn.py b/src/gateware/cxp_downconn.py index be342f4..368271e 100644 --- a/src/gateware/cxp_downconn.py +++ b/src/gateware/cxp_downconn.py @@ -8,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): @@ -101,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.rxinit_done, o_O=pmod_pads[1]), - Instance("OBUF", i_I=gtx.clk_aligner.restart, o_O=pmod_pads[2]), - Instance("OBUF", i_I=gtx.clk_aligner.comma_aligned, o_O=pmod_pads[3]), - Instance("OBUF", i_I=gtx.clk_aligner.ready, o_O=pmod_pads[4]), - Instance("OBUF", i_I=gtx.clk_aligner.comma_det_reset, o_O=pmod_pads[5]), - # Instance("OBUF", i_I=gtx.clk_aligner.comma_det.detected, 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]), ] @@ -260,157 +259,106 @@ class QPLL(Module): ) ] -# detect if the comma is located at data[0:10] -class Comma_Detector(Module): - def __init__(self, comma, width): - self.reset = Signal() - self.data = Signal(width) - - self.detected = Signal() - self.bitshift = Signal(max=width) - self.comma_aligned = Signal() - - # # # - last_data = Signal(10) - data = Signal(width+10) - - comma_n = ~comma & 0b1111111111 - self.sync += [ - last_data.eq(self.data[:10]), - data.eq(Cat(self.data, last_data)), - If(self.reset, - self.bitshift.eq(0), - self.detected.eq(0), - ), - - If(self.reset, - self.comma_aligned.eq(0) - ).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n), - self.comma_aligned.eq(1) - ), - ] - - for n in range(width): - self.sync += \ - If((data[n:n+10] == comma) | (data[n:n+10] == comma_n), - self.bitshift.eq(width-n), - self.detected.eq(1), - ) # Warning: Xilinx transceivers are LSB first, and comma needs to be flipped -# compared to the usual 8b10b binary representation. -# 50000 62.5MHz locks | 125MHz takes a lot time to locks | 250MHz many commas -# 30000 62.5MHz & 125MHz locks | 250MHz more commas but not lock -# 30000 62.5MHz & 125MHz locks | 250MHz nothing to see -# 27000 62.5MHz & 125MHz locks | 250MHz nothing to see -# 25000 62.5MHz takes long time to lock | 125MHz no lock | 250MHz locks -# 24700 62.5MHz lock | 125MHz sometimes locks | 250MHz locks -# 20000 250MHz nothing to see -# 10000 62.5MHz & 125MHz nothing to see | 250MHz many commas not much can survive the second check -class Manual_Aligner(Module): - def __init__(self, comma, check_period=24_700, width=20): - self.rxslide = Signal() +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() # # # - timerout_period = 5_000_000 - timerout = Signal(reset=timerout_period-1, max=timerout_period) - ready_rxclk = Signal() - self.specials += MultiReg(ready_rxclk, self.ready) - self.ready.attr.add("no_retiming") - - - restart_sys = Signal() - restart_rxclk = Signal() - self.specials += MultiReg(restart_rxclk, restart_sys) - restart_sys.attr.add("no_retiming") - - # NOTE: be careful of all the timeout values!!! It should be much larger than the longest fsm - # TODO: fix comma fall too fast for 500MHz (10Gpbs) -> need to change CDR_CFG via DRP - # Restart rx periodically since rx need to be restart when connecting RXN/RXP - self.sync += [ - self.restart.eq(0), - If(restart_sys, - timerout.eq(timerout.reset), - self.restart.eq(1), - ).Elif(~self.ready, - If((timerout == 0), - timerout.eq(timerout.reset), - self.restart.eq(1), - ).Else( - timerout.eq(timerout - 1), - ) - ) - ] - - self.comma_det_reset = Signal() 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 += [ - If(self.comma_det_reset, + 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(recheck_ps.o, + self.valid_data.eq(0) + ).Elif((rx1cnt == 4) | (rx1cnt == 5) | (rx1cnt == 6), + self.valid_data.eq(1) + ), ] - self.submodules.fsm = fsm = ClockDomainsRenamer("cxp_gtx_rx")(FSM(reset_state="IDLE")) + + 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), + ) + ] - rxinit_done_rxclk = Signal() - self.specials += MultiReg(self.rxinit_done, rxinit_done_rxclk, odomain="cxp_gtx_rx") - - check_timer = Signal(reset=check_period-1,max=check_period) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", - self.comma_det_reset.eq(1), - If(rxinit_done_rxclk, - NextValue(check_timer, check_timer.reset), - NextState("WAIT_COMMA_DET"), - ), + aligner_en_sys.eq(1), + If(check, + recheck_ps.i.eq(1), + If(aligned, + NextState("WAIT_NO_ERROR"), + ).Else( + self.restart.eq(1), + ) + ) ) - fsm.act("WAIT_COMMA_DET", - NextValue(check_timer, check_timer - 1), - If(check_timer == 0, - restart_rxclk.eq(1), - NextState("RESET"), - # restart_ps.i.eq(1), - # NextState("IDLE"), - ).Elif(self.comma_aligned, - NextValue(check_timer, check_timer.reset), - self.comma_det_reset.eq(1), - NextState("READY") + 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", - ready_rxclk.eq(1), - If(check_timer == 0, - NextValue(check_timer, check_timer.reset), - self.comma_det_reset.eq(1), - If(~self.comma_aligned, - restart_rxclk.eq(1), - NextState("RESET"), - # restart_ps.i.eq(1), - # NextState("IDLE"), + self.ready.eq(1), + If(check, + recheck_ps.i.eq(1), + If(~(aligned & valid_data), + self.restart.eq(1), + NextState("IDLE"), ) - ).Else( - NextValue(check_timer, check_timer - 1), ) ) - fsm.act("RESET", - restart_rxclk.eq(1), - ) class GTX(Module): @@ -466,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", @@ -558,7 +506,7 @@ class GTX(Module): i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, - i_RXLPMEN=1, # RXLPMEN = 1: LPM mode is enabled for non scramble data + 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, @@ -597,18 +545,17 @@ class GTX(Module): p_ALIGN_COMMA_DOUBLE="FALSE", p_ALIGN_COMMA_ENABLE=0b1111111111, p_ALIGN_COMMA_WORD=2, # allow rxslide to shift 20 times - p_ALIGN_MCOMMA_DET="FALSE", + 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, - i_RXPCOMMAALIGNEN=0, - i_RXMCOMMAALIGNEN=0, - i_RXCOMMADETEN=0, # enable manual word alignment - 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", @@ -735,13 +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.data.eq(rxdata), - clk_aligner.rxinit_done.eq(rx_init.done), - 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 | clk_aligner.restart), + rx_init.restart.eq(self.rx_restart | comma_det.restart), tx_init.restart.eq(self.tx_restart), ]