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]),