forked from M-Labs/artiq-zynq
Compare commits
8 Commits
6134ad5794
...
6c53447808
Author | SHA1 | Date |
---|---|---|
morgan | 6c53447808 | |
morgan | 14aa81c8a2 | |
morgan | 82af01350f | |
morgan | 1f033d605c | |
morgan | 7d5e3c1ef9 | |
morgan | 95ec9b1253 | |
morgan | abd9157065 | |
morgan | 1a05dd6ac4 |
|
@ -341,7 +341,7 @@
|
||||||
{
|
{
|
||||||
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
inherit fastnumbers artiq-netboot ramda migen-axi binutils-arm;
|
||||||
} //
|
} //
|
||||||
(board-package-set { target = "zc706"; variant = "cxp_fmc"; }) //
|
(board-package-set { target = "zc706"; variant = "cxp_demo"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
(board-package-set { target = "zc706"; variant = "nist_clock"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
(board-package-set { target = "zc706"; variant = "nist_clock_master"; }) //
|
||||||
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
(board-package-set { target = "zc706"; variant = "nist_clock_master_100mhz"; }) //
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
from migen import *
|
from migen import *
|
||||||
|
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
|
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
|
||||||
|
|
||||||
from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface
|
from artiq.gateware.drtio.core import ChannelInterface
|
||||||
|
|
||||||
from cxp_downconn import CXP_DownConn
|
from cxp_downconn import CXP_DownConn
|
||||||
|
from cxp_upconn import CXP_UpConn
|
||||||
|
|
||||||
class CXP(Module, AutoCSR):
|
class CXP(Module, AutoCSR):
|
||||||
def __init__(self, refclk, pads, sys_clk_freq, debug_sma):
|
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
self.nchannels = nchannels = len(pads)
|
nchannels = len(pads)
|
||||||
self.rx_start_init = CSRStorage()
|
self.rx_start_init = CSRStorage()
|
||||||
self.rx_restart = CSRStatus()
|
self.rx_restart = CSRStatus()
|
||||||
self.rx_bypass_clk_alignment = CSRStorage()
|
self.rx_bypass_clk_alignment = CSRStorage()
|
||||||
|
@ -19,6 +20,7 @@ class CXP(Module, AutoCSR):
|
||||||
self.loopback_mode = CSRStorage(3)
|
self.loopback_mode = CSRStorage(3)
|
||||||
|
|
||||||
self.txinit_phaligndone = CSRStatus()
|
self.txinit_phaligndone = CSRStatus()
|
||||||
|
self.rxinit_phaligndone = CSRStatus()
|
||||||
self.rx_ready = CSRStatus()
|
self.rx_ready = CSRStatus()
|
||||||
|
|
||||||
self.data_0 = CSRStorage(8)
|
self.data_0 = CSRStorage(8)
|
||||||
|
@ -37,20 +39,31 @@ class CXP(Module, AutoCSR):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# single CXP
|
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")
|
self.submodules.gtx = gtx = CXP_DownConn(refclk, pads, sys_clk_freq, tx_mode="single", rx_mode="single")
|
||||||
|
|
||||||
# ! loopback for debugging
|
# DEBUG:loopback
|
||||||
self.sync += gtx.loopback_mode.eq(self.loopback_mode.storage)
|
self.sync += gtx.loopback_mode.eq(self.loopback_mode.storage)
|
||||||
|
|
||||||
# ! debug sma
|
# # ! debug sma
|
||||||
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)
|
||||||
]
|
# ]
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.txinit_phaligndone.status.eq(self.gtx.tx_init.Xxphaligndone),
|
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.rx_ready.status.eq(self.gtx.rx_ready),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -115,4 +128,58 @@ class CXP(Module, AutoCSR):
|
||||||
getattr(self, "cd_cxp_gtx_rx" + str(0)).rst.eq(self.gtx.cd_cxp_gtx_rx.rst)
|
getattr(self, "cd_cxp_gtx_rx" + str(0)).rst.eq(self.gtx.cd_cxp_gtx_rx.rst)
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: add low speed SERDES
|
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)),
|
||||||
|
]
|
||||||
|
|
|
@ -5,7 +5,6 @@ from migen.genlib.cdc import MultiReg, PulseSynchronizer
|
||||||
from misoc.cores.code_8b10b import Encoder, Decoder
|
from misoc.cores.code_8b10b import Encoder, Decoder
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
|
|
||||||
from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface
|
|
||||||
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
|
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
|
||||||
|
|
||||||
from operator import add
|
from operator import add
|
||||||
|
@ -29,13 +28,13 @@ from functools import reduce
|
||||||
# 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 CXP_BruteforceClockAligner(Module):
|
class CXP_BruteforceClockAligner(Module):
|
||||||
def __init__(self, comma, tx_clk_freq, check_period=6e-3):
|
def __init__(self, comma, sys_clk_freq, check_period):
|
||||||
self.rxdata = Signal(20)
|
self.rxdata = Signal(20)
|
||||||
self.restart = Signal()
|
self.restart = Signal()
|
||||||
|
|
||||||
self.ready = Signal()
|
self.ready = Signal()
|
||||||
|
|
||||||
check_max_val = ceil(check_period*tx_clk_freq)
|
check_max_val = ceil(check_period*sys_clk_freq)
|
||||||
check_counter = Signal(max=check_max_val+1)
|
check_counter = Signal(max=check_max_val+1)
|
||||||
check = Signal()
|
check = Signal()
|
||||||
reset_check_counter = Signal()
|
reset_check_counter = Signal()
|
||||||
|
@ -135,7 +134,6 @@ class CXP_DownConn(Module):
|
||||||
pll_div = int(40/cpll_div)
|
pll_div = int(40/cpll_div)
|
||||||
|
|
||||||
self.rx_restart = Signal()
|
self.rx_restart = Signal()
|
||||||
self.rx_bypass_clk_alignment = Signal()
|
|
||||||
self.tx_restart = Signal()
|
self.tx_restart = Signal()
|
||||||
self.loopback_mode = Signal(3)
|
self.loopback_mode = Signal(3)
|
||||||
|
|
||||||
|
@ -417,7 +415,8 @@ class CXP_DownConn(Module):
|
||||||
self.decoders[1].input.eq(rxdata[10:])
|
self.decoders[1].input.eq(rxdata[10:])
|
||||||
]
|
]
|
||||||
|
|
||||||
clock_aligner = CXP_BruteforceClockAligner(0b0101111100, sys_clk_freq, check_period=1e-3)
|
# 6e-3 is too slow for 3.25Gbps line rate
|
||||||
|
clock_aligner = CXP_BruteforceClockAligner(0b0101111100, sys_clk_freq, check_period=1e-2)
|
||||||
self.submodules += clock_aligner
|
self.submodules += clock_aligner
|
||||||
self.comb += [
|
self.comb += [
|
||||||
clock_aligner.rxdata.eq(rxdata),
|
clock_aligner.rxdata.eq(rxdata),
|
||||||
|
|
|
@ -8,7 +8,8 @@ from misoc.interconnect.csr import *
|
||||||
|
|
||||||
|
|
||||||
class CXP_UpConn(Module, AutoCSR):
|
class CXP_UpConn(Module, AutoCSR):
|
||||||
def __init__(self, pads, sys_clk_freq, pmod, nfifos=3, fifo_depth=32):
|
nfifos = 3
|
||||||
|
def __init__(self, pads, sys_clk_freq, pmod, fifo_depth=32):
|
||||||
self.clock_domains.cd_cxp_upconn = ClockDomain()
|
self.clock_domains.cd_cxp_upconn = ClockDomain()
|
||||||
self.clk_reset = CSRStorage(reset=1)
|
self.clk_reset = CSRStorage(reset=1)
|
||||||
self.bitrate2x_enable = CSRStorage()
|
self.bitrate2x_enable = CSRStorage()
|
||||||
|
@ -50,26 +51,23 @@ class CXP_UpConn(Module, AutoCSR):
|
||||||
]
|
]
|
||||||
|
|
||||||
self.submodules.fsm = ClockDomainsRenamer("cxp_upconn")(FSM(reset_state="WAIT_TX_ENABLE"))
|
self.submodules.fsm = ClockDomainsRenamer("cxp_upconn")(FSM(reset_state="WAIT_TX_ENABLE"))
|
||||||
self.submodules.tx_fifos = TxFIFOs(nfifos, fifo_depth)
|
self.submodules.tx_fifos = TxFIFOs(self.nfifos, fifo_depth)
|
||||||
self.submodules.tx_idle = TxIdle()
|
self.submodules.tx_idle = TxIdle()
|
||||||
|
|
||||||
o = Signal()
|
o = Signal()
|
||||||
tx_en = Signal()
|
tx_en = Signal()
|
||||||
tx_bitcount = Signal(max=10)
|
tx_bitcount = Signal(max=10)
|
||||||
tx_wordcount = Signal()
|
tx_wordcount = Signal(max=4)
|
||||||
tx_reg = Signal(10)
|
tx_reg = Signal(10)
|
||||||
|
|
||||||
disp = Signal()
|
disp = Signal()
|
||||||
tx_wordcount = Signal(max=4)
|
priorities = Signal(max=self.nfifos)
|
||||||
priority = Signal(max=nfifos)
|
|
||||||
idling = Signal()
|
idling = Signal()
|
||||||
|
|
||||||
# startup sequence
|
# startup sequence
|
||||||
self.fsm.act("WAIT_TX_ENABLE",
|
self.fsm.act("WAIT_TX_ENABLE",
|
||||||
NextValue(self.tx_idle.disp_in, 0),
|
|
||||||
NextValue(self.tx_idle.word_idx, 0),
|
|
||||||
|
|
||||||
If(self.tx_enable.storage,
|
If(self.tx_enable.storage,
|
||||||
|
NextValue(self.tx_idle.word_idx, 0),
|
||||||
NextValue(tx_wordcount, 0),
|
NextValue(tx_wordcount, 0),
|
||||||
NextValue(tx_bitcount, 0),
|
NextValue(tx_bitcount, 0),
|
||||||
NextState("LOAD_CHAR")
|
NextState("LOAD_CHAR")
|
||||||
|
@ -91,11 +89,6 @@ class CXP_UpConn(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# CXP 2.1 section 9.2.4
|
|
||||||
# Higher priority packet can be inserted into a lower priority packet during transmission
|
|
||||||
# Priority lv 0 can be inserted in char boundary of the packet
|
|
||||||
# Priority lv 1-2 need to be inserted in word boundary of the packet
|
|
||||||
self.sync.cxp_upconn += [
|
self.sync.cxp_upconn += [
|
||||||
self.tx_fifos.disp_in.eq(disp),
|
self.tx_fifos.disp_in.eq(disp),
|
||||||
self.tx_idle.disp_in.eq(disp),
|
self.tx_idle.disp_in.eq(disp),
|
||||||
|
@ -110,39 +103,33 @@ class CXP_UpConn(Module, AutoCSR):
|
||||||
If(tx_bitcount == 9,
|
If(tx_bitcount == 9,
|
||||||
tx_bitcount.eq(0),
|
tx_bitcount.eq(0),
|
||||||
If((~self.tx_fifos.pe.n) & (self.tx_fifos.pe.o == 0),
|
If((~self.tx_fifos.pe.n) & (self.tx_fifos.pe.o == 0),
|
||||||
# trigger packet can interrupt at char level
|
# trigger packets are inserted at char boundary and don't contribute to word count
|
||||||
tx_reg.eq(self.tx_fifos.source_data[0]),
|
tx_reg.eq(self.tx_fifos.source_data[0]),
|
||||||
self.tx_fifos.source_ack[0].eq(1),
|
self.tx_fifos.source_ack[0].eq(1),
|
||||||
disp.eq(self.tx_fifos.disp_out[0]),
|
disp.eq(self.tx_fifos.disp_out[0]),
|
||||||
).Else(
|
).Else(
|
||||||
# priority zero doesn't contribute to word count
|
# word boundary
|
||||||
If(tx_wordcount != 3,
|
|
||||||
tx_wordcount.eq(tx_wordcount + 1),
|
|
||||||
).Else(
|
|
||||||
tx_wordcount.eq(0),
|
|
||||||
),
|
|
||||||
|
|
||||||
# new word boundary
|
|
||||||
If(tx_wordcount == 3,
|
If(tx_wordcount == 3,
|
||||||
|
tx_wordcount.eq(0),
|
||||||
If(~self.tx_fifos.pe.n,
|
If(~self.tx_fifos.pe.n,
|
||||||
|
# priority lv 1 & 2 packets are inserted at word boundary
|
||||||
idling.eq(0),
|
idling.eq(0),
|
||||||
priority.eq(self.tx_fifos.pe.o),
|
priorities.eq(self.tx_fifos.pe.o),
|
||||||
|
|
||||||
self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1),
|
self.tx_fifos.source_ack[self.tx_fifos.pe.o].eq(1),
|
||||||
tx_reg.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]),
|
tx_reg.eq(self.tx_fifos.source_data[self.tx_fifos.pe.o]),
|
||||||
disp.eq(self.tx_fifos.disp_out[self.tx_fifos.pe.o]),
|
disp.eq(self.tx_fifos.disp_out[self.tx_fifos.pe.o]),
|
||||||
).Else(
|
).Else(
|
||||||
idling.eq(1),
|
idling.eq(1),
|
||||||
|
|
||||||
self.tx_idle.source_ack.eq(1),
|
self.tx_idle.source_ack.eq(1),
|
||||||
tx_reg.eq(self.tx_idle.source_data),
|
tx_reg.eq(self.tx_idle.source_data),
|
||||||
disp.eq(self.tx_idle.disp_out),
|
disp.eq(self.tx_idle.disp_out),
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
|
tx_wordcount.eq(tx_wordcount + 1),
|
||||||
If(~idling,
|
If(~idling,
|
||||||
self.tx_fifos.source_ack[priority].eq(1),
|
self.tx_fifos.source_ack[priorities].eq(1),
|
||||||
tx_reg.eq(self.tx_fifos.source_data[priority]),
|
tx_reg.eq(self.tx_fifos.source_data[priorities]),
|
||||||
disp.eq(self.tx_fifos.disp_out[priority]),
|
disp.eq(self.tx_fifos.disp_out[priorities]),
|
||||||
).Else(
|
).Else(
|
||||||
self.tx_idle.source_ack.eq(1),
|
self.tx_idle.source_ack.eq(1),
|
||||||
tx_reg.eq(self.tx_idle.source_data),
|
tx_reg.eq(self.tx_idle.source_data),
|
||||||
|
@ -244,6 +231,7 @@ class TxFIFOs(Module):
|
||||||
# reset ack after asserted
|
# reset ack after asserted
|
||||||
If(self.source_ack[i], self.source_ack[i].eq(0)),
|
If(self.source_ack[i], self.source_ack[i].eq(0)),
|
||||||
]
|
]
|
||||||
|
|
||||||
# FIFOs transmission priority
|
# FIFOs transmission priority
|
||||||
self.submodules.pe = PriorityEncoder(nfifos)
|
self.submodules.pe = PriorityEncoder(nfifos)
|
||||||
self.comb += self.pe.i.eq(source_stb)
|
self.comb += self.pe.i.eq(source_stb)
|
||||||
|
@ -261,7 +249,7 @@ class TxIdle(Module):
|
||||||
|
|
||||||
# CXP 2.1 section 9.2.5
|
# CXP 2.1 section 9.2.5
|
||||||
IDLE_CHARS = Array([
|
IDLE_CHARS = Array([
|
||||||
#[data, k]
|
#[char, k]
|
||||||
[0b10111100, 1], #K28.5
|
[0b10111100, 1], #K28.5
|
||||||
[0b00111100, 1], #K28.1
|
[0b00111100, 1], #K28.1
|
||||||
[0b00111100, 1], #K28.1
|
[0b00111100, 1], #K28.1
|
||||||
|
|
|
@ -649,7 +649,7 @@ class _NIST_QC2_RTIO:
|
||||||
self.add_rtio(rtio_channels)
|
self.add_rtio(rtio_channels)
|
||||||
|
|
||||||
|
|
||||||
class _CXP_FMC_RTIO():
|
class CXP_FMC():
|
||||||
"""
|
"""
|
||||||
CoaXpress FMC with 4 CXP channel and 1 SMA trigger
|
CoaXpress FMC with 4 CXP channel and 1 SMA trigger
|
||||||
"""
|
"""
|
||||||
|
@ -664,17 +664,32 @@ class _CXP_FMC_RTIO():
|
||||||
Subsignal("n_rx", Pins("AD19"), IOStandard("LVCMOS33")),
|
Subsignal("n_rx", Pins("AD19"), IOStandard("LVCMOS33")),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
pmod1_33 = [
|
||||||
|
("pmod1_33", 0, Pins("AJ21"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 1, Pins("AK21"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 2, Pins("AB21"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 3, Pins("AB16"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 4, Pins("Y20"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 5, Pins("AA20"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 6, Pins("AC18"), IOStandard("LVCMOS33")),
|
||||||
|
("pmod1_33", 7, Pins("AC19"), IOStandard("LVCMOS33")),
|
||||||
|
]
|
||||||
|
|
||||||
platform.add_extension(debug_sma)
|
platform.add_extension(debug_sma)
|
||||||
|
platform.add_extension(pmod1_33)
|
||||||
|
pmod_pads = [platform.request("pmod1_33", i) for i in range(8)]
|
||||||
|
|
||||||
clk_freq = 125e6
|
clk_freq = 125e6
|
||||||
|
|
||||||
self.submodules.cxp_gtx = cxp.CXP(
|
self.submodules.cxp = cxp.CXP(
|
||||||
refclk=self.cdr_clk,
|
refclk=self.cdr_clk,
|
||||||
pads=platform.request("CXP_HS", 0),
|
pads=platform.request("CXP_HS", 0),
|
||||||
sys_clk_freq=clk_freq,
|
sys_clk_freq=clk_freq,
|
||||||
debug_sma=platform.request("user_sma_clock_33")
|
debug_sma=platform.request("user_sma_clock_33"),
|
||||||
|
pmod_pads = pmod_pads
|
||||||
)
|
)
|
||||||
self.csr_devices.append("cxp_gtx")
|
self.csr_devices.append("cxp")
|
||||||
|
|
||||||
rtio_channels = []
|
rtio_channels = []
|
||||||
# FIXME remove this placeholder RTIO channel
|
# FIXME remove this placeholder RTIO channel
|
||||||
|
@ -722,14 +737,13 @@ class NIST_QC2_Satellite(_SatelliteBase, _NIST_QC2_RTIO):
|
||||||
_SatelliteBase.__init__(self, acpki, drtio100mhz)
|
_SatelliteBase.__init__(self, acpki, drtio100mhz)
|
||||||
_NIST_QC2_RTIO.__init__(self)
|
_NIST_QC2_RTIO.__init__(self)
|
||||||
|
|
||||||
class CXP_FMC(ZC706, _CXP_FMC_RTIO):
|
class CXP_Demo(ZC706, CXP_FMC):
|
||||||
def __init__(self, acpki, drtio100mhz):
|
def __init__(self, acpki, drtio100mhz):
|
||||||
ZC706.__init__(self, acpki)
|
ZC706.__init__(self, acpki)
|
||||||
# self.submodules += SMAClkinForward(self.platform)
|
CXP_FMC.__init__(self)
|
||||||
_CXP_FMC_RTIO.__init__(self)
|
|
||||||
|
|
||||||
VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite,
|
VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_CLOCK_Master, NIST_CLOCK_Satellite,
|
||||||
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_FMC]}
|
NIST_QC2, NIST_QC2_Master, NIST_QC2_Satellite, CXP_Demo]}
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||||
|
use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
use crate::pl::csr;
|
||||||
|
|
||||||
|
pub fn main(timer: &mut GlobalTimer) {
|
||||||
|
unsafe {
|
||||||
|
info!("turning on pmc loopback mode...");
|
||||||
|
csr::cxp::loopback_mode_write(0b010); // Near-End PMA Loopback
|
||||||
|
|
||||||
|
// enable cxp gtx clock domains
|
||||||
|
csr::cxp::tx_start_init_write(1);
|
||||||
|
csr::cxp::rx_start_init_write(1);
|
||||||
|
|
||||||
|
info!("waiting for QPLL/CPLL to lock...");
|
||||||
|
timer.delay_us(50_000);
|
||||||
|
info!("tx_phaligndone = {} ", csr::cxp::txinit_phaligndone_read(),);
|
||||||
|
|
||||||
|
// enable txdata tranmission thought MGTXTXP, required by PMA loopback
|
||||||
|
csr::cxp::txenable_write(1);
|
||||||
|
|
||||||
|
loopback_testing(timer, 0x00, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loopback_testing(timer: &mut GlobalTimer, data: u8, control_bit: u8) {
|
||||||
|
unsafe {
|
||||||
|
// send K28_5 for CDR to align
|
||||||
|
const K28_5: u8 = 0xBC;
|
||||||
|
csr::cxp::data_0_write(K28_5);
|
||||||
|
csr::cxp::control_bit_0_write(1);
|
||||||
|
csr::cxp::data_1_write(K28_5);
|
||||||
|
csr::cxp::control_bit_1_write(1);
|
||||||
|
|
||||||
|
info!("waiting for rx to align...");
|
||||||
|
while csr::cxp::rx_ready_read() != 1 {}
|
||||||
|
info!("rx ready!");
|
||||||
|
|
||||||
|
csr::cxp::data_1_write(data);
|
||||||
|
csr::cxp::control_bit_1_write(control_bit);
|
||||||
|
println!(
|
||||||
|
"data[0] = {:#04x} control bit = {:#b} encoded = {:#012b}",
|
||||||
|
csr::cxp::data_0_read(),
|
||||||
|
csr::cxp::control_bit_0_read(),
|
||||||
|
csr::cxp::encoded_0_read(),
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"data[1] = {:#04x} control bit = {:#b} encoded = {:#012b}",
|
||||||
|
csr::cxp::data_1_read(),
|
||||||
|
csr::cxp::control_bit_1_read(),
|
||||||
|
csr::cxp::encoded_1_read(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for _ in 0..20 {
|
||||||
|
timer.delay_us(100);
|
||||||
|
// println!(
|
||||||
|
// "data[0] = {:#012b} data[1] = {:#012b}",
|
||||||
|
// csr::cxp::rxdata_0_read(),
|
||||||
|
// csr::cxp::rxdata_1_read(),
|
||||||
|
// );
|
||||||
|
println!(
|
||||||
|
"decoded_data[0] = {:#04x} decoded_k[0] = {:#b} decoded_data[1] = {:#04x} decoded_k[1] = {:#b}",
|
||||||
|
csr::cxp::decoded_data_0_read(),
|
||||||
|
csr::cxp::decoded_k_0_read(),
|
||||||
|
csr::cxp::decoded_data_1_read(),
|
||||||
|
csr::cxp::decoded_k_1_read(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||||
|
use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
|
|
||||||
|
use crate::pl::csr;
|
||||||
|
|
||||||
|
pub fn crc_test() {
|
||||||
|
let arr = [
|
||||||
|
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, // CXP CRC-32
|
||||||
|
0x56, 0x86, 0x5D, 0x6f,
|
||||||
|
];
|
||||||
|
let mut crc: u32; // seed = 0xFFFFFFFF
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
csr::cxp::crc_en_write(1);
|
||||||
|
|
||||||
|
for a in arr.iter() {
|
||||||
|
csr::cxp::crc_data_write(*a);
|
||||||
|
crc = csr::cxp::crc_value_read();
|
||||||
|
println!("input = {:#04x}", *a);
|
||||||
|
println!("CRC NOT(val.reverse) = {:#010x}", !crc.reverse_bits());
|
||||||
|
// since the input bit are reversed when entering the crc engine, the output char need to be reversed to cancel out on the receiver side
|
||||||
|
println!("CRC CXP = {:#010x}", crc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_test(timer: &mut GlobalTimer) {
|
||||||
|
// the 8bit shift is k symbol
|
||||||
|
// const K28_1: u16 = 0x3C | (1 << 8);
|
||||||
|
// const K28_5: u16 = 0xBC | (1 << 8);
|
||||||
|
const D31_1: u16 = 0x3F;
|
||||||
|
const D01_1: u16 = 0x21;
|
||||||
|
|
||||||
|
const LEN: usize = 100;
|
||||||
|
let mut arr: [u16; LEN] = [0; LEN];
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
csr::cxp::upconn_clk_reset_write(1);
|
||||||
|
// csr::cxp::upconn_bitrate2x_enable_write(1);
|
||||||
|
csr::cxp::upconn_clk_reset_write(0);
|
||||||
|
loop {
|
||||||
|
// TODO: verify the char & word boundary thingy
|
||||||
|
for _ in 0..8 {
|
||||||
|
csr::cxp::upconn_symbol1_write(D01_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..4 {
|
||||||
|
csr::cxp::upconn_symbol2_write(D31_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.delay_us(1);
|
||||||
|
csr::cxp::upconn_tx_enable_write(1);
|
||||||
|
|
||||||
|
for i in 0..LEN {
|
||||||
|
arr[i] = get_encoded();
|
||||||
|
}
|
||||||
|
for i in 0..LEN {
|
||||||
|
match arr[i] {
|
||||||
|
0b1010111001 | 0b0101001001 => {
|
||||||
|
println!("encoded = {:#012b} D31.1", arr[i])
|
||||||
|
}
|
||||||
|
0b0111011001 | 0b1000101001 => {
|
||||||
|
println!("encoded = {:#012b} D01.1", arr[i])
|
||||||
|
}
|
||||||
|
0b0011111010 | 0b1100000101 => {
|
||||||
|
println!("encoded = {:#012b} K28.5 start idling....", arr[i])
|
||||||
|
}
|
||||||
|
0b0011111001 | 0b1100000110 => {
|
||||||
|
println!("encoded = {:#012b} K28.1 idling...", arr[i])
|
||||||
|
}
|
||||||
|
0b0011101010 => {
|
||||||
|
println!("encoded = {:#012b} D28.5 END idle", arr[i])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("encoded = {:#012b}", arr[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("-------------------------------------");
|
||||||
|
|
||||||
|
csr::cxp::upconn_tx_enable_write(0);
|
||||||
|
timer.delay_us(2_000_000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_encoded() -> u16 {
|
||||||
|
unsafe { csr::cxp::upconn_encoded_data_read().reverse_bits() >> 6 }
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,6 +42,11 @@ pub mod si5324;
|
||||||
pub mod si549;
|
pub mod si549;
|
||||||
use core::{cmp, str};
|
use core::{cmp, str};
|
||||||
|
|
||||||
|
#[cfg(has_cxp)]
|
||||||
|
pub mod cxp_downconn;
|
||||||
|
#[cfg(has_cxp)]
|
||||||
|
pub mod cxp_upconn;
|
||||||
|
|
||||||
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
pub fn identifier_read(buf: &mut [u8]) -> &str {
|
||||||
unsafe {
|
unsafe {
|
||||||
pl::csr::identifier::address_write(0);
|
pl::csr::identifier::address_write(0);
|
||||||
|
|
Loading…
Reference in New Issue