1
0
Fork 0

cxp upconn: clenaup & add 41.66Mbps

This commit is contained in:
morgan 2024-08-28 16:52:48 +08:00
parent f5eb196726
commit 08cade7f16
1 changed files with 87 additions and 307 deletions

View File

@ -1,42 +1,58 @@
from math import ceil from math import ceil
from migen import * from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.coding import PriorityEncoder from migen.genlib.coding import PriorityEncoder
from misoc.cores.code_8b10b import SingleEncoder from misoc.cores.code_8b10b import SingleEncoder
from misoc.interconnect import stream from misoc.interconnect import stream
from misoc.interconnect.csr import * from misoc.interconnect.csr import *
class CXP_UpConn_ClockGen(Module): IDLE_CHARS = Array([
#[char, k]
[0xBC, 1], #K28.5
[0x3C, 1], #K28.1
[0x3C, 1], #K28.1
[0xB5, 0], #D21.5
])
class UpConn_ClockGen(Module):
def __init__(self, sys_clk_freq): def __init__(self, sys_clk_freq):
self.clk = Signal() self.clk = Signal()
self.clk_10x = Signal() # 20.83MHz 48ns self.clk_10x = Signal() # 20.83MHz 48ns or 41.66MHz 24ns
# self.clk2x = Signal() # 41.66MHz 24ns
self.freq2x_enable = Signal()
# # # # # #
period = 1e9/sys_clk_freq period = 1e9/sys_clk_freq
max_count = ceil(48/period) max_count = ceil(48/period)
counter = Signal(max=max_count, reset=max_count-1) counter = Signal(max=max_count, reset=max_count-1)
divided = Signal(max=10, reset=9) clk_div = Signal(max=10, reset=9)
self.sync += [ self.sync += [
self.clk_10x.eq(0),
self.clk.eq(0), self.clk.eq(0),
self.clk_10x.eq(0),
If(counter == 0, If(counter == 0,
counter.eq(counter.reset),
self.clk_10x.eq(1), self.clk_10x.eq(1),
If(divided == 0, If(self.freq2x_enable,
self.clk.eq(1), counter.eq(int(max_count/2)-1),
divided.eq(divided.reset),
).Else( ).Else(
divided.eq(divided-1) counter.eq(counter.reset),
) ),
).Else( ).Else(
counter.eq(counter-1), counter.eq(counter-1),
),
If(counter == 0,
If(clk_div == 0,
self.clk.eq(1),
clk_div.eq(clk_div.reset),
).Else(
clk_div.eq(clk_div-1),
)
) )
] ]
class SERDES_10bits(Module): class SERDES_10bits(Module):
@ -58,6 +74,7 @@ class SERDES_10bits(Module):
self.sync += [ self.sync += [
If(self.oe, If(self.oe,
# send LSB first
o.eq(tx_reg[0]), o.eq(tx_reg[0]),
tx_reg.eq(Cat(tx_reg[1:], 0)), tx_reg.eq(Cat(tx_reg[1:], 0)),
tx_bitcount.eq(tx_bitcount + 1), tx_bitcount.eq(tx_bitcount + 1),
@ -72,8 +89,8 @@ class SERDES_10bits(Module):
) )
] ]
class Priority_8b10b_Machine(Module): class Transmission_Scheduler(Module):
def __init__(self, tx_fifos, nfifos): def __init__(self, tx_fifos):
self.tx_enable = Signal() self.tx_enable = Signal()
self.oe = Signal() self.oe = Signal()
@ -83,19 +100,11 @@ class Priority_8b10b_Machine(Module):
self.submodules.startup_fsm = startup_fsm = FSM(reset_state="WAIT_TX_ENABLE") self.submodules.startup_fsm = startup_fsm = FSM(reset_state="WAIT_TX_ENABLE")
self.submodules.encoder = encoder = SingleEncoder(True) self.submodules.encoder = encoder = SingleEncoder(True)
IDLE_CHARS = Array([
#[char, k]
[0xBC, 1], #K28.5
[0x3C, 1], #K28.1
[0x3C, 1], #K28.1
[0xB5, 0], #D21.5
])
tx_charcount = Signal(max=4) tx_charcount = Signal(max=4)
tx_wordcount = Signal(max=10000) tx_wordcount = Signal(max=10000)
idling = Signal() idling = Signal()
priorities = Signal(max=nfifos) priorities = Signal.like(tx_fifos.pe.o)
# DEBUG: # DEBUG:
self.idling = Signal() self.idling = Signal()
@ -168,258 +177,6 @@ class Priority_8b10b_Machine(Module):
) )
] ]
class CXP_with_CE(Module):
def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, fifo_depth, nfifos=3):
self.bitrate2x_enable = Signal()
self.tx_enable = Signal()
# # #
self.submodules.cg = cg = CXP_UpConn_ClockGen(sys_clk_freq)
self.submodules.tx_fifos = tx_fifos = TxFIFOs(nfifos, fifo_depth)
# TODO: rename machine plz
self.submodules.machine = machine = CEInserter()(Priority_8b10b_Machine(tx_fifos, nfifos))
self.submodules.serdes = serdes = CEInserter()(SERDES_10bits(pad))
self.comb += [
machine.ce.eq(cg.clk),
machine.tx_enable.eq(self.tx_enable),
serdes.ce.eq(cg.clk_10x),
serdes.d.eq(machine.encoder.output),
serdes.oe.eq(machine.oe),
]
# DEBUG: remove pads
prioity_0 = Signal()
word_bound = Signal()
p0 = Signal()
p3 = Signal()
self.comb += [
prioity_0.eq((~tx_fifos.pe.n) & (tx_fifos.pe.o == 0)),
word_bound.eq(machine.tx_charcount == 3),
# because of clk delay
p0.eq(machine.tx_charcount == 2),
p3.eq(machine.tx_charcount == 1),
]
self.specials += [
# # debug sma
Instance("OBUF", i_I=cg.clk, o_O=debug_sma.p_tx),
Instance("OBUF", i_I=cg.clk_10x, o_O=debug_sma.n_rx),
# # pmod 0-7 pin
Instance("OBUF", i_I=serdes.o, o_O=pmod_pads[0]),
Instance("OBUF", i_I=cg.clk_10x, o_O=pmod_pads[1]),
Instance("OBUF", i_I=~tx_fifos.pe.n, o_O=pmod_pads[2]),
Instance("OBUF", i_I=prioity_0, o_O=pmod_pads[3]),
Instance("OBUF", i_I=word_bound, o_O=pmod_pads[4]),
Instance("OBUF", i_I=machine.idling, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=tx_fifos.source_ack[0], o_O=pmod[6]),
# Instance("OBUF", i_I=tx_fifos.source_ack[2], o_O=pmod[6]),
# Instance("OBUF", i_I=tx_fifos.source_ack[1], o_O=pmod[7]),
Instance("OBUF", i_I=p0, o_O=pmod_pads[6]),
Instance("OBUF", i_I=p3, o_O=pmod_pads[7]),
]
class CXP_UpConn(Module, AutoCSR):
def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, fifo_depth, nfifos=3):
self.clock_domains.cd_cxp_upconn = ClockDomain()
self.clk_reset = Signal()
self.bitrate2x_enable = Signal()
self.tx_enable = Signal()
# # #
pll_locked = Signal()
pll_fb_clk = Signal()
pll_cxpclk = Signal()
pll_cxpclk2x = Signal()
self.specials += [
Instance("PLLE2_ADV",
p_BANDWIDTH="HIGH",
o_LOCKED=pll_locked,
i_RST=ResetSignal("sys"),
p_CLKIN1_PERIOD=1e9/sys_clk_freq, # ns
i_CLKIN1=ClockSignal("sys"),
# VCO @ 1.25GHz
p_CLKFBOUT_MULT=1.25e9/sys_clk_freq, p_DIVCLK_DIVIDE=1,
i_CLKFBIN=pll_fb_clk, o_CLKFBOUT=pll_fb_clk,
# 20.83MHz (48ns)
p_CLKOUT0_DIVIDE=60, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_cxpclk,
# 41.66MHz (24ns) for downconnection over 6.25Gpbs
p_CLKOUT1_DIVIDE=30, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_cxpclk2x,
),
Instance("BUFGMUX",
i_I0=pll_cxpclk,
i_I1=pll_cxpclk2x,
i_S=self.bitrate2x_enable,
o_O=self.cd_cxp_upconn.clk
),
AsyncResetSynchronizer(self.cd_cxp_upconn, ~pll_locked | self.clk_reset)
]
self.submodules.startup_fsm = startup_fsm = ClockDomainsRenamer("cxp_upconn")(FSM(reset_state="WAIT_TX_ENABLE"))
self.submodules.encoder = encoder = ClockDomainsRenamer("cxp_upconn")(SingleEncoder(True))
self.submodules.tx_fifos = tx_fifos = TxFIFOs(nfifos, fifo_depth)
self.submodules.tx_idle = tx_idle = TxIdle()
o = Signal()
self.specials += Instance("OBUF", i_I=o, o_O=pad),
tx_en = Signal()
tx_bitcount = Signal(max=10)
tx_charcount = Signal(max=4)
tx_wordcount = Signal(max=10000)
tx_reg = Signal(10)
priorities = Signal(max=nfifos)
idling = Signal()
startup_fsm.act("WAIT_TX_ENABLE",
If(self.tx_enable,
NextValue(tx_idle.word_idx, 0),
NextState("ENCODE_CHAR")
)
)
startup_fsm.act("ENCODE_CHAR",
NextValue(tx_idle.source_ack, 1),
NextValue(encoder.d, tx_idle.source_data),
NextValue(encoder.k, tx_idle.source_k),
NextState("LOAD_CHAR"),
)
startup_fsm.act("LOAD_CHAR",
NextValue(idling, 1),
NextValue(tx_charcount, 0),
NextValue(tx_bitcount, 0),
NextValue(tx_reg, encoder.output),
NextValue(encoder.disp_in, encoder.disp_out),
NextState("START_TX")
)
startup_fsm.act("START_TX",
tx_en.eq(1),
If((~self.tx_enable) & (tx_charcount == 3),
NextState("WAIT_TX_ENABLE")
)
)
# OSERDESE2 is not used as PLLE2 can't output the required 2.083MHz (480ns) for the CLKDIV
self.sync.cxp_upconn += [
If(tx_en,
o.eq(tx_reg[0]),
tx_reg.eq(Cat(tx_reg[1:], 0)),
tx_bitcount.eq(tx_bitcount + 1),
If(tx_bitcount == 9,
tx_bitcount.eq(0),
tx_reg.eq(encoder.output),
encoder.disp_in.eq(encoder.disp_out),
),
# packet insertion and idle word
If(tx_bitcount == 9,
# Section 9.2.4 (CXP-001-2021)
# trigger packets should be inserted at char boundary
If((~tx_fifos.pe.n) & (tx_fifos.pe.o == 0),
# trigger packets are inserted at char boundary and don't contribute to word count
tx_fifos.source_ack[0].eq(1),
encoder.d.eq(tx_fifos.source_data[0]),
encoder.k.eq(tx_fifos.source_k[0]),
).Else(
If(tx_charcount == 3,
tx_charcount.eq(0),
# Section 9.2.4 (CXP-001-2021)
# other priorities packets are inserted at word boundary
If((~tx_fifos.pe.n) & (tx_wordcount != 9999),
idling.eq(0),
priorities.eq(tx_fifos.pe.o),
tx_wordcount.eq(tx_wordcount + 1),
tx_fifos.source_ack[tx_fifos.pe.o].eq(1),
encoder.d.eq(tx_fifos.source_data[tx_fifos.pe.o]),
encoder.k.eq(tx_fifos.source_k[tx_fifos.pe.o]),
).Else(
# Section 9.2.5.1 (CXP-001-2021)
# IDLE word shall be transmitted at least once every 10,000 words, but should not be inserted into trigger packet
idling.eq(1),
tx_wordcount.eq(0),
tx_idle.source_ack.eq(1),
encoder.d.eq(tx_idle.source_data),
encoder.k.eq(tx_idle.source_k),
)
).Else(
tx_charcount.eq(tx_charcount + 1),
If(~idling,
tx_fifos.source_ack[priorities].eq(1),
encoder.d.eq(tx_fifos.source_data[priorities]),
encoder.k.eq(tx_fifos.source_k[priorities]),
).Else(
tx_idle.source_ack.eq(1),
encoder.d.eq(tx_idle.source_data),
encoder.k.eq(tx_idle.source_k),
)
),
)
)
).Else(
o.eq(0)
)
]
# DEBUG: remove pads
self.encoded_data = CSRStatus(10)
self.sync.cxp_upconn +=[
If(tx_bitcount == 0,
self.encoded_data.status.eq(tx_reg),
)
]
prioity_0 = Signal()
word_bound = Signal()
p0 = Signal()
p3 = Signal()
self.comb += [
prioity_0.eq((~tx_fifos.pe.n) & (tx_fifos.pe.o == 0)),
word_bound.eq(tx_charcount == 3),
p0.eq(tx_idle.word_idx == 0),
p3.eq(tx_idle.word_idx == 3),
]
self.specials += [
# # debug sma
Instance("OBUF", i_I=o, o_O=debug_sma.p_tx),
Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=debug_sma.n_rx),
# # pmod 0-7 pin
Instance("OBUF", i_I=o, o_O=pmod_pads[0]),
Instance("OBUF", i_I=self.cd_cxp_upconn.clk, o_O=pmod_pads[1]),
Instance("OBUF", i_I=~tx_fifos.pe.n, o_O=pmod_pads[2]),
Instance("OBUF", i_I=prioity_0, o_O=pmod_pads[3]),
Instance("OBUF", i_I=word_bound, o_O=pmod_pads[4]),
Instance("OBUF", i_I=idling, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=tx_fifos.source_ack[0], o_O=pmod[6]),
# Instance("OBUF", i_I=tx_fifos.source_ack[2], o_O=pmod[6]),
# Instance("OBUF", i_I=tx_fifos.source_ack[1], o_O=pmod[7]),
Instance("OBUF", i_I=p0, o_O=pmod_pads[6]),
Instance("OBUF", i_I=p3, o_O=pmod_pads[7]),
]
class TxFIFOs(Module): class TxFIFOs(Module):
def __init__(self, nfifos, fifo_depth): def __init__(self, nfifos, fifo_depth):
@ -434,11 +191,9 @@ class TxFIFOs(Module):
# # # # # #
non_empty = Signal(nfifos) not_empty_reg = Signal(nfifos)
for i in range(nfifos): for i in range(nfifos):
# cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"})
# fifo = cdr(stream.AsyncFIFO([("data", 8), ("k", 1)], fifo_depth))
fifo = stream.SyncFIFO([("data", 8), ("k", 1)], fifo_depth) fifo = stream.SyncFIFO([("data", 8), ("k", 1)], fifo_depth)
setattr(self.submodules, "tx_fifo" + str(i), fifo) setattr(self.submodules, "tx_fifo" + str(i), fifo)
@ -459,45 +214,70 @@ class TxFIFOs(Module):
fifo.source.ack.eq(0), fifo.source.ack.eq(0),
), ),
non_empty[i].eq(fifo.source.stb), not_empty_reg[i].eq(fifo.source.stb),
self.source_data[i].eq(fifo.source.data), self.source_data[i].eq(fifo.source.data),
self.source_k[i].eq(fifo.source.k), self.source_k[i].eq(fifo.source.k),
] ]
# FIFOs transmission priority # FIFOs transmission priority
self.submodules.pe = PriorityEncoder(nfifos) self.submodules.pe = PriorityEncoder(nfifos)
self.comb += self.pe.i.eq(non_empty) self.comb += self.pe.i.eq(not_empty_reg)
class TxIdle(Module): class CXP_UpConn(Module):
def __init__(self): def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, fifo_depth, nfifos=3):
self.source_ack = Signal() self.bitrate2x_enable = Signal()
self.source_data = Signal(8) self.tx_enable = Signal()
self.source_k = Signal()
self.word_idx = Signal(max=4)
# # # # # #
# section 9.2.5 (CXP-001-2021) self.submodules.cg = cg = UpConn_ClockGen(sys_clk_freq)
IDLE_CHARS = Array([ self.submodules.tx_fifos = tx_fifos = TxFIFOs(nfifos, fifo_depth)
#[char, k]
[0b10111100, 1], #K28.5
[0b00111100, 1], #K28.1
[0b00111100, 1], #K28.1
[0b10111100, 0], #D28.5
])
self.sync += [ self.submodules.scheduler = scheduler = CEInserter()(Transmission_Scheduler(tx_fifos))
self.source_data.eq(IDLE_CHARS[self.word_idx][0]), self.submodules.serdes = serdes = CEInserter()(SERDES_10bits(pad))
self.source_k.eq(IDLE_CHARS[self.word_idx][1]),
If(self.source_ack, self.comb += [
# reset after asserted cg.freq2x_enable.eq(self.bitrate2x_enable),
self.source_ack.eq(0),
If(self.word_idx != 3, scheduler.ce.eq(cg.clk),
self.word_idx.eq(self.word_idx + 1), scheduler.tx_enable.eq(self.tx_enable),
).Else(
self.word_idx.eq(self.word_idx.reset), serdes.ce.eq(cg.clk_10x),
) serdes.d.eq(scheduler.encoder.output),
), serdes.oe.eq(scheduler.oe),
] ]
# DEBUG: remove pads
prioity_0 = Signal()
word_bound = Signal()
p0 = Signal()
p3 = Signal()
self.comb += [
prioity_0.eq((~tx_fifos.pe.n) & (tx_fifos.pe.o == 0)),
word_bound.eq(scheduler.tx_charcount == 3),
# because of clk delay
p0.eq(scheduler.tx_charcount == 2),
p3.eq(scheduler.tx_charcount == 1),
]
self.specials += [
# # debug sma
Instance("OBUF", i_I=cg.clk, o_O=debug_sma.p_tx),
Instance("OBUF", i_I=cg.clk_10x, o_O=debug_sma.n_rx),
# # pmod 0-7 pin
Instance("OBUF", i_I=serdes.o, o_O=pmod_pads[0]),
Instance("OBUF", i_I=cg.clk_10x, o_O=pmod_pads[1]),
Instance("OBUF", i_I=~tx_fifos.pe.n, o_O=pmod_pads[2]),
Instance("OBUF", i_I=prioity_0, o_O=pmod_pads[3]),
Instance("OBUF", i_I=word_bound, o_O=pmod_pads[4]),
Instance("OBUF", i_I=scheduler.idling, o_O=pmod_pads[5]),
# Instance("OBUF", i_I=tx_fifos.source_ack[0], o_O=pmod[6]),
# Instance("OBUF", i_I=tx_fifos.source_ack[2], o_O=pmod[6]),
# Instance("OBUF", i_I=tx_fifos.source_ack[1], o_O=pmod[7]),
Instance("OBUF", i_I=p0, o_O=pmod_pads[6]),
Instance("OBUF", i_I=p3, o_O=pmod_pads[7]),
]