1
0
Fork 0

cxp downconn: use 40bits

This commit is contained in:
morgan 2024-08-14 16:48:36 +08:00
parent 17277504f1
commit 49d5cad5fd
1 changed files with 233 additions and 133 deletions

View File

@ -1,6 +1,5 @@
from migen import * from migen import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.cdc import MultiReg, PulseSynchronizer
from migen.genlib.misc import WaitTimer
from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer
from misoc.cores.code_8b10b import Encoder, Decoder from misoc.cores.code_8b10b import Encoder, Decoder
@ -155,43 +154,20 @@ class CXP_DownConn(Module, AutoCSR):
self.loopback_mode = CSRStorage(3) self.loopback_mode = CSRStorage(3)
self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage) self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage)
# DEBUG: RXDATA checking
aligned = Signal()
valid_data = Signal()
rx1cnt = Signal(max=11)
comma = 0b0101111100
comma_n = ~comma & 0b1111111111
self.sync.cxp_gtx_rx += [
If(self.gtx.comma_det.check_ps.o,
aligned.eq(0),
).Elif((gtx.comma_det.data[:10] == comma) | (gtx.comma_det.data[:10] == comma_n),
aligned.eq(1),
),
rx1cnt.eq(reduce(add, [gtx.comma_det.data[i] for i in range(10)])),
If(self.gtx.comma_det.check_ps.o,
valid_data.eq(0)
).Elif((rx1cnt == 4) | (rx1cnt == 5) | (rx1cnt == 6),
valid_data.eq(1)
),
]
# DEBUG: IO SMA & PMOD # DEBUG: IO SMA & PMOD
self.specials += [ self.specials += [
Instance("OBUF", i_I=gtx.rxoutclk, o_O=debug_sma.p_tx), Instance("OBUF", i_I=gtx.rxoutclk, o_O=debug_sma.p_tx),
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.comma_det.aligner_en_rxclk, o_O=pmod_pads[0]), Instance("OBUF", i_I=gtx.comma_det.rxinit_done, o_O=pmod_pads[0]),
Instance("OBUF", i_I=gtx.comma_det.rxinit_done, o_O=pmod_pads[1]), Instance("OBUF", i_I=gtx.comma_det.restart, o_O=pmod_pads[1]),
Instance("OBUF", i_I=gtx.comma_det.restart, o_O=pmod_pads[2]), Instance("OBUF", i_I=gtx.comma_det.aligner_en_rxclk, o_O=pmod_pads[2]),
Instance("OBUF", i_I=aligned, o_O=pmod_pads[3]), Instance("OBUF", i_I=gtx.comma_det.check_reset, o_O=pmod_pads[3]),
Instance("OBUF", i_I=gtx.comma_det.ready, o_O=pmod_pads[4]), Instance("OBUF", i_I=gtx.comma_det.comma_aligned, o_O=pmod_pads[4]),
Instance("OBUF", i_I=gtx.comma_det.check_ps.o, o_O=pmod_pads[5]), Instance("OBUF", i_I=gtx.comma_det.comma_seen, o_O=pmod_pads[5]),
Instance("OBUF", i_I=valid_data, o_O=pmod_pads[6]), Instance("OBUF", i_I=gtx.comma_det.has_error, o_O=pmod_pads[6]),
# Instance("OBUF", i_I=, o_O=pmod_pads[7]), Instance("OBUF", i_I=gtx.comma_det.ready, o_O=pmod_pads[7]),
# Instance("OBUF", i_I=gtx.dclk, o_O=pmod_pads[0]), # Instance("OBUF", i_I=gtx.dclk, o_O=pmod_pads[0]),
# Instance("OBUF", i_I=gtx.den, o_O=pmod_pads[1]), # Instance("OBUF", i_I=gtx.den, o_O=pmod_pads[1]),
@ -200,8 +176,6 @@ class CXP_DownConn(Module, AutoCSR):
] ]
# DEBUG: datain # DEBUG: datain
counter_max = 2
counter = Signal(max=counter_max)
self.data_0 = CSRStorage(8) self.data_0 = CSRStorage(8)
self.data_1 = CSRStorage(8) self.data_1 = CSRStorage(8)
@ -222,31 +196,34 @@ class CXP_DownConn(Module, AutoCSR):
self.decoded_k_1 = CSRStatus() self.decoded_k_1 = CSRStatus()
self.sync.cxp_gtx_tx += [ self.sync.cxp_gtx_tx += [
If(counter == 0, self.gtx.encoder.d[0].eq(0xBC),
self.gtx.encoder.d[0].eq(self.data_0.storage), self.gtx.encoder.k[0].eq(1),
self.gtx.encoder.k[0].eq(self.control_bit_0.storage), self.gtx.encoder.d[1].eq(0x3C),
self.gtx.encoder.d[1].eq(self.data_1.storage), self.gtx.encoder.k[1].eq(1),
self.gtx.encoder.k[1].eq(self.control_bit_1.storage), self.gtx.encoder.d[2].eq(0x3C),
counter.eq(counter+1), self.gtx.encoder.k[2].eq(1),
).Elif(counter == 1, self.gtx.encoder.d[3].eq(0xB5),
self.gtx.encoder.d[0].eq(self.data_2.storage), self.gtx.encoder.k[3].eq(0),
self.gtx.encoder.k[0].eq(self.control_bit_2.storage),
self.gtx.encoder.d[1].eq(self.data_3.storage),
self.gtx.encoder.k[1].eq(self.control_bit_3.storage),
counter.eq(0),
),
self.encoded_0.status.eq(self.gtx.encoder.output[0]), self.encoded_0.status.eq(self.gtx.encoder.output[0]),
self.encoded_1.status.eq(self.gtx.encoder.output[1]), self.encoded_1.status.eq(self.gtx.encoder.output[1]),
] ]
# keep it odd, so it will show data[n] where n is odd
stb_timer = Signal(reset=10, max=11)
self.sync.cxp_gtx_rx += [ self.sync.cxp_gtx_rx += [
self.rxdata_0.status.eq(self.gtx.decoders[0].input), If(stb_timer == 0,
self.decoded_data_0.status.eq(self.gtx.decoders[0].d), self.rxdata_0.status.eq(self.gtx.decoders[0].input),
self.decoded_k_0.status.eq(self.gtx.decoders[0].k), self.decoded_data_0.status.eq(self.gtx.decoders[0].d),
self.decoded_k_0.status.eq(self.gtx.decoders[0].k),
self.rxdata_1.status.eq(self.gtx.decoders[1].input), self.rxdata_1.status.eq(self.gtx.decoders[1].input),
self.decoded_data_1.status.eq(self.gtx.decoders[1].d), self.decoded_data_1.status.eq(self.gtx.decoders[1].d),
self.decoded_k_1.status.eq(self.gtx.decoders[1].k), self.decoded_k_1.status.eq(self.gtx.decoders[1].k),
stb_timer.eq(stb_timer.reset),
).Else(
stb_timer.eq(stb_timer - 1),
)
] ]
@ -295,7 +272,7 @@ class QPLL(Module):
# refclk_div = 2 # refclk_div = 2
# self.Xxout_div = 2 # self.Xxout_div = 2
self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/20 self.tx_usrclk_freq = (sys_clk_freq*fbdiv_real/self.Xxout_div)/40
self.specials += [ self.specials += [
Instance("GTXE2_COMMON", Instance("GTXE2_COMMON",
@ -352,7 +329,7 @@ class QPLL(Module):
# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped # Warning: Xilinx transceivers are LSB first, and comma needs to be flipped
# compared to the usual 8b10b binary representation. # compared to the usual 8b10b binary representation.
class Comma_Detector(Module): class Comma_Detector(Module):
def __init__(self, comma, check_period=150_000): def __init__(self, comma, check_period=1_000_000):
self.data = Signal(20) self.data = Signal(20)
self.rxinit_done = Signal() self.rxinit_done = Signal()
@ -368,85 +345,205 @@ class Comma_Detector(Module):
# - UG476 (v1.12.1) p.228 # - UG476 (v1.12.1) p.228
# The validity of data & comma are checked externally # The validity of data & comma are checked externally
aligned = Signal() # aligned = Signal()
valid_data = Signal() # valid_data = Signal()
aligned_rxclk = Signal() # aligned_rxclk = Signal()
valid_data_rxclk = Signal() # valid_data_rxclk = Signal()
rx1cnt = Signal(max=11) # rx1cnt = Signal(max=11)
self.specials += [ # self.specials += [
MultiReg(aligned_rxclk, aligned), # MultiReg(aligned_rxclk, aligned),
MultiReg(valid_data_rxclk, valid_data), # MultiReg(valid_data_rxclk, valid_data),
] # ]
self.submodules.check_ps = check_ps = PulseSynchronizer("sys", "cxp_gtx_rx") # self.submodules.check_reset = check_reset = PulseSynchronizer("sys", "cxp_gtx_rx")
comma_n = ~comma & 0b1111111111 # comma_n = ~comma & 0b1111111111
self.sync.cxp_gtx_rx += [ # self.sync.cxp_gtx_rx += [
If(check_ps.o, # If(check_reset.o,
aligned_rxclk.eq(0), # aligned_rxclk.eq(0),
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n), # ).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
aligned_rxclk.eq(1), # aligned_rxclk.eq(1),
), # ),
rx1cnt.eq(reduce(add, [self.data[i] for i in range(10)])), # rx1cnt.eq(reduce(add, [self.data[i] for i in range(10)])),
If(check_ps.o, # If(check_reset.o,
valid_data_rxclk.eq(0), # valid_data_rxclk.eq(0),
).Elif((rx1cnt == 4) | (rx1cnt == 5) | (rx1cnt == 6), # ).Elif((rx1cnt == 4) | (rx1cnt == 5) | (rx1cnt == 6),
valid_data_rxclk.eq(1), # valid_data_rxclk.eq(1),
), # ),
] # ]
# self.aligned = Signal()
# self.valid_data = Signal()
# self.comb +=[
# self.aligned.eq(aligned),
# self.valid_data.eq(valid_data)
# ]
check_counter = Signal(reset=check_period-1, max=check_period) check_counter = Signal(reset=check_period-1, max=check_period)
check = Signal() # check = Signal()
self.sync += [ self.sync += [
check.eq(0), self.restart.eq(0),
If(check_counter == 0, # check.eq(0),
check_counter.eq(check_counter.reset), # check_reset.i.eq(0),
check.eq(1), If(~self.ready,
).Else( If(check_counter == 0,
check_counter.eq(check_counter - 1), check_counter.eq(check_counter.reset),
# check.eq(1),
self.restart.eq(1),
# check_reset.i.eq(1),
).Else(
check_counter.eq(check_counter - 1),
)
) )
] ]
self.submodules.fsm = fsm = FSM(reset_state="WAIT_COMMA_ALIGN") # WIP:
aligner_en = Signal() comma_n = ~comma & 0b1111111111
self.specials += MultiReg(aligner_en, self.aligner_en_rxclk, odomain="cxp_gtx_rx")
fsm.act("WAIT_COMMA_ALIGN", has_error = Signal()
aligner_en.eq(1), comma_aligned = Signal()
comma_seen = Signal()
error_seen = Signal()
one_counts = Signal(max=11)
counter_period = 5000
counter = Signal(reset=counter_period-1, max=counter_period)
check_reset = Signal()
check = Signal()
self.sync.cxp_gtx_rx += [
check.eq(0),
If(counter == 0,
counter.eq(counter.reset),
check.eq(1),
).Else(
counter.eq(counter - 1),
),
has_error.eq(0),
one_counts.eq(reduce(add, [self.data[i] for i in range(10, 20)])),
If((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
has_error.eq(1)
),
comma_aligned.eq(0),
If((self.data[:10] == comma) | (self.data[:10] == comma_n),
comma_aligned.eq(1)
),
# signal that need to be manually cleared
If(check_reset,
comma_seen.eq(0),
).Elif((self.data[:10] == comma) | (self.data[:10] == comma_n),
comma_seen.eq(1)
),
one_counts.eq(reduce(add, [self.data[i] for i in range(10, 20)])),
If(check_reset,
error_seen.eq(0),
).Elif((one_counts != 4) & (one_counts != 5) & (one_counts != 6),
error_seen.eq(1),
),
]
# DEBUG: expose signal
self.check_reset = Signal()
self.comma_aligned = Signal()
self.comma_seen = Signal()
self.has_error = Signal()
self.error_seen = Signal()
self.comb +=[
self.check_reset.eq(check_reset),
self.comma_aligned.eq(comma_aligned),
self.comma_seen.eq(comma_seen),
self.has_error.eq(has_error),
self.error_seen.eq(error_seen),
]
self.submodules.rxfsm = rxfsm = ClockDomainsRenamer("cxp_gtx_rx")(FSM(reset_state="ALIGNING"))
rxfsm.act("ALIGNING",
self.aligner_en_rxclk.eq(1),
If(comma_aligned & (~has_error),
check_reset.eq(1),
NextState("DOUBLE_CHECK"),
)
)
rxfsm.act("DOUBLE_CHECK",
If(check, If(check,
check_ps.i.eq(1), check_reset.eq(1),
If(aligned, If(~error_seen,
NextState("WAIT_VALID_DATA"), NextState("READY"),
).Else( ).Else(
self.restart.eq(1), NextState("ALIGNING")
) )
) )
) )
fsm.act("WAIT_VALID_DATA", ready = Signal()
aligner_en.eq(1), self.specials += MultiReg(ready, self.ready)
rxfsm.act("READY",
ready.eq(1),
If(check, If(check,
check_ps.i.eq(1), check_reset.eq(1),
If(aligned & valid_data, If(~comma_seen,
NextState("READY"), NextState("ALIGNING"),
).Else(
self.restart.eq(1),
NextState("WAIT_COMMA_ALIGN"),
) )
) )
) )
fsm.act("READY",
self.ready.eq(1), # self.submodules.fsm = fsm = FSM(reset_state="WAIT_RXINIT")
If(check,
check_ps.i.eq(1), # aligner_en = Signal()
If(~(aligned & valid_data), # self.specials += MultiReg(aligner_en, self.aligner_en_rxclk, odomain="cxp_gtx_rx")
self.restart.eq(1),
NextState("WAIT_COMMA_ALIGN"), # fsm.act("WAIT_RXINIT",
) # If(self.rxinit_done,
) # NextState("WAIT_COMMA_ALIGN"),
) # )
# )
# fsm.act("WAIT_COMMA_ALIGN",
# aligner_en.eq(1),
# If(check,
# check_reset.i.eq(1),
# If(aligned,
# NextState("WAIT_VALID_DATA"),
# ).Else(
# self.restart.eq(1),
# NextState("WAIT_RXINIT")
# )
# )
# )
# fsm.act("WAIT_VALID_DATA",
# aligner_en.eq(1),
# If(check,
# check_reset.i.eq(1),
# If(aligned & valid_data,
# NextState("READY"),
# ).Else(
# self.restart.eq(1),
# NextState("WAIT_RXINIT"),
# )
# )
# )
# fsm.act("READY",
# self.ready.eq(1),
# If(check,
# check_reset.i.eq(1),
# If(~(aligned & valid_data),
# self.restart.eq(1),
# NextState("WAIT_RXINIT"),
# )
# )
# )
@ -463,7 +560,7 @@ class GTX(Module):
# linerate = USRCLK * datawidth # linerate = USRCLK * datawidth
pll_fbout_mult = 8 pll_fbout_mult = 8
txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq # 20 is datawidth txusr_pll_div = pll_fbout_mult*sys_clk_freq/qpll.tx_usrclk_freq
self.tx_restart = Signal() self.tx_restart = Signal()
self.rx_restart = Signal() self.rx_restart = Signal()
@ -484,9 +581,9 @@ class GTX(Module):
self.dout = Signal(16) self.dout = Signal(16)
self.dready = Signal() self.dready = Signal()
self.submodules.encoder = ClockDomainsRenamer("cxp_gtx_tx")(Encoder(2, True)) self.submodules.encoder = ClockDomainsRenamer("cxp_gtx_tx")(Encoder(4, True))
self.submodules.decoders = [ClockDomainsRenamer("cxp_gtx_rx")( self.submodules.decoders = [ClockDomainsRenamer("cxp_gtx_rx")(
(Decoder(True))) for _ in range(2)] (Decoder(True))) for _ in range(4)]
# transceiver direct clock outputs # transceiver direct clock outputs
@ -509,8 +606,8 @@ class GTX(Module):
rx_init.cplllock.eq(qpll.lock) rx_init.cplllock.eq(qpll.lock)
] ]
txdata = Signal(20) txdata = Signal(40)
rxdata = Signal(20) rxdata = Signal(40)
comma_aligner_en = Signal() comma_aligner_en = Signal()
# Note: the following parameters were set after consulting AR45360 # Note: the following parameters were set after consulting AR45360
@ -570,11 +667,11 @@ class GTX(Module):
i_TXINHIBIT=~self.txenable, i_TXINHIBIT=~self.txenable,
# TX data # TX data
p_TX_DATA_WIDTH=20, p_TX_DATA_WIDTH=40,
p_TX_INT_DATAWIDTH=0, p_TX_INT_DATAWIDTH=1,
i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), i_TXCHARDISPMODE=Cat(txdata[9], txdata[19], txdata[29], txdata[39]),
i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18], txdata[28], txdata[38]),
i_TXDATA=Cat(txdata[:8], txdata[10:18]), i_TXDATA=Cat(txdata[:8], txdata[10:18], txdata[20:28], txdata[30:38]),
i_TXUSRCLK=ClockSignal("cxp_gtx_tx"), i_TXUSRCLK=ClockSignal("cxp_gtx_tx"),
i_TXUSRCLK2=ClockSignal("cxp_gtx_tx"), i_TXUSRCLK2=ClockSignal("cxp_gtx_tx"),
@ -633,27 +730,28 @@ class GTX(Module):
p_CLK_COR_SEQ_2_ENABLE=0b1111, p_CLK_COR_SEQ_2_ENABLE=0b1111,
# RX data # RX data
p_RX_DATA_WIDTH=20, p_RX_DATA_WIDTH=40,
p_RX_INT_DATAWIDTH=0, p_RX_INT_DATAWIDTH=1,
o_RXDISPERR=Cat(rxdata[9], rxdata[19]), o_RXDISPERR=Cat(rxdata[9], rxdata[19], rxdata[29], rxdata[39]),
o_RXCHARISK=Cat(rxdata[8], rxdata[18]), o_RXCHARISK=Cat(rxdata[8], rxdata[18], rxdata[28], rxdata[38]),
o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), o_RXDATA=Cat(rxdata[:8], rxdata[10:18], rxdata[20:28], rxdata[30:38]),
# 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=2, # align comma to rxdata[:10] only p_ALIGN_COMMA_WORD=4, # align comma to rxdata[:10] only
p_ALIGN_MCOMMA_DET="TRUE", p_ALIGN_MCOMMA_DET="TRUE",
p_ALIGN_MCOMMA_VALUE=0b1010000011, p_ALIGN_MCOMMA_VALUE=0b1010000011,
p_ALIGN_PCOMMA_DET="TRUE", p_ALIGN_PCOMMA_DET="TRUE",
p_ALIGN_PCOMMA_VALUE=0b0101111100, p_ALIGN_PCOMMA_VALUE=0b0101111100,
p_SHOW_REALIGN_COMMA="FALSE", p_SHOW_REALIGN_COMMA="TRUE",
p_RXSLIDE_AUTO_WAIT=7, p_RXSLIDE_AUTO_WAIT=7,
p_RXSLIDE_MODE="OFF", p_RXSLIDE_MODE="OFF",
p_RX_SIG_VALID_DLY=10, p_RX_SIG_VALID_DLY=10,
i_RXPCOMMAALIGNEN=comma_aligner_en, i_RXPCOMMAALIGNEN=comma_aligner_en,
i_RXMCOMMAALIGNEN=comma_aligner_en, i_RXMCOMMAALIGNEN=comma_aligner_en,
i_RXCOMMADETEN=1, i_RXCOMMADETEN=1,
i_RXSLIDE=0,
# RX 8B/10B Decoder Attributes # RX 8B/10B Decoder Attributes
p_RX_DISPERR_SEQ_MATCH="FALSE", p_RX_DISPERR_SEQ_MATCH="FALSE",
@ -758,7 +856,7 @@ class GTX(Module):
p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=pll_fbout_mult, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk, i_CLKFBIN=txpll_fb_clk, o_CLKFBOUT=txpll_fb_clk,
# frequency = linerate/20 # frequency = linerate/40
p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout, p_CLKOUT0_DIVIDE=txusr_pll_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=txpll_clkout,
# Dynamic Reconfiguration Ports # Dynamic Reconfiguration Ports
@ -784,9 +882,11 @@ class GTX(Module):
] ]
self.comb += [ self.comb += [
txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])), txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1], self.encoder.output[2], self.encoder.output[3])),
self.decoders[0].input.eq(rxdata[:10]), self.decoders[0].input.eq(rxdata[:10]),
self.decoders[1].input.eq(rxdata[10:]) self.decoders[1].input.eq(rxdata[10:20]),
self.decoders[2].input.eq(rxdata[20:30]),
self.decoders[3].input.eq(rxdata[30:]),
] ]