2
0
mirror of https://github.com/m-labs/artiq.git synced 2024-12-25 03:08:27 +08:00

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
This commit is contained in:
Florent Kermarrec 2017-08-29 13:38:52 +02:00
parent 26a11a296c
commit 89558e2653
3 changed files with 158 additions and 292 deletions

View File

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

View File

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

View File

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