From 89558e265361682ed44a9c66cadc47dd37b97007 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 29 Aug 2017 13:38:52 +0200 Subject: [PATCH] gateware/serwb: for the initial version set delay in the center of the valid sampling window and don't use phase detectors we'll use phase detectors later when it will be working reliably for both artix7 and kintex ultrascale --- artiq/gateware/serwb/kusphy.py | 56 +----- artiq/gateware/serwb/phy.py | 327 ++++++++++++++------------------- artiq/gateware/serwb/s7phy.py | 67 ++----- 3 files changed, 158 insertions(+), 292 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 4733fb58c..412f469e4 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -5,8 +5,6 @@ from migen.genlib.misc import BitSlip from misoc.cores.code_8b10b import Encoder, Decoder -from artiq.gateware.serwb.phy import PhaseDetector - class KUSSerdesPLL(Module): def __init__(self, refclk_freq, linerate, vco_div=1): @@ -228,22 +226,17 @@ class KUSSerdes(Module): self.submodules.rx_gearbox = Gearbox(8, "serdes_5x", 40, "serdes") self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(40)) - self.submodules.phase_detector = ClockDomainsRenamer("serdes_5x")(PhaseDetector()) - - # 2 serdes for phase detection: 1 master (used for data) / 1 slave - serdes_m_i_nodelay = Signal() - serdes_s_i_nodelay = Signal() + serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=pads.rx_p, i_IB=pads.rx_n, - o_O=serdes_m_i_nodelay, - o_OB=serdes_s_i_nodelay + o_O=serdes_i_nodelay ) ] - serdes_m_i_delayed = Signal() - serdes_m_q = Signal(8) + serdes_i_delayed = Signal() + serdes_q = Signal(8) self.specials += [ Instance("IDELAYE3", p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, @@ -256,55 +249,22 @@ class KUSSerdes(Module): i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc, i_CE=rx_delay_ce, - i_IDATAIN=serdes_m_i_nodelay, o_DATAOUT=serdes_m_i_delayed + i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), Instance("ISERDESE3", p_DATA_WIDTH=8, - i_D=serdes_m_i_delayed, + i_D=serdes_i_delayed, i_RST=ResetSignal("serdes"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, i_CLK=ClockSignal("serdes_20x"), i_CLK_B=~ClockSignal("serdes_20x"), i_CLKDIV=ClockSignal("serdes_5x"), - o_Q=serdes_m_q + o_Q=serdes_q ) ] - self.comb += self.phase_detector.mdata.eq(serdes_m_q) - - serdes_s_i_delayed = Signal() - serdes_s_q = Signal(8) - self.specials += [ - Instance("IDELAYE3", - p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, - p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, - # Note: can't use TIME mode since not reloading DELAY_VALUE on rst... - # Got answer from Xilinx, need testing: - # https://forums.xilinx.com/xlnx/board/crawl_message?board.id=ultrascale&message.id=4699 - p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", - p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=50, # 1/4 bit period (ambient temp) - - i_CLK=ClockSignal("serdes_5x"), - i_RST=rx_delay_rst, i_LOAD=0, - i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc, - i_CE=rx_delay_ce, - - i_IDATAIN=serdes_s_i_nodelay, o_DATAOUT=serdes_s_i_delayed - ), - Instance("ISERDESE3", - p_DATA_WIDTH=8, - - i_D=serdes_s_i_delayed, - i_RST=ResetSignal("serdes"), - i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, - i_CLK=ClockSignal("serdes_20x"), i_CLK_B=~ClockSignal("serdes_20x"), - i_CLKDIV=ClockSignal("serdes_5x"), - o_Q=serdes_s_q - ) - ] - self.comb += self.phase_detector.sdata.eq(~serdes_s_q) self.comb += [ - self.rx_gearbox.i.eq(serdes_m_q), + self.rx_gearbox.i.eq(serdes_q), self.rx_bitslip.value.eq(rx_bitslip_value), self.rx_bitslip.i.eq(self.rx_gearbox.o), self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 39640208d..179e141f9 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -5,86 +5,6 @@ from migen.genlib.misc import WaitTimer from misoc.interconnect.csr import * -class PhaseDetector(Module, AutoCSR): - def __init__(self, nbits=8): - self.mdata = Signal(8) - self.sdata = Signal(8) - - self.reset = Signal() - self.too_early = Signal() - self.too_late = Signal() - - # # # - - # Ideal sampling (middle of the eye): - # _____ _____ _____ - # | |_____| |_____| |_____| data - # + + + + + + master sampling - # - - - - - - slave sampling (90°/bit period) - # Since taps are fixed length delays, this ideal case is not possible - # and we will fall in the 2 following possible cases: - # - # 1) too late sampling (idelay needs to be decremented): - # _____ _____ _____ - # | |_____| |_____| |_____| data - # + + + + + + master sampling - # - - - - - - slave sampling (90°/bit period) - # On mdata transition, mdata != sdata - # - # - # 2) too early sampling (idelay needs to be incremented): - # _____ _____ _____ - # | |_____| |_____| |_____| data - # + + + + + + master sampling - # - - - - - - slave sampling (90°/bit period) - # On mdata transition, mdata == sdata - - transition = Signal() - inc = Signal() - dec = Signal() - - # Find transition - mdata_d = Signal(8) - self.sync.serdes_5x += mdata_d.eq(self.mdata) - self.comb += transition.eq(mdata_d != self.mdata) - - - # Find what to do - self.comb += [ - inc.eq(transition & (self.mdata == self.sdata)), - dec.eq(transition & (self.mdata != self.sdata)) - ] - - # Error accumulator - lateness = Signal(nbits, reset=2**(nbits - 1)) - too_late = Signal() - too_early = Signal() - reset_lateness = Signal() - self.comb += [ - too_late.eq(lateness == (2**nbits - 1)), - too_early.eq(lateness == 0) - ] - self.sync.serdes_5x += [ - If(reset_lateness, - lateness.eq(2**(nbits - 1)) - ).Elif(~too_late & ~too_early, - If(inc, lateness.eq(lateness - 1)), - If(dec, lateness.eq(lateness + 1)) - ) - ] - - # control / status cdc - self.specials += [ - MultiReg(too_early, self.too_early), - MultiReg(too_late, self.too_late) - ] - self.submodules.do_reset_lateness = PulseSynchronizer("sys", "serdes_5x") - self.comb += [ - reset_lateness.eq(self.do_reset_lateness.o), - self.do_reset_lateness.i.eq(self.reset) - ] - - # Master <--> Slave synchronization: # 1) Master sends idle pattern (zeroes) to reset Slave. # 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle pattern. @@ -102,25 +22,26 @@ class SerdesMasterInit(Module): # # # self.delay = delay = Signal(max=taps) - self.delay_found = delay_found = Signal() + self.delay_min = delay_min = Signal(max=taps) + self.delay_min_found = delay_min_found = Signal() + self.delay_max = delay_max = Signal(max=taps) + self.delay_max_found = delay_max_found = Signal() self.bitslip = bitslip = Signal(max=40) - self.bitslip_found = bitslip_found = Signal() - timer = WaitTimer(8192) + timer = WaitTimer(1024) self.submodules += timer self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) self.comb += self.fsm.reset.eq(self.reset) - phase_detector_too_early_last = Signal() - fsm.act("IDLE", - NextValue(delay_found, 0), NextValue(delay, 0), + NextValue(delay_min, 0), + NextValue(delay_min_found, 0), + NextValue(delay_max, 0), + NextValue(delay_max_found, 0), serdes.rx_delay_rst.eq(1), - NextValue(bitslip_found, 0), NextValue(bitslip, 0), - NextValue(phase_detector_too_early_last, 0), NextState("RESET_SLAVE"), serdes.tx_idle.eq(1) ) @@ -142,61 +63,75 @@ class SerdesMasterInit(Module): timer.wait.eq(1), If(timer.done, timer.wait.eq(0), - serdes.phase_detector.reset.eq(1), - If(~delay_found, - NextState("CHECK_PHASE") - ).Else( - NextState("CHECK_PATTERN") - ), - ), - serdes.tx_comma.eq(1) - ) - fsm.act("CHECK_PHASE", - # Since we are always incrementing delay, - # ideal sampling is found when phase detector - # transitions from too_early to too_late - If(serdes.phase_detector.too_late & - phase_detector_too_early_last, - NextValue(delay_found, 1), NextState("CHECK_PATTERN") - ).Elif(serdes.phase_detector.too_late | - serdes.phase_detector.too_early, - NextValue(phase_detector_too_early_last, - serdes.phase_detector.too_early), - NextState("INC_DELAY") - ), - serdes.tx_comma.eq(1) - ) - fsm.act("INC_DELAY", - If(delay == (taps - 1), - NextState("ERROR") - ).Else( - NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1), - serdes.rx_delay_ce.eq(1), - NextState("WAIT_STABLE") ), serdes.tx_comma.eq(1) ) fsm.act("CHECK_PATTERN", - If(serdes.rx_comma, - timer.wait.eq(1), - If(timer.done, - NextValue(bitslip_found, 1), - NextState("READY") - ) + If(~delay_min_found, + If(serdes.rx_comma, + timer.wait.eq(1), + If(timer.done, + NextValue(delay_min, delay), + NextValue(delay_min_found, 1) + ) + ).Else( + NextState("INC_DELAY_BITSLIP") + ), ).Else( - NextState("INC_BITSLIP") + If(~serdes.rx_comma, + NextValue(delay_max, delay), + NextValue(delay_max_found, 1), + NextState("RESET_SAMPLING_WINDOW") + ).Else( + NextState("INC_DELAY_BITSLIP") + ) ), serdes.tx_comma.eq(1) ) self.comb += serdes.rx_bitslip_value.eq(bitslip) - fsm.act("INC_BITSLIP", - If(bitslip == (40 - 1), - NextState("ERROR") + fsm.act("INC_DELAY_BITSLIP", + NextState("WAIT_STABLE"), + If(delay == (taps - 1), + If(delay_min_found, + NextState("ERROR") + ), + If(bitslip == (40 - 1), + NextValue(bitslip, 0) + ).Else( + NextValue(bitslip, bitslip + 1) + ), + NextValue(delay, 0), + serdes.rx_delay_rst.eq(1) ).Else( - NextValue(bitslip, bitslip + 1), - NextState("WAIT_STABLE") + NextValue(delay, delay + 1), + serdes.rx_delay_inc.eq(1), + serdes.rx_delay_ce.eq(1) + ), + serdes.tx_comma.eq(1) + ) + fsm.act("RESET_SAMPLING_WINDOW", + NextValue(delay, 0), + serdes.rx_delay_rst.eq(1), + NextState("WAIT_SAMPLING_WINDOW"), + serdes.tx_comma.eq(1) + ) + fsm.act("CONFIGURE_SAMPLING_WINDOW", + If(delay == (delay_min + (delay_max - delay_min)[1:]), + NextState("READY") + ).Else( + NextValue(delay, delay + 1), + serdes.rx_delay_inc.eq(1), + serdes.rx_delay_ce.eq(1), + NextState("WAIT_SAMPLING_WINDOW") + ), + serdes.tx_comma.eq(1) + ) + fsm.act("WAIT_SAMPLING_WINDOW", + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("CONFIGURE_SAMPLING_WINDOW") ), serdes.tx_comma.eq(1) ) @@ -217,9 +152,11 @@ class SerdesSlaveInit(Module, AutoCSR): # # # self.delay = delay = Signal(max=taps) - self.delay_found = delay_found = Signal() + self.delay_min = delay_min = Signal(max=taps) + self.delay_min_found = delay_min_found = Signal() + self.delay_max = delay_max = Signal(max=taps) + self.delay_max_found = delay_max_found = Signal() self.bitslip = bitslip = Signal(max=40) - self.bitslip_found = bitslip_found = Signal() timer = WaitTimer(1024) self.submodules += timer @@ -227,16 +164,14 @@ class SerdesSlaveInit(Module, AutoCSR): self.comb += self.reset.eq(serdes.rx_idle) self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - - phase_detector_too_early_last = Signal() - fsm.act("IDLE", - NextValue(delay_found, 0), NextValue(delay, 0), + NextValue(delay_min, 0), + NextValue(delay_min_found, 0), + NextValue(delay_max, 0), + NextValue(delay_max_found, 0), serdes.rx_delay_rst.eq(1), - NextValue(bitslip_found, 0), NextValue(bitslip, 0), - NextValue(phase_detector_too_early_last, 0), NextState("WAIT_STABLE"), serdes.tx_idle.eq(1) ) @@ -244,64 +179,76 @@ class SerdesSlaveInit(Module, AutoCSR): timer.wait.eq(1), If(timer.done, timer.wait.eq(0), - serdes.phase_detector.reset.eq(1), - If(~delay_found, - NextState("CHECK_PHASE") - ).Else( - NextState("CHECK_PATTERN") - ), - ), - serdes.tx_idle.eq(1) - ) - fsm.act("CHECK_PHASE", - # Since we are always incrementing delay, - # ideal sampling is found when phase detector - # transitions from too_early to too_late - If(serdes.phase_detector.too_late & - phase_detector_too_early_last, - NextValue(delay_found, 1), NextState("CHECK_PATTERN") - ).Elif(serdes.phase_detector.too_late | - serdes.phase_detector.too_early, - NextValue(phase_detector_too_early_last, - serdes.phase_detector.too_early), - NextState("INC_DELAY") - ), - serdes.tx_idle.eq(1) - ) - fsm.act("INC_DELAY", - If(delay == (taps - 1), - NextState("ERROR") - ).Else( - NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1), - serdes.rx_delay_ce.eq(1), - NextState("WAIT_STABLE") ), serdes.tx_idle.eq(1) ) fsm.act("CHECK_PATTERN", - If(serdes.rx_comma, - timer.wait.eq(1), - If(timer.done, - NextValue(bitslip_found, 1), - NextState("SEND_PATTERN") - ) + If(~delay_min_found, + If(serdes.rx_comma, + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextValue(delay_min, delay), + NextValue(delay_min_found, 1) + ) + ).Else( + NextState("INC_DELAY_BITSLIP") + ), ).Else( - NextState("INC_BITSLIP") + If(~serdes.rx_comma, + NextValue(delay_max, delay), + NextValue(delay_max_found, 1), + NextState("RESET_SAMPLING_WINDOW") + ).Else( + NextState("INC_DELAY_BITSLIP") + ) ), serdes.tx_idle.eq(1) ) self.comb += serdes.rx_bitslip_value.eq(bitslip) - fsm.act("INC_BITSLIP", - If(bitslip == (40 - 1), - NextState("ERROR") + fsm.act("INC_DELAY_BITSLIP", + NextState("WAIT_STABLE"), + If(delay == (taps - 1), + If(delay_min_found, + NextState("ERROR") + ), + If(bitslip == (40 - 1), + NextValue(bitslip, 0) + ).Else( + NextValue(bitslip, bitslip + 1) + ), + NextValue(delay, 0), + serdes.rx_delay_rst.eq(1) ).Else( - NextValue(bitslip, bitslip + 1), - NextState("WAIT_STABLE") + NextValue(delay, delay + 1), + serdes.rx_delay_inc.eq(1), + serdes.rx_delay_ce.eq(1) ), serdes.tx_idle.eq(1) ) + fsm.act("RESET_SAMPLING_WINDOW", + NextValue(delay, 0), + serdes.rx_delay_rst.eq(1), + NextState("WAIT_SAMPLING_WINDOW") + ) + fsm.act("CONFIGURE_SAMPLING_WINDOW", + If(delay == (delay_min + (delay_max - delay_min)[1:]), + NextState("SEND_PATTERN") + ).Else( + NextValue(delay, delay + 1), + serdes.rx_delay_inc.eq(1), + serdes.rx_delay_ce.eq(1), + NextState("WAIT_SAMPLING_WINDOW") + ) + ) + fsm.act("WAIT_SAMPLING_WINDOW", + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("CONFIGURE_SAMPLING_WINDOW") + ) + ) fsm.act("SEND_PATTERN", timer.wait.eq(1), If(timer.done, @@ -327,9 +274,11 @@ class SerdesControl(Module, AutoCSR): self.error = CSRStatus() self.delay = CSRStatus(9) - self.delay_found = CSRStatus() + self.delay_min_found = CSRStatus() + self.delay_min = CSRStatus(9) + self.delay_max_found = CSRStatus() + self.delay_max = CSRStatus(9) self.bitslip = CSRStatus(6) - self.bitslip_found = CSRStatus() # # # @@ -338,8 +287,10 @@ class SerdesControl(Module, AutoCSR): self.comb += [ self.ready.status.eq(init.ready), self.error.status.eq(init.error), - self.delay_found.status.eq(init.delay_found), self.delay.status.eq(init.delay), - self.bitslip_found.status.eq(init.bitslip_found), + self.delay_min_found.status.eq(init.delay_min_found), + self.delay_min.status.eq(init.delay_min), + self.delay_max_found.status.eq(init.delay_max_found), + self.delay_max.status.eq(init.delay_max), self.bitslip.status.eq(init.bitslip) ] diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index ed1366805..2b5a0473c 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -5,8 +5,6 @@ from migen.genlib.misc import BitSlip from misoc.cores.code_8b10b import Encoder, Decoder -from artiq.gateware.serwb.phy import PhaseDetector - class S7SerdesPLL(Module): def __init__(self, refclk_freq, linerate, vco_div=1): @@ -221,22 +219,17 @@ class S7Serdes(Module): self.submodules.rx_gearbox = Gearbox(8, "serdes_5x", 40, "serdes") self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(40)) - self.submodules.phase_detector = ClockDomainsRenamer("serdes_5x")(PhaseDetector()) - - # 2 serdes for phase detection: 1 master (used for data) / 1 slave - serdes_m_i_nodelay = Signal() - serdes_s_i_nodelay = Signal() + serdes_i_nodelay = Signal() self.specials += [ Instance("IBUFDS_DIFF_OUT", i_I=pads.rx_p, i_IB=pads.rx_n, - o_O=serdes_m_i_nodelay, - o_OB=serdes_s_i_nodelay + o_O=serdes_i_nodelay ) ] - serdes_m_i_delayed = Signal() - serdes_m_q = Signal(8) + serdes_i_delayed = Signal() + serdes_q = Signal(8) self.specials += [ Instance("IDELAYE2", p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", @@ -249,66 +242,28 @@ class S7Serdes(Module): i_CE=self.rx_delay_ce, i_LDPIPEEN=0, i_INC=self.rx_delay_inc, - i_IDATAIN=serdes_m_i_nodelay, o_DATAOUT=serdes_m_i_delayed + i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), Instance("ISERDESE2", p_DATA_WIDTH=8, p_DATA_RATE="DDR", p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, p_IOBDELAY="IFD", - i_DDLY=serdes_m_i_delayed, + i_DDLY=serdes_i_delayed, i_CE1=1, i_RST=ResetSignal("serdes"), i_CLK=ClockSignal("serdes_20x"), i_CLKB=~ClockSignal("serdes_20x"), i_CLKDIV=ClockSignal("serdes_5x"), i_BITSLIP=0, - o_Q8=serdes_m_q[0], o_Q7=serdes_m_q[1], - o_Q6=serdes_m_q[2], o_Q5=serdes_m_q[3], - o_Q4=serdes_m_q[4], o_Q3=serdes_m_q[5], - o_Q2=serdes_m_q[6], o_Q1=serdes_m_q[7] + o_Q8=serdes_q[0], o_Q7=serdes_q[1], + o_Q6=serdes_q[2], o_Q5=serdes_q[3], + o_Q4=serdes_q[4], o_Q3=serdes_q[5], + o_Q2=serdes_q[6], o_Q1=serdes_q[7] ) ] - self.comb += self.phase_detector.mdata.eq(serdes_m_q) - - serdes_s_i_delayed = Signal() - serdes_s_q = Signal(8) - serdes_s_idelay_value = int(1/(4*pll.linerate)/78e-12) # 1/4 bit period - assert serdes_s_idelay_value < 32 - self.specials += [ - Instance("IDELAYE2", - p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", - p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", - p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=serdes_s_idelay_value, - - i_C=ClockSignal(), - i_LD=self.rx_delay_rst, - i_CE=self.rx_delay_ce, - i_LDPIPEEN=0, i_INC=self.rx_delay_inc, - - i_IDATAIN=serdes_s_i_nodelay, o_DATAOUT=serdes_s_i_delayed - ), - Instance("ISERDESE2", - p_DATA_WIDTH=8, p_DATA_RATE="DDR", - p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", - p_NUM_CE=1, p_IOBDELAY="IFD", - - i_DDLY=serdes_s_i_delayed, - i_CE1=1, - i_RST=ResetSignal("serdes"), - i_CLK=ClockSignal("serdes_20x"), i_CLKB=~ClockSignal("serdes_20x"), - i_CLKDIV=ClockSignal("serdes_5x"), - i_BITSLIP=0, - o_Q8=serdes_s_q[0], o_Q7=serdes_s_q[1], - o_Q6=serdes_s_q[2], o_Q5=serdes_s_q[3], - o_Q4=serdes_s_q[4], o_Q3=serdes_s_q[5], - o_Q2=serdes_s_q[6], o_Q1=serdes_s_q[7] - ) - ] - self.comb += self.phase_detector.sdata.eq(~serdes_s_q) self.comb += [ - self.rx_gearbox.i.eq(serdes_m_q), + self.rx_gearbox.i.eq(serdes_q), self.rx_bitslip.value.eq(rx_bitslip_value), self.rx_bitslip.i.eq(self.rx_gearbox.o), self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),