forked from M-Labs/artiq-zynq
cxp downconn: add manual alignment & rxrestart
This commit is contained in:
parent
452c3cee64
commit
bf1fd2d79b
|
@ -13,7 +13,7 @@ from functools import reduce
|
||||||
class CXP_DownConn(Module, AutoCSR):
|
class CXP_DownConn(Module, AutoCSR):
|
||||||
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
|
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
self.rx_start_init = CSRStorage()
|
self.rx_start_init = CSRStorage()
|
||||||
self.rx_restart = CSRStorage()
|
self.rx_restart = CSR()
|
||||||
|
|
||||||
self.tx_start_init = CSRStorage()
|
self.tx_start_init = CSRStorage()
|
||||||
self.tx_restart = CSR()
|
self.tx_restart = CSR()
|
||||||
|
@ -54,7 +54,7 @@ class CXP_DownConn(Module, AutoCSR):
|
||||||
|
|
||||||
gtx.txenable.eq(self.txenable.storage[0]),
|
gtx.txenable.eq(self.txenable.storage[0]),
|
||||||
gtx.tx_restart.eq(self.tx_restart.re),
|
gtx.tx_restart.eq(self.tx_restart.re),
|
||||||
gtx.rx_restart.eq(self.rx_restart.storage),
|
gtx.rx_restart.eq(self.rx_restart.re),
|
||||||
gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage),
|
gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage),
|
||||||
gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage),
|
gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage),
|
||||||
# gtx.rx_alignment_en.eq(self.rx_data_alignment.storage),
|
# gtx.rx_alignment_en.eq(self.rx_data_alignment.storage),
|
||||||
|
@ -100,10 +100,10 @@ class CXP_DownConn(Module, AutoCSR):
|
||||||
Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx),
|
Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx),
|
||||||
|
|
||||||
# pmod 0-7 pin
|
# pmod 0-7 pin
|
||||||
Instance("OBUF", i_I=gtx.tx_init.gtXxreset, o_O=pmod_pads[0]),
|
Instance("OBUF", i_I=gtx.clk_aligner.rxslide, o_O=pmod_pads[0]),
|
||||||
Instance("OBUF", i_I=gtx.tx_init.Xxdlysreset, o_O=pmod_pads[1]),
|
Instance("OBUF", i_I=gtx.clk_aligner.ready, o_O=pmod_pads[1]),
|
||||||
Instance("OBUF", i_I=gtx.tx_init.Xxdlysresetdone , o_O=pmod_pads[2]),
|
# Instance("OBUF", i_I=gtx.tx_init.Xxdlysresetdone , o_O=pmod_pads[2]),
|
||||||
Instance("OBUF", i_I=gtx.tx_init.Xxphaligndone , o_O=pmod_pads[3]),
|
# Instance("OBUF", i_I=gtx.tx_init.Xxphaligndone , o_O=pmod_pads[3]),
|
||||||
# Instance("OBUF", i_I=, o_O=pmod_pads[4]),
|
# Instance("OBUF", i_I=, o_O=pmod_pads[4]),
|
||||||
# Instance("OBUF", i_I=, o_O=pmod_pads[5]),
|
# Instance("OBUF", i_I=, o_O=pmod_pads[5]),
|
||||||
# Instance("OBUF", i_I=, o_O=pmod_pads[6]),
|
# Instance("OBUF", i_I=, o_O=pmod_pads[6]),
|
||||||
|
@ -359,7 +359,76 @@ class CXP_BruteforceClockAligner(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped
|
||||||
|
# compared to the usual 8b10b binary representation.
|
||||||
|
class Manual_Aligner(Module):
|
||||||
|
def __init__(self, comma, check_cycles=20000):
|
||||||
|
|
||||||
|
self.rxslide = Signal()
|
||||||
|
self.rxdata = Signal(20)
|
||||||
|
|
||||||
|
self.ready = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
checks_reset = Signal()
|
||||||
|
error_seen = Signal()
|
||||||
|
comma_seen = Signal()
|
||||||
|
|
||||||
|
rx1cnt = Signal(max=11)
|
||||||
|
|
||||||
|
comma_n = ~comma & 0b1111111111
|
||||||
|
self.sync.cxp_gtx_rx += [
|
||||||
|
rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])),
|
||||||
|
If(checks_reset,
|
||||||
|
error_seen.eq(0)
|
||||||
|
).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6),
|
||||||
|
error_seen.eq(1)
|
||||||
|
),
|
||||||
|
If(checks_reset,
|
||||||
|
comma_seen.eq(0)
|
||||||
|
).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n),
|
||||||
|
comma_seen.eq(1)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# minimum of 32 RXUSRCLK2 cycles are required between two RXSLIDE pulses
|
||||||
|
slide_timer = ClockDomainsRenamer("cxp_gtx_rx")(WaitTimer(64))
|
||||||
|
self.submodules += slide_timer
|
||||||
|
counter = Signal(reset=check_cycles-1, max=check_cycles)
|
||||||
|
|
||||||
|
fsm = ClockDomainsRenamer("cxp_gtx_rx")(FSM(reset_state="IDLE"))
|
||||||
|
self.submodules += fsm
|
||||||
|
|
||||||
|
fsm.act("IDLE",
|
||||||
|
slide_timer.wait.eq(1),
|
||||||
|
If(slide_timer.done,
|
||||||
|
If(comma_seen,
|
||||||
|
NextState("READY"),
|
||||||
|
).Else(
|
||||||
|
NextState("SLIDING")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fsm.act("SLIDING",
|
||||||
|
self.rxslide.eq(1),
|
||||||
|
checks_reset.eq(1),
|
||||||
|
NextState("IDLE")
|
||||||
|
)
|
||||||
|
|
||||||
|
fsm.act("READY",
|
||||||
|
self.ready.eq(1),
|
||||||
|
If(counter == 0,
|
||||||
|
NextValue(counter, check_cycles - 1),
|
||||||
|
If(error_seen,
|
||||||
|
NextState("IDLE"),
|
||||||
|
)
|
||||||
|
).Else(
|
||||||
|
NextValue(counter, counter - 1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class GTX(Module):
|
class GTX(Module):
|
||||||
# Settings:
|
# Settings:
|
||||||
|
@ -399,10 +468,12 @@ class GTX(Module):
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# TX generates cxp_tx clock, init must be in system domain
|
# TX generates cxp_tx clock, init must be in system domain
|
||||||
# DEBUG: 500e6 is used to fix tx reset by holding gtxtxreset for a couple cycle more
|
# FIXME: 500e6 is used to fix Xx reset by holding gtxXxreset for a couple cycle more
|
||||||
self.submodules.tx_init = tx_init = GTXInit(500e6, False, mode=tx_mode)
|
self.submodules.tx_init = tx_init = GTXInit(500e6, False, mode=tx_mode)
|
||||||
|
self.submodules.rx_init = rx_init = GTXInit(500e6, True, mode=rx_mode)
|
||||||
|
|
||||||
# RX receives restart commands from txusrclk domain
|
# RX receives restart commands from txusrclk domain
|
||||||
self.submodules.rx_init = rx_init = ClockDomainsRenamer("cxp_gtx_tx")(GTXInit(qpll.tx_usrclk_freq, True, mode=rx_mode))
|
# self.submodules.rx_init = rx_init = ClockDomainsRenamer("cxp_gtx_tx")(GTXInit(500e6, True, mode=rx_mode))
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
tx_init.cplllock.eq(qpll.lock),
|
tx_init.cplllock.eq(qpll.lock),
|
||||||
|
@ -411,6 +482,8 @@ class GTX(Module):
|
||||||
|
|
||||||
txdata = Signal(20)
|
txdata = Signal(20)
|
||||||
rxdata = Signal(20)
|
rxdata = Signal(20)
|
||||||
|
|
||||||
|
rxslide = Signal()
|
||||||
# Note: the following parameters were set after consulting AR45360
|
# Note: the following parameters were set after consulting AR45360
|
||||||
self.specials += \
|
self.specials += \
|
||||||
Instance("GTXE2_CHANNEL",
|
Instance("GTXE2_CHANNEL",
|
||||||
|
@ -540,16 +613,22 @@ class GTX(Module):
|
||||||
# RX Byte and Word Alignment Attributes
|
# RX Byte and Word Alignment Attributes
|
||||||
p_ALIGN_COMMA_DOUBLE="FALSE",
|
p_ALIGN_COMMA_DOUBLE="FALSE",
|
||||||
p_ALIGN_COMMA_ENABLE=0b1111111111,
|
p_ALIGN_COMMA_ENABLE=0b1111111111,
|
||||||
p_ALIGN_COMMA_WORD=1,
|
p_ALIGN_COMMA_WORD=2,
|
||||||
p_ALIGN_MCOMMA_DET="TRUE",
|
p_ALIGN_MCOMMA_DET="FALSE",
|
||||||
p_ALIGN_MCOMMA_VALUE=0b1010000011,
|
p_ALIGN_MCOMMA_VALUE=0b1010000011,
|
||||||
p_ALIGN_PCOMMA_DET="TRUE",
|
p_ALIGN_PCOMMA_DET="FALSE",
|
||||||
p_ALIGN_PCOMMA_VALUE=0b0101111100,
|
p_ALIGN_PCOMMA_VALUE=0b0101111100,
|
||||||
p_SHOW_REALIGN_COMMA="FALSE",
|
p_SHOW_REALIGN_COMMA="FALSE",
|
||||||
p_RXSLIDE_AUTO_WAIT=7,
|
p_RXSLIDE_AUTO_WAIT=7,
|
||||||
p_RXSLIDE_MODE="PCS",
|
p_RXSLIDE_MODE="PCS",
|
||||||
p_RX_SIG_VALID_DLY=10,
|
p_RX_SIG_VALID_DLY=10,
|
||||||
|
|
||||||
|
# Manual Word Alignment
|
||||||
|
i_RXPCOMMAALIGNEN=0,
|
||||||
|
i_RXMCOMMAALIGNEN=0,
|
||||||
|
i_RXCOMMADETEN=1, # enable word alignment, but breaks rxrestart if gtxXxreset hold too short
|
||||||
|
i_RXSLIDE=rxslide,
|
||||||
|
|
||||||
# RX 8B/10B Decoder Attributes
|
# RX 8B/10B Decoder Attributes
|
||||||
p_RX_DISPERR_SEQ_MATCH="FALSE",
|
p_RX_DISPERR_SEQ_MATCH="FALSE",
|
||||||
p_DEC_MCOMMA_DETECT="TRUE",
|
p_DEC_MCOMMA_DETECT="TRUE",
|
||||||
|
@ -678,11 +757,21 @@ class GTX(Module):
|
||||||
# 125MHz: align <1s
|
# 125MHz: align <1s
|
||||||
# 156.25MHz: align <15s
|
# 156.25MHz: align <15s
|
||||||
# 250MHz: cannot align
|
# 250MHz: cannot align
|
||||||
clock_aligner = CXP_BruteforceClockAligner(0b0101111100, 800_000)
|
# clock_aligner = CXP_BruteforceClockAligner(0b0101111100, 1_000_000)
|
||||||
self.submodules += clock_aligner
|
# self.submodules += clock_aligner
|
||||||
|
# self.comb += [
|
||||||
|
# clock_aligner.rxdata.eq(rxdata),
|
||||||
|
# rx_init.restart.eq(clock_aligner.restart),
|
||||||
|
# self.rx_ready.eq(clock_aligner.ready),
|
||||||
|
# ]
|
||||||
|
|
||||||
|
self.submodules.clk_aligner = clk_aligner = Manual_Aligner(0b0101111100)
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
clock_aligner.rxdata.eq(rxdata),
|
clk_aligner.rxdata.eq(rxdata),
|
||||||
rx_init.restart.eq(clock_aligner.restart),
|
rxslide.eq(clk_aligner.rxslide),
|
||||||
self.rx_ready.eq(clock_aligner.ready),
|
self.rx_ready.eq(clk_aligner.ready),
|
||||||
tx_init.restart.eq(self.tx_restart)
|
|
||||||
|
rx_init.restart.eq(self.rx_restart),
|
||||||
|
tx_init.restart.eq(self.tx_restart),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue