forked from M-Labs/artiq-zynq
cxp: add upconn, downconn & crc
cxp: add crc32 for cxp cxp: add upconn & downconn
This commit is contained in:
parent
1f033d605c
commit
82af01350f
|
@ -0,0 +1,185 @@
|
||||||
|
from migen import *
|
||||||
|
from misoc.interconnect.csr import *
|
||||||
|
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
|
||||||
|
|
||||||
|
from artiq.gateware.drtio.core import ChannelInterface
|
||||||
|
|
||||||
|
from cxp_downconn import CXP_DownConn
|
||||||
|
from cxp_upconn import CXP_UpConn
|
||||||
|
|
||||||
|
class CXP(Module, AutoCSR):
|
||||||
|
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
|
nchannels = len(pads)
|
||||||
|
self.rx_start_init = CSRStorage()
|
||||||
|
self.rx_restart = CSRStatus()
|
||||||
|
self.rx_bypass_clk_alignment = CSRStorage()
|
||||||
|
|
||||||
|
self.tx_start_init = CSRStorage()
|
||||||
|
self.tx_restart = CSRStorage()
|
||||||
|
|
||||||
|
self.loopback_mode = CSRStorage(3)
|
||||||
|
|
||||||
|
self.txinit_phaligndone = CSRStatus()
|
||||||
|
self.rxinit_phaligndone = CSRStatus()
|
||||||
|
self.rx_ready = CSRStatus()
|
||||||
|
|
||||||
|
self.data_0 = CSRStorage(8)
|
||||||
|
self.data_1 = CSRStorage(8)
|
||||||
|
self.control_bit_0 = CSRStorage()
|
||||||
|
self.control_bit_1 = CSRStorage()
|
||||||
|
self.encoded_0 = CSRStatus(10)
|
||||||
|
self.encoded_1 = CSRStatus(10)
|
||||||
|
|
||||||
|
self.rxdata_0 = CSRStatus(10)
|
||||||
|
self.rxdata_1 = CSRStatus(10)
|
||||||
|
self.decoded_data_0 = CSRStatus(8)
|
||||||
|
self.decoded_data_1 = CSRStatus(8)
|
||||||
|
self.decoded_k_0 = CSRStatus()
|
||||||
|
self.decoded_k_1 = CSRStatus()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
self.submodules.crc = CXP_CRC(8)
|
||||||
|
|
||||||
|
# FIFOs with transmission priority
|
||||||
|
# 0: Trigger packet
|
||||||
|
# 1: IO acknowledgment for trigger packet
|
||||||
|
# 2: All other packets
|
||||||
|
|
||||||
|
self.submodules.upconn = CXP_UpConn(debug_sma, sys_clk_freq, pmod_pads)
|
||||||
|
|
||||||
|
|
||||||
|
# single & master tx_mode can lock with rx in loopback
|
||||||
|
self.submodules.gtx = gtx = CXP_DownConn(refclk, pads, sys_clk_freq, tx_mode="single", rx_mode="single")
|
||||||
|
|
||||||
|
# DEBUG:loopback
|
||||||
|
self.sync += gtx.loopback_mode.eq(self.loopback_mode.storage)
|
||||||
|
|
||||||
|
# # ! debug sma
|
||||||
|
# self.specials += [
|
||||||
|
# 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)
|
||||||
|
# ]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
self.txinit_phaligndone.status.eq(self.gtx.tx_init.Xxphaligndone),
|
||||||
|
self.rxinit_phaligndone.status.eq(self.gtx.rx_init.Xxphaligndone),
|
||||||
|
self.rx_ready.status.eq(self.gtx.rx_ready),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.sync.cxp_gtx_tx += [
|
||||||
|
self.gtx.encoder.d[0].eq(self.data_0.storage),
|
||||||
|
self.gtx.encoder.k[0].eq(self.control_bit_0.storage),
|
||||||
|
self.encoded_0.status.eq(self.gtx.encoder.output[0]),
|
||||||
|
|
||||||
|
self.gtx.encoder.d[1].eq(self.data_1.storage),
|
||||||
|
self.gtx.encoder.k[1].eq(self.control_bit_1.storage),
|
||||||
|
self.encoded_1.status.eq(self.gtx.encoder.output[1]),
|
||||||
|
]
|
||||||
|
self.sync.cxp_gtx_rx += [
|
||||||
|
self.rxdata_0.status.eq(self.gtx.decoders[0].input),
|
||||||
|
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.decoded_data_1.status.eq(self.gtx.decoders[1].d),
|
||||||
|
self.decoded_k_1.status.eq(self.gtx.decoders[1].k),
|
||||||
|
]
|
||||||
|
|
||||||
|
# TODO: rip encoder & rx clockalignment out of CXP_GTX
|
||||||
|
|
||||||
|
# TODO: use expose encoder & decoder from CXP
|
||||||
|
# encoder.k = 1 if sending control bit, different calculation
|
||||||
|
# encoder.d = data 8 bit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
channel_interface = ChannelInterface(gtx.encoder, gtx.decoders)
|
||||||
|
self.comb += channel_interface.rx_ready.eq(gtx.rx_ready)
|
||||||
|
channel_interfaces = []
|
||||||
|
channel_interfaces.append(channel_interface)
|
||||||
|
|
||||||
|
# TransceiverInterface, just adding cxp_rx_<num>
|
||||||
|
self.stable_clkin = CSRStorage()
|
||||||
|
self.txenable = CSRStorage(len(channel_interfaces))
|
||||||
|
for i in range(len(channel_interfaces)):
|
||||||
|
name = "cxp_gtx_rx" + str(i)
|
||||||
|
setattr(self.clock_domains, "cd_"+name, ClockDomain(name=name))
|
||||||
|
self.channels = channel_interfaces
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: add tx_phase_alignment for multi CXP
|
||||||
|
# The TX phase alignment will fail with a wrong TXUSRCLK frequency
|
||||||
|
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
gtx.rx_init.clk_path_ready.eq(self.rx_start_init.storage),
|
||||||
|
|
||||||
|
gtx.tx_init.clk_path_ready.eq(self.tx_start_init.storage),
|
||||||
|
gtx.txenable.eq(self.txenable.storage[0]),
|
||||||
|
gtx.tx_restart.eq(self.tx_restart.storage),
|
||||||
|
]
|
||||||
|
|
||||||
|
# TODO: Connect multilane cxp_tx
|
||||||
|
|
||||||
|
# TODO: Connect slave i's `cxp_gtx_rx` clock to `cxp_gtx_rxi` clock
|
||||||
|
self.comb += [
|
||||||
|
getattr(self, "cd_cxp_gtx_rx" + str(0)).clk.eq(self.gtx.cd_cxp_gtx_rx.clk),
|
||||||
|
getattr(self, "cd_cxp_gtx_rx" + str(0)).rst.eq(self.gtx.cd_cxp_gtx_rx.rst)
|
||||||
|
]
|
||||||
|
|
||||||
|
class CXP_CRC(Module, AutoCSR):
|
||||||
|
width = 32
|
||||||
|
polynom = 0x04C11DB7
|
||||||
|
seed = 2**width-1
|
||||||
|
def __init__(self, data_width):
|
||||||
|
self.d = Signal(data_width)
|
||||||
|
self.stb = Signal()
|
||||||
|
self.reset = Signal()
|
||||||
|
self.val = Signal(self.width, reset=self.seed)
|
||||||
|
|
||||||
|
self.data = CSR(data_width)
|
||||||
|
self.en = CSR()
|
||||||
|
self.value = CSRStatus(self.width)
|
||||||
|
self.processed = CSRStatus(self.width)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom)
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
self.val.eq(self.engine.next),
|
||||||
|
If(self.stb,
|
||||||
|
self.engine.data.eq(self.d),
|
||||||
|
|
||||||
|
If(self.reset,
|
||||||
|
self.engine.last.eq(self.seed),
|
||||||
|
# clear reset bit
|
||||||
|
self.reset.eq(0),
|
||||||
|
).Else(
|
||||||
|
self.engine.last.eq(self.val),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# DEBUG: remove those csr
|
||||||
|
# TODO: do char bit reverse outside of this submodule
|
||||||
|
|
||||||
|
p0 = Signal(8)
|
||||||
|
p1 = Signal(8)
|
||||||
|
p2 = Signal(8)
|
||||||
|
p3 = Signal(8)
|
||||||
|
self.comb += [
|
||||||
|
p3.eq(self.engine.next[:8][::-1]),
|
||||||
|
p2.eq(self.engine.next[8:16][::-1]),
|
||||||
|
p1.eq(self.engine.next[16:24][::-1]),
|
||||||
|
p0.eq(self.engine.next[24:32][::-1]),
|
||||||
|
]
|
||||||
|
self.sync += [
|
||||||
|
self.d.eq(self.data.r),
|
||||||
|
self.stb.eq(self.data.re),
|
||||||
|
If(self.en.re, self.reset.eq(1)),
|
||||||
|
|
||||||
|
self.value.status.eq(self.engine.next),
|
||||||
|
self.processed.status.eq(Cat(p3, p2, p1, p0)),
|
||||||
|
]
|
Loading…
Reference in New Issue