forked from M-Labs/artiq
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:
parent
26a11a296c
commit
89558e2653
@ -5,8 +5,6 @@ from migen.genlib.misc import BitSlip
|
|||||||
|
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
from misoc.cores.code_8b10b import Encoder, Decoder
|
||||||
|
|
||||||
from artiq.gateware.serwb.phy import PhaseDetector
|
|
||||||
|
|
||||||
|
|
||||||
class KUSSerdesPLL(Module):
|
class KUSSerdesPLL(Module):
|
||||||
def __init__(self, refclk_freq, linerate, vco_div=1):
|
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_gearbox = Gearbox(8, "serdes_5x", 40, "serdes")
|
||||||
self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(40))
|
self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(40))
|
||||||
|
|
||||||
self.submodules.phase_detector = ClockDomainsRenamer("serdes_5x")(PhaseDetector())
|
serdes_i_nodelay = Signal()
|
||||||
|
|
||||||
# 2 serdes for phase detection: 1 master (used for data) / 1 slave
|
|
||||||
serdes_m_i_nodelay = Signal()
|
|
||||||
serdes_s_i_nodelay = Signal()
|
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("IBUFDS_DIFF_OUT",
|
Instance("IBUFDS_DIFF_OUT",
|
||||||
i_I=pads.rx_p,
|
i_I=pads.rx_p,
|
||||||
i_IB=pads.rx_n,
|
i_IB=pads.rx_n,
|
||||||
o_O=serdes_m_i_nodelay,
|
o_O=serdes_i_nodelay
|
||||||
o_OB=serdes_s_i_nodelay
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
serdes_m_i_delayed = Signal()
|
serdes_i_delayed = Signal()
|
||||||
serdes_m_q = Signal(8)
|
serdes_q = Signal(8)
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("IDELAYE3",
|
Instance("IDELAYE3",
|
||||||
p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0,
|
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_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc,
|
||||||
i_CE=rx_delay_ce,
|
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",
|
Instance("ISERDESE3",
|
||||||
p_DATA_WIDTH=8,
|
p_DATA_WIDTH=8,
|
||||||
|
|
||||||
i_D=serdes_m_i_delayed,
|
i_D=serdes_i_delayed,
|
||||||
i_RST=ResetSignal("serdes"),
|
i_RST=ResetSignal("serdes"),
|
||||||
i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0,
|
i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0,
|
||||||
i_CLK=ClockSignal("serdes_20x"), i_CLK_B=~ClockSignal("serdes_20x"),
|
i_CLK=ClockSignal("serdes_20x"), i_CLK_B=~ClockSignal("serdes_20x"),
|
||||||
i_CLKDIV=ClockSignal("serdes_5x"),
|
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.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.value.eq(rx_bitslip_value),
|
||||||
self.rx_bitslip.i.eq(self.rx_gearbox.o),
|
self.rx_bitslip.i.eq(self.rx_gearbox.o),
|
||||||
self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),
|
self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),
|
||||||
|
@ -5,86 +5,6 @@ from migen.genlib.misc import WaitTimer
|
|||||||
from misoc.interconnect.csr import *
|
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:
|
# Master <--> Slave synchronization:
|
||||||
# 1) Master sends idle pattern (zeroes) to reset Slave.
|
# 1) Master sends idle pattern (zeroes) to reset Slave.
|
||||||
# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle pattern.
|
# 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 = 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 = bitslip = Signal(max=40)
|
||||||
self.bitslip_found = bitslip_found = Signal()
|
|
||||||
|
|
||||||
timer = WaitTimer(8192)
|
timer = WaitTimer(1024)
|
||||||
self.submodules += timer
|
self.submodules += timer
|
||||||
|
|
||||||
self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE"))
|
self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE"))
|
||||||
self.comb += self.fsm.reset.eq(self.reset)
|
self.comb += self.fsm.reset.eq(self.reset)
|
||||||
|
|
||||||
phase_detector_too_early_last = Signal()
|
|
||||||
|
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
NextValue(delay_found, 0),
|
|
||||||
NextValue(delay, 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),
|
serdes.rx_delay_rst.eq(1),
|
||||||
NextValue(bitslip_found, 0),
|
|
||||||
NextValue(bitslip, 0),
|
NextValue(bitslip, 0),
|
||||||
NextValue(phase_detector_too_early_last, 0),
|
|
||||||
NextState("RESET_SLAVE"),
|
NextState("RESET_SLAVE"),
|
||||||
serdes.tx_idle.eq(1)
|
serdes.tx_idle.eq(1)
|
||||||
)
|
)
|
||||||
@ -142,61 +63,75 @@ class SerdesMasterInit(Module):
|
|||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
timer.wait.eq(0),
|
timer.wait.eq(0),
|
||||||
serdes.phase_detector.reset.eq(1),
|
|
||||||
If(~delay_found,
|
|
||||||
NextState("CHECK_PHASE")
|
|
||||||
).Else(
|
|
||||||
NextState("CHECK_PATTERN")
|
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)
|
serdes.tx_comma.eq(1)
|
||||||
)
|
)
|
||||||
fsm.act("CHECK_PATTERN",
|
fsm.act("CHECK_PATTERN",
|
||||||
|
If(~delay_min_found,
|
||||||
If(serdes.rx_comma,
|
If(serdes.rx_comma,
|
||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
NextValue(bitslip_found, 1),
|
NextValue(delay_min, delay),
|
||||||
NextState("READY")
|
NextValue(delay_min_found, 1)
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
NextState("INC_BITSLIP")
|
NextState("INC_DELAY_BITSLIP")
|
||||||
|
),
|
||||||
|
).Else(
|
||||||
|
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)
|
serdes.tx_comma.eq(1)
|
||||||
)
|
)
|
||||||
self.comb += serdes.rx_bitslip_value.eq(bitslip)
|
self.comb += serdes.rx_bitslip_value.eq(bitslip)
|
||||||
fsm.act("INC_BITSLIP",
|
fsm.act("INC_DELAY_BITSLIP",
|
||||||
If(bitslip == (40 - 1),
|
NextState("WAIT_STABLE"),
|
||||||
|
If(delay == (taps - 1),
|
||||||
|
If(delay_min_found,
|
||||||
NextState("ERROR")
|
NextState("ERROR")
|
||||||
|
),
|
||||||
|
If(bitslip == (40 - 1),
|
||||||
|
NextValue(bitslip, 0)
|
||||||
).Else(
|
).Else(
|
||||||
NextValue(bitslip, bitslip + 1),
|
NextValue(bitslip, bitslip + 1)
|
||||||
NextState("WAIT_STABLE")
|
),
|
||||||
|
NextValue(delay, 0),
|
||||||
|
serdes.rx_delay_rst.eq(1)
|
||||||
|
).Else(
|
||||||
|
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)
|
serdes.tx_comma.eq(1)
|
||||||
)
|
)
|
||||||
@ -217,9 +152,11 @@ class SerdesSlaveInit(Module, AutoCSR):
|
|||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.delay = delay = Signal(max=taps)
|
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 = bitslip = Signal(max=40)
|
||||||
self.bitslip_found = bitslip_found = Signal()
|
|
||||||
|
|
||||||
timer = WaitTimer(1024)
|
timer = WaitTimer(1024)
|
||||||
self.submodules += timer
|
self.submodules += timer
|
||||||
@ -227,16 +164,14 @@ class SerdesSlaveInit(Module, AutoCSR):
|
|||||||
self.comb += self.reset.eq(serdes.rx_idle)
|
self.comb += self.reset.eq(serdes.rx_idle)
|
||||||
|
|
||||||
self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE"))
|
self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE"))
|
||||||
|
|
||||||
phase_detector_too_early_last = Signal()
|
|
||||||
|
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
NextValue(delay_found, 0),
|
|
||||||
NextValue(delay, 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),
|
serdes.rx_delay_rst.eq(1),
|
||||||
NextValue(bitslip_found, 0),
|
|
||||||
NextValue(bitslip, 0),
|
NextValue(bitslip, 0),
|
||||||
NextValue(phase_detector_too_early_last, 0),
|
|
||||||
NextState("WAIT_STABLE"),
|
NextState("WAIT_STABLE"),
|
||||||
serdes.tx_idle.eq(1)
|
serdes.tx_idle.eq(1)
|
||||||
)
|
)
|
||||||
@ -244,64 +179,76 @@ class SerdesSlaveInit(Module, AutoCSR):
|
|||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
timer.wait.eq(0),
|
timer.wait.eq(0),
|
||||||
serdes.phase_detector.reset.eq(1),
|
|
||||||
If(~delay_found,
|
|
||||||
NextState("CHECK_PHASE")
|
|
||||||
).Else(
|
|
||||||
NextState("CHECK_PATTERN")
|
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)
|
serdes.tx_idle.eq(1)
|
||||||
)
|
)
|
||||||
fsm.act("CHECK_PATTERN",
|
fsm.act("CHECK_PATTERN",
|
||||||
|
If(~delay_min_found,
|
||||||
If(serdes.rx_comma,
|
If(serdes.rx_comma,
|
||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
NextValue(bitslip_found, 1),
|
timer.wait.eq(0),
|
||||||
NextState("SEND_PATTERN")
|
NextValue(delay_min, delay),
|
||||||
|
NextValue(delay_min_found, 1)
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
NextState("INC_BITSLIP")
|
NextState("INC_DELAY_BITSLIP")
|
||||||
|
),
|
||||||
|
).Else(
|
||||||
|
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)
|
serdes.tx_idle.eq(1)
|
||||||
)
|
)
|
||||||
self.comb += serdes.rx_bitslip_value.eq(bitslip)
|
self.comb += serdes.rx_bitslip_value.eq(bitslip)
|
||||||
fsm.act("INC_BITSLIP",
|
fsm.act("INC_DELAY_BITSLIP",
|
||||||
If(bitslip == (40 - 1),
|
NextState("WAIT_STABLE"),
|
||||||
|
If(delay == (taps - 1),
|
||||||
|
If(delay_min_found,
|
||||||
NextState("ERROR")
|
NextState("ERROR")
|
||||||
|
),
|
||||||
|
If(bitslip == (40 - 1),
|
||||||
|
NextValue(bitslip, 0)
|
||||||
).Else(
|
).Else(
|
||||||
NextValue(bitslip, bitslip + 1),
|
NextValue(bitslip, bitslip + 1)
|
||||||
NextState("WAIT_STABLE")
|
),
|
||||||
|
NextValue(delay, 0),
|
||||||
|
serdes.rx_delay_rst.eq(1)
|
||||||
|
).Else(
|
||||||
|
NextValue(delay, delay + 1),
|
||||||
|
serdes.rx_delay_inc.eq(1),
|
||||||
|
serdes.rx_delay_ce.eq(1)
|
||||||
),
|
),
|
||||||
serdes.tx_idle.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",
|
fsm.act("SEND_PATTERN",
|
||||||
timer.wait.eq(1),
|
timer.wait.eq(1),
|
||||||
If(timer.done,
|
If(timer.done,
|
||||||
@ -327,9 +274,11 @@ class SerdesControl(Module, AutoCSR):
|
|||||||
self.error = CSRStatus()
|
self.error = CSRStatus()
|
||||||
|
|
||||||
self.delay = CSRStatus(9)
|
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 = CSRStatus(6)
|
||||||
self.bitslip_found = CSRStatus()
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
@ -338,8 +287,10 @@ class SerdesControl(Module, AutoCSR):
|
|||||||
self.comb += [
|
self.comb += [
|
||||||
self.ready.status.eq(init.ready),
|
self.ready.status.eq(init.ready),
|
||||||
self.error.status.eq(init.error),
|
self.error.status.eq(init.error),
|
||||||
self.delay_found.status.eq(init.delay_found),
|
|
||||||
self.delay.status.eq(init.delay),
|
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)
|
self.bitslip.status.eq(init.bitslip)
|
||||||
]
|
]
|
||||||
|
@ -5,8 +5,6 @@ from migen.genlib.misc import BitSlip
|
|||||||
|
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
from misoc.cores.code_8b10b import Encoder, Decoder
|
||||||
|
|
||||||
from artiq.gateware.serwb.phy import PhaseDetector
|
|
||||||
|
|
||||||
|
|
||||||
class S7SerdesPLL(Module):
|
class S7SerdesPLL(Module):
|
||||||
def __init__(self, refclk_freq, linerate, vco_div=1):
|
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_gearbox = Gearbox(8, "serdes_5x", 40, "serdes")
|
||||||
self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(40))
|
self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(40))
|
||||||
|
|
||||||
self.submodules.phase_detector = ClockDomainsRenamer("serdes_5x")(PhaseDetector())
|
serdes_i_nodelay = Signal()
|
||||||
|
|
||||||
# 2 serdes for phase detection: 1 master (used for data) / 1 slave
|
|
||||||
serdes_m_i_nodelay = Signal()
|
|
||||||
serdes_s_i_nodelay = Signal()
|
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("IBUFDS_DIFF_OUT",
|
Instance("IBUFDS_DIFF_OUT",
|
||||||
i_I=pads.rx_p,
|
i_I=pads.rx_p,
|
||||||
i_IB=pads.rx_n,
|
i_IB=pads.rx_n,
|
||||||
o_O=serdes_m_i_nodelay,
|
o_O=serdes_i_nodelay
|
||||||
o_OB=serdes_s_i_nodelay
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
serdes_m_i_delayed = Signal()
|
serdes_i_delayed = Signal()
|
||||||
serdes_m_q = Signal(8)
|
serdes_q = Signal(8)
|
||||||
self.specials += [
|
self.specials += [
|
||||||
Instance("IDELAYE2",
|
Instance("IDELAYE2",
|
||||||
p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA",
|
p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA",
|
||||||
@ -249,66 +242,28 @@ class S7Serdes(Module):
|
|||||||
i_CE=self.rx_delay_ce,
|
i_CE=self.rx_delay_ce,
|
||||||
i_LDPIPEEN=0, i_INC=self.rx_delay_inc,
|
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",
|
Instance("ISERDESE2",
|
||||||
p_DATA_WIDTH=8, p_DATA_RATE="DDR",
|
p_DATA_WIDTH=8, p_DATA_RATE="DDR",
|
||||||
p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING",
|
p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING",
|
||||||
p_NUM_CE=1, p_IOBDELAY="IFD",
|
p_NUM_CE=1, p_IOBDELAY="IFD",
|
||||||
|
|
||||||
i_DDLY=serdes_m_i_delayed,
|
i_DDLY=serdes_i_delayed,
|
||||||
i_CE1=1,
|
i_CE1=1,
|
||||||
i_RST=ResetSignal("serdes"),
|
i_RST=ResetSignal("serdes"),
|
||||||
i_CLK=ClockSignal("serdes_20x"), i_CLKB=~ClockSignal("serdes_20x"),
|
i_CLK=ClockSignal("serdes_20x"), i_CLKB=~ClockSignal("serdes_20x"),
|
||||||
i_CLKDIV=ClockSignal("serdes_5x"),
|
i_CLKDIV=ClockSignal("serdes_5x"),
|
||||||
i_BITSLIP=0,
|
i_BITSLIP=0,
|
||||||
o_Q8=serdes_m_q[0], o_Q7=serdes_m_q[1],
|
o_Q8=serdes_q[0], o_Q7=serdes_q[1],
|
||||||
o_Q6=serdes_m_q[2], o_Q5=serdes_m_q[3],
|
o_Q6=serdes_q[2], o_Q5=serdes_q[3],
|
||||||
o_Q4=serdes_m_q[4], o_Q3=serdes_m_q[5],
|
o_Q4=serdes_q[4], o_Q3=serdes_q[5],
|
||||||
o_Q2=serdes_m_q[6], o_Q1=serdes_m_q[7]
|
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.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.value.eq(rx_bitslip_value),
|
||||||
self.rx_bitslip.i.eq(self.rx_gearbox.o),
|
self.rx_bitslip.i.eq(self.rx_gearbox.o),
|
||||||
self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),
|
self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),
|
||||||
|
Loading…
Reference in New Issue
Block a user