forked from M-Labs/artiq-zynq
cxp upconn: rewrite oserdes using CEInserter
IDLE word: fix p3 to D21.5 CLKGEN: missing 24ns
This commit is contained in:
parent
4170e63a6e
commit
d55bd81137
|
@ -1,3 +1,5 @@
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
from migen.genlib.coding import PriorityEncoder
|
from migen.genlib.coding import PriorityEncoder
|
||||||
|
@ -6,6 +8,224 @@ 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):
|
||||||
|
def __init__(self, sys_clk_freq):
|
||||||
|
self.clk = Signal()
|
||||||
|
self.clk_10x = Signal() # 20.83MHz 48ns
|
||||||
|
# self.clk2x = Signal() # 41.66MHz 24ns
|
||||||
|
# # #
|
||||||
|
|
||||||
|
period = 1e9/sys_clk_freq
|
||||||
|
max_count = ceil(48/period)
|
||||||
|
counter = Signal(max=max_count, reset=max_count-1)
|
||||||
|
|
||||||
|
divided = Signal(max=10, reset=9)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
self.clk_10x.eq(0),
|
||||||
|
self.clk.eq(0),
|
||||||
|
|
||||||
|
If(counter == 0,
|
||||||
|
counter.eq(counter.reset),
|
||||||
|
self.clk_10x.eq(1),
|
||||||
|
If(divided == 0,
|
||||||
|
self.clk.eq(1),
|
||||||
|
divided.eq(divided.reset),
|
||||||
|
).Else(
|
||||||
|
divided.eq(divided-1)
|
||||||
|
)
|
||||||
|
).Else(
|
||||||
|
counter.eq(counter-1),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
class SERDES_10bits(Module):
|
||||||
|
def __init__(self, pad):
|
||||||
|
self.oe = Signal()
|
||||||
|
self.d = Signal(10)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
o = Signal()
|
||||||
|
tx_bitcount = Signal(max=10)
|
||||||
|
tx_reg = Signal(10)
|
||||||
|
|
||||||
|
# DEBUG:
|
||||||
|
self.o = Signal()
|
||||||
|
self.comb += self.o.eq(o)
|
||||||
|
|
||||||
|
self.specials += Instance("OBUF", i_I=o, o_O=pad),
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(self.oe,
|
||||||
|
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(self.d),
|
||||||
|
),
|
||||||
|
).Else(
|
||||||
|
o.eq(0),
|
||||||
|
tx_bitcount.eq(0),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
class Priority_8b10b_Machine(Module):
|
||||||
|
def __init__(self, tx_fifos, nfifos):
|
||||||
|
self.tx_enable = Signal()
|
||||||
|
|
||||||
|
self.oe = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
self.submodules.startup_fsm = startup_fsm = FSM(reset_state="WAIT_TX_ENABLE")
|
||||||
|
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_wordcount = Signal(max=10000)
|
||||||
|
|
||||||
|
idling = Signal()
|
||||||
|
priorities = Signal(max=nfifos)
|
||||||
|
|
||||||
|
# DEBUG:
|
||||||
|
self.idling = Signal()
|
||||||
|
self.tx_charcount = Signal(max=4)
|
||||||
|
self.comb += [
|
||||||
|
self.idling.eq(idling),
|
||||||
|
self.tx_charcount.eq(tx_charcount),
|
||||||
|
]
|
||||||
|
|
||||||
|
startup_fsm.act("WAIT_TX_ENABLE",
|
||||||
|
If(self.tx_enable,
|
||||||
|
NextValue(idling, 1),
|
||||||
|
NextValue(tx_charcount, 0),
|
||||||
|
NextValue(encoder.d, IDLE_CHARS[0][0]),
|
||||||
|
NextValue(encoder.k, IDLE_CHARS[0][1]),
|
||||||
|
NextState("START_TX"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
startup_fsm.act("START_TX",
|
||||||
|
self.oe.eq(1),
|
||||||
|
If((~self.tx_enable) & (tx_charcount == 3),
|
||||||
|
NextState("WAIT_TX_ENABLE")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(self.oe,
|
||||||
|
encoder.disp_in.eq(encoder.disp_out),
|
||||||
|
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),
|
||||||
|
|
||||||
|
encoder.d.eq(IDLE_CHARS[0][0]),
|
||||||
|
encoder.k.eq(IDLE_CHARS[0][1]),
|
||||||
|
)
|
||||||
|
).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(
|
||||||
|
encoder.d.eq(IDLE_CHARS[tx_charcount + 1][0]),
|
||||||
|
encoder.k.eq(IDLE_CHARS[tx_charcount + 1][1]),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
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):
|
class CXP_UpConn(Module, AutoCSR):
|
||||||
def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, fifo_depth, nfifos=3):
|
def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, fifo_depth, nfifos=3):
|
||||||
|
@ -217,8 +437,10 @@ class TxFIFOs(Module):
|
||||||
non_empty = Signal(nfifos)
|
non_empty = Signal(nfifos)
|
||||||
|
|
||||||
for i in range(nfifos):
|
for i in range(nfifos):
|
||||||
cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"})
|
# cdr = ClockDomainsRenamer({"write": "sys", "read": "cxp_upconn"})
|
||||||
fifo = cdr(stream.AsyncFIFO([("data", 8), ("k", 1)], fifo_depth))
|
# fifo = cdr(stream.AsyncFIFO([("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)
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
|
@ -228,7 +450,7 @@ class TxFIFOs(Module):
|
||||||
fifo.sink.k.eq(self.sink_k[i]),
|
fifo.sink.k.eq(self.sink_k[i]),
|
||||||
]
|
]
|
||||||
|
|
||||||
self.sync.cxp_upconn += [
|
self.sync += [
|
||||||
If(self.source_ack[i],
|
If(self.source_ack[i],
|
||||||
# reset ack after asserted
|
# reset ack after asserted
|
||||||
self.source_ack[i].eq(0),
|
self.source_ack[i].eq(0),
|
||||||
|
@ -264,7 +486,7 @@ class TxIdle(Module):
|
||||||
[0b10111100, 0], #D28.5
|
[0b10111100, 0], #D28.5
|
||||||
])
|
])
|
||||||
|
|
||||||
self.sync.cxp_upconn += [
|
self.sync += [
|
||||||
self.source_data.eq(IDLE_CHARS[self.word_idx][0]),
|
self.source_data.eq(IDLE_CHARS[self.word_idx][0]),
|
||||||
self.source_k.eq(IDLE_CHARS[self.word_idx][1]),
|
self.source_k.eq(IDLE_CHARS[self.word_idx][1]),
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue