forked from M-Labs/artiq-zynq
Compare commits
35 Commits
074e8e94d1
...
7285479f5b
Author | SHA1 | Date |
---|---|---|
morgan | 7285479f5b | |
morgan | cb0a0358a3 | |
morgan | 790f0196b6 | |
morgan | b1069f524a | |
morgan | 98095664ce | |
morgan | 12bf931614 | |
morgan | b725594a1d | |
morgan | fe57067f70 | |
morgan | 8b2181b1a8 | |
morgan | 08ee4f1cb9 | |
morgan | 133802fef2 | |
morgan | 5af2d8c23b | |
morgan | 581d9ffebb | |
morgan | 6943a2b17e | |
morgan | 5c253fefb6 | |
morgan | aeabca2182 | |
morgan | 16ccd7eada | |
morgan | d9888d7647 | |
morgan | 6b50d83e67 | |
morgan | b2ce43155e | |
morgan | d81c770e54 | |
morgan | f83afc7195 | |
morgan | 38485aec56 | |
morgan | 7dbeefd0a4 | |
morgan | fa674e32f5 | |
morgan | 9f8f8c1ad0 | |
morgan | 397027876c | |
morgan | 8a6e89b2d8 | |
morgan | f0dda0fcf7 | |
morgan | 04932d630f | |
morgan | d9fb50c12e | |
morgan | fa5ede6174 | |
morgan | ce0f302b22 | |
morgan | 3a80f37a2f | |
morgan | f19c7fa369 |
20
flake.lock
20
flake.lock
|
@ -11,11 +11,11 @@
|
||||||
"src-pythonparser": "src-pythonparser"
|
"src-pythonparser": "src-pythonparser"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1724210813,
|
"lastModified": 1725373154,
|
||||||
"narHash": "sha256-OqQdE2lC0jKNS2fFq0Fda1nBpyT8ijmSXqdkO8xeOJ8=",
|
"narHash": "sha256-fq9EW9fDWrV0v1vNj7ZqDNpNYx8+OxoFdPwpvkPf67g=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "61e96b37f9c4345e2d7bf71d47ba0b5e947de83e",
|
"rev": "0c1ffa9f4f6a3e7864459923ec4b9cc45f16327a",
|
||||||
"revCount": 8985,
|
"revCount": 9005,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/m-labs/artiq.git"
|
"url": "https://github.com/m-labs/artiq.git"
|
||||||
},
|
},
|
||||||
|
@ -102,11 +102,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1723362943,
|
"lastModified": 1724224976,
|
||||||
"narHash": "sha256-dFZRVSgmJkyM0bkPpaYRtG/kRMRTorUIDj8BxoOt1T4=",
|
"narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a58bc8ad779655e790115244571758e8de055e3d",
|
"rev": "c374d94f1536013ca8e92341b540eba4c22f9c62",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -169,11 +169,11 @@
|
||||||
"src-migen": {
|
"src-migen": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1721561053,
|
"lastModified": 1724304798,
|
||||||
"narHash": "sha256-z3LRhNmKZrjr6rFD0yxtccSa/SWvFIYmb+G/D5d2Jd8=",
|
"narHash": "sha256-tQ02N0eXY5W/Z7CrOy3Cu4WjDZDQWb8hYlzsFzr3Mus=",
|
||||||
"owner": "m-labs",
|
"owner": "m-labs",
|
||||||
"repo": "migen",
|
"repo": "migen",
|
||||||
"rev": "9279e8623f8433bc4f23ac51e5e2331bfe544417",
|
"rev": "832a7240ba32af9cbd4fdd519ddcb4f912534726",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -2,7 +2,7 @@ from migen import *
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
from misoc.interconnect import stream
|
from misoc.interconnect import stream
|
||||||
|
|
||||||
from cxp_downconn import CXP_DownConn
|
from cxp_downconn import CXP_DownConn_PHY
|
||||||
from cxp_upconn import CXP_UpConn_PHY
|
from cxp_upconn import CXP_UpConn_PHY
|
||||||
from cxp_pipeline import *
|
from cxp_pipeline import *
|
||||||
|
|
||||||
|
@ -10,11 +10,20 @@ class CXP(Module, AutoCSR):
|
||||||
def __init__(self, refclk, downconn_pads, upconn_pads, sys_clk_freq, debug_sma, pmod_pads):
|
def __init__(self, refclk, downconn_pads, upconn_pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
self.submodules.upconn = UpConn_Interface(upconn_pads, sys_clk_freq, debug_sma, pmod_pads)
|
self.submodules.upconn = UpConn_Interface(upconn_pads, sys_clk_freq, debug_sma, pmod_pads)
|
||||||
|
|
||||||
self.submodules.downconn = CXP_DownConn(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads)
|
self.submodules.downconn = DownConn_Interface(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads)
|
||||||
# TODO: support the option high speed upconn
|
# TODO: support the option high speed upconn
|
||||||
|
|
||||||
# TODO: add link layer
|
# TODO: add link layer
|
||||||
|
|
||||||
|
class DownConn_Interface(Module, AutoCSR):
|
||||||
|
def __init__(self, refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
self.submodules.phy = phy = CXP_DownConn_PHY(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads)
|
||||||
|
self.gtxs = phy.gtxs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UpConn_Interface(Module, AutoCSR):
|
class UpConn_Interface(Module, AutoCSR):
|
||||||
def __init__(self, upconn_pads, sys_clk_freq, debug_sma, pmod_pads):
|
def __init__(self, upconn_pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
|
@ -23,24 +32,24 @@ class UpConn_Interface(Module, AutoCSR):
|
||||||
self.tx_enable = CSRStorage()
|
self.tx_enable = CSRStorage()
|
||||||
self.tx_busy = CSRStatus()
|
self.tx_busy = CSRStatus()
|
||||||
|
|
||||||
|
self.tx_testmode_en = CSRStorage()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
layout = [("data", 8), ("k", 1)]
|
self.submodules.phy = phy = CXP_UpConn_PHY(upconn_pads, sys_clk_freq, debug_sma, pmod_pads)
|
||||||
|
|
||||||
self.submodules.upconn_phy = upconn_phy = CXP_UpConn_PHY(upconn_pads, sys_clk_freq, debug_sma, pmod_pads, layout)
|
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
upconn_phy.bitrate2x_enable.eq(self.bitrate2x_enable.storage),
|
phy.bitrate2x_enable.eq(self.bitrate2x_enable.storage),
|
||||||
upconn_phy.tx_enable.eq(self.tx_enable.storage),
|
phy.tx_enable.eq(self.tx_enable.storage),
|
||||||
upconn_phy.clk_reset.eq(self.clk_reset.re),
|
phy.clk_reset.eq(self.clk_reset.re),
|
||||||
self.tx_busy.status.eq(upconn_phy.tx_busy),
|
self.tx_busy.status.eq(phy.tx_busy),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Packet FIFOs with transmission priority
|
# Packet FIFOs with transmission priority
|
||||||
# 0: Trigger packet
|
# 0: Trigger packet
|
||||||
self.submodules.trig = trig = TX_Trigger(layout)
|
self.submodules.trig = trig = TX_Trigger()
|
||||||
self.comb += trig.source.connect(upconn_phy.sinks[0])
|
self.comb += trig.source.connect(phy.sinks[0])
|
||||||
|
|
||||||
# DEBUG: INPUT
|
# DEBUG: INPUT
|
||||||
self.trig_stb = CSR()
|
self.trig_stb = CSR()
|
||||||
|
@ -55,8 +64,8 @@ class UpConn_Interface(Module, AutoCSR):
|
||||||
|
|
||||||
|
|
||||||
# 1: IO acknowledgment for trigger packet
|
# 1: IO acknowledgment for trigger packet
|
||||||
self.submodules.trig_ack = trig_ack = Trigger_ACK(layout)
|
self.submodules.trig_ack = trig_ack = Trigger_ACK()
|
||||||
self.comb += trig_ack.source.connect(upconn_phy.sinks[1])
|
self.comb += trig_ack.source.connect(phy.sinks[1])
|
||||||
|
|
||||||
# DEBUG: INPUT
|
# DEBUG: INPUT
|
||||||
self.ack = CSR()
|
self.ack = CSR()
|
||||||
|
@ -65,5 +74,16 @@ class UpConn_Interface(Module, AutoCSR):
|
||||||
|
|
||||||
# 2: All other packets
|
# 2: All other packets
|
||||||
# Control is not timing dependent, all the link layer is done in firmware
|
# Control is not timing dependent, all the link layer is done in firmware
|
||||||
self.submodules.command = command = TX_Command_Packet(layout)
|
self.submodules.command = command = TX_Command_Packet()
|
||||||
self.comb += command.source.connect(upconn_phy.sinks[2])
|
self.submodules.testseq = testseq = TX_Test_Packet()
|
||||||
|
|
||||||
|
|
||||||
|
self.submodules.mux = mux = stream.Multiplexer(upconn_layout, 2)
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
command.source.connect(mux.sink0),
|
||||||
|
testseq.source.connect(mux.sink1),
|
||||||
|
mux.sel.eq(self.tx_testmode_en.storage),
|
||||||
|
|
||||||
|
mux.source.connect(phy.sinks[2])
|
||||||
|
]
|
||||||
|
|
|
@ -10,7 +10,7 @@ from artiq.gateware.drtio.transceiver.gtx_7series_init import *
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from operator import add
|
from operator import add
|
||||||
|
|
||||||
class CXP_DownConn(Module, AutoCSR):
|
class CXP_DownConn_PHY(Module, AutoCSR):
|
||||||
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
|
def __init__(self, refclk, pads, sys_clk_freq, debug_sma, pmod_pads):
|
||||||
nconn = len(pads)
|
nconn = len(pads)
|
||||||
self.rx_start_init = CSRStorage()
|
self.rx_start_init = CSRStorage()
|
||||||
|
|
|
@ -3,6 +3,11 @@ from misoc.interconnect.csr import *
|
||||||
from misoc.interconnect import stream
|
from misoc.interconnect import stream
|
||||||
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine, LiteEthMACCRCChecker
|
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine, LiteEthMACCRCChecker
|
||||||
|
|
||||||
|
upconn_dw = 8
|
||||||
|
upconn_layout = [("data", upconn_dw), ("k", upconn_dw//8)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def K(x, y):
|
def K(x, y):
|
||||||
return ((y << 5) | x)
|
return ((y << 5) | x)
|
||||||
|
|
||||||
|
@ -52,11 +57,11 @@ class Code_Source(Module):
|
||||||
|
|
||||||
class Code_Inserter(Module):
|
class Code_Inserter(Module):
|
||||||
def __init__(self, layout, insert_infront=True, counts=4):
|
def __init__(self, layout, insert_infront=True, counts=4):
|
||||||
self.sink = sink = stream.Endpoint(layout)
|
self.sink = stream.Endpoint(layout)
|
||||||
self.source = source = stream.Endpoint(layout)
|
self.source = stream.Endpoint(layout)
|
||||||
|
|
||||||
self.data = Signal.like(sink.data)
|
self.data = Signal.like(self.sink.data)
|
||||||
self.k = Signal.like(sink.k)
|
self.k = Signal.like(self.sink.k)
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
assert counts > 0
|
assert counts > 0
|
||||||
|
@ -77,61 +82,61 @@ class Code_Inserter(Module):
|
||||||
|
|
||||||
if insert_infront:
|
if insert_infront:
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
sink.ack.eq(1),
|
self.sink.ack.eq(1),
|
||||||
clr_cnt.eq(1),
|
clr_cnt.eq(1),
|
||||||
If(sink.stb,
|
If(self.sink.stb,
|
||||||
sink.ack.eq(0),
|
self.sink.ack.eq(0),
|
||||||
NextState("INSERT"),
|
NextState("INSERT"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fsm.act("INSERT",
|
fsm.act("INSERT",
|
||||||
sink.ack.eq(0),
|
self.sink.ack.eq(0),
|
||||||
source.stb.eq(1),
|
self.source.stb.eq(1),
|
||||||
source.data.eq(self.data),
|
self.source.data.eq(self.data),
|
||||||
source.k.eq(self.k),
|
self.source.k.eq(self.k),
|
||||||
If(cnt == counts - 1,
|
If(cnt == counts - 1,
|
||||||
If(source.ack, NextState("COPY"))
|
If(self.source.ack, NextState("COPY"))
|
||||||
).Else(
|
).Else(
|
||||||
inc_cnt.eq(source.ack)
|
inc_cnt.eq(self.source.ack)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fsm.act("COPY",
|
fsm.act("COPY",
|
||||||
sink.connect(source),
|
self.sink.connect(self.source),
|
||||||
If(sink.stb & sink.eop & source.ack,
|
If(self.sink.stb & self.sink.eop & self.source.ack,
|
||||||
NextState("IDLE"),
|
NextState("IDLE"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
sink.ack.eq(1),
|
self.sink.ack.eq(1),
|
||||||
clr_cnt.eq(1),
|
clr_cnt.eq(1),
|
||||||
If(sink.stb,
|
If(self.sink.stb,
|
||||||
sink.ack.eq(0),
|
self.sink.ack.eq(0),
|
||||||
NextState("COPY"),
|
NextState("COPY"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fsm.act("COPY",
|
fsm.act("COPY",
|
||||||
sink.connect(source),
|
self.sink.connect(self.source),
|
||||||
source.eop.eq(0),
|
self.source.eop.eq(0),
|
||||||
If(sink.stb & sink.eop & source.ack,
|
If(self.sink.stb & self.sink.eop & self.source.ack,
|
||||||
NextState("INSERT"),
|
NextState("INSERT"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
fsm.act("INSERT",
|
fsm.act("INSERT",
|
||||||
sink.ack.eq(0),
|
self.sink.ack.eq(0),
|
||||||
source.stb.eq(1),
|
self.source.stb.eq(1),
|
||||||
source.data.eq(self.data),
|
self.source.data.eq(self.data),
|
||||||
source.k.eq(self.k),
|
self.source.k.eq(self.k),
|
||||||
If(cnt == counts - 1,
|
If(cnt == counts - 1,
|
||||||
source.eop.eq(1),
|
self.source.eop.eq(1),
|
||||||
If(source.ack, NextState("IDLE"))
|
If(self.source.ack, NextState("IDLE"))
|
||||||
).Else(
|
).Else(
|
||||||
inc_cnt.eq(source.ack)
|
inc_cnt.eq(self.source.ack)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -184,22 +189,22 @@ class CXPCRC32Checker(LiteEthMACCRCChecker):
|
||||||
LiteEthMACCRCChecker.__init__(self, CXPCRC32, layout)
|
LiteEthMACCRCChecker.__init__(self, CXPCRC32, layout)
|
||||||
|
|
||||||
class TX_Trigger(Module, AutoCSR):
|
class TX_Trigger(Module, AutoCSR):
|
||||||
def __init__(self, layout):
|
def __init__(self):
|
||||||
self.trig_stb = Signal()
|
self.trig_stb = Signal()
|
||||||
self.delay = Signal(8)
|
self.delay = Signal(upconn_dw)
|
||||||
self.linktrig_mode = Signal(max=4)
|
self.linktrig_mode = Signal(max=4)
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.code_src = code_src = Code_Source(layout, counts=3)
|
self.submodules.code_src = code_src = Code_Source(upconn_layout, counts=3)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
code_src.stb.eq(self.trig_stb),
|
code_src.stb.eq(self.trig_stb),
|
||||||
code_src.data.eq(self.delay),
|
code_src.data.eq(self.delay),
|
||||||
code_src.k.eq(0)
|
code_src.k.eq(0)
|
||||||
]
|
]
|
||||||
|
|
||||||
self.submodules.inserter_once = inserter_once = Code_Inserter(layout, counts=1)
|
self.submodules.inserter_once = inserter_once = Code_Inserter(upconn_layout, counts=1)
|
||||||
self.submodules.inserter_twice = inserter_twice = Code_Inserter(layout, counts=2)
|
self.submodules.inserter_twice = inserter_twice = Code_Inserter(upconn_layout, counts=2)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
inserter_once.k.eq(1),
|
inserter_once.k.eq(1),
|
||||||
inserter_twice.k.eq(1),
|
inserter_twice.k.eq(1),
|
||||||
|
@ -220,15 +225,15 @@ class TX_Trigger(Module, AutoCSR):
|
||||||
self.source = tx_pipeline[-1].source
|
self.source = tx_pipeline[-1].source
|
||||||
|
|
||||||
class Trigger_ACK(Module):
|
class Trigger_ACK(Module):
|
||||||
def __init__(self, layout):
|
def __init__(self):
|
||||||
self.ack = Signal()
|
self.ack = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# Section 9.3.2 (CXP-001-2021)
|
# Section 9.3.2 (CXP-001-2021)
|
||||||
# Send 4x K28.6 and 4x 0x01 as trigger packet ack
|
# Send 4x K28.6 and 4x 0x01 as trigger packet ack
|
||||||
self.submodules.code_src = code_src = Code_Source(layout)
|
self.submodules.code_src = code_src = Code_Source(upconn_layout)
|
||||||
self.submodules.k_code_inserter = k_code_inserter = Code_Inserter(layout)
|
self.submodules.k_code_inserter = k_code_inserter = Code_Inserter(upconn_layout)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
code_src.stb.eq(self.ack),
|
code_src.stb.eq(self.ack),
|
||||||
code_src.data.eq(0x01),
|
code_src.data.eq(0x01),
|
||||||
|
@ -242,20 +247,17 @@ class Trigger_ACK(Module):
|
||||||
self.source = k_code_inserter.source
|
self.source = k_code_inserter.source
|
||||||
|
|
||||||
class TX_Command_Packet(Module, AutoCSR):
|
class TX_Command_Packet(Module, AutoCSR):
|
||||||
def __init__(self, layout):
|
def __init__(self):
|
||||||
self.len = CSRStorage(6)
|
self.len = CSRStorage(6)
|
||||||
self.data = CSR(8)
|
self.data = CSR(upconn_dw)
|
||||||
self.writeable = CSRStatus()
|
self.writeable = CSRStatus()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
# TODO: use RAM instead of FIFO ?
|
|
||||||
# Section 12.1.2 (CXP-001-2021)
|
# Section 12.1.2 (CXP-001-2021)
|
||||||
# Max control packet size is 128 bytes
|
# Max control packet size is 128 bytes
|
||||||
|
self.submodules.fifo = fifo = stream.SyncFIFO(upconn_layout, 128)
|
||||||
# NOTE: The firmware will lock up if there is not enough space for the packet
|
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(upconn_layout)
|
||||||
self.submodules.fifo = fifo = stream.SyncFIFO(layout, 128)
|
|
||||||
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(layout)
|
|
||||||
self.source = pak_wrp.source
|
self.source = pak_wrp.source
|
||||||
|
|
||||||
self.comb += fifo.source.connect(pak_wrp.sink)
|
self.comb += fifo.source.connect(pak_wrp.sink)
|
||||||
|
@ -278,3 +280,69 @@ class TX_Command_Packet(Module, AutoCSR):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class TX_Test_Packet(Module, AutoCSR):
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.stb = CSR()
|
||||||
|
self.busy = CSRStatus()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
testdata_src = stream.Endpoint(upconn_layout)
|
||||||
|
|
||||||
|
|
||||||
|
# Section 9.9.2 (CXP-001-2021)
|
||||||
|
# 0x00, 0x01 ... 0xFF need to be send 16 times
|
||||||
|
# cnt[8:12] is used to count up 16 times while cnt[:8] is the data
|
||||||
|
cnt = Signal(max=0x1000)
|
||||||
|
clr_cnt = Signal()
|
||||||
|
inc_cnt = Signal()
|
||||||
|
|
||||||
|
self.sync += [
|
||||||
|
If(clr_cnt,
|
||||||
|
cnt.eq(cnt.reset),
|
||||||
|
).Elif(inc_cnt,
|
||||||
|
cnt.eq(cnt + 1),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
|
||||||
|
|
||||||
|
fsm.act("IDLE",
|
||||||
|
clr_cnt.eq(1),
|
||||||
|
If(self.stb.re,
|
||||||
|
NextState("WRITE")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fsm.act("WRITE",
|
||||||
|
testdata_src.stb.eq(1),
|
||||||
|
testdata_src.data.eq(cnt[:8]),
|
||||||
|
testdata_src.k.eq(0),
|
||||||
|
If(cnt == 0xFFF,
|
||||||
|
testdata_src.eop.eq(1),
|
||||||
|
If(testdata_src.ack, NextState("IDLE"))
|
||||||
|
).Else(
|
||||||
|
inc_cnt.eq(testdata_src.ack)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.submodules.pak_type_inserter = pak_type_inserter = Code_Inserter(upconn_layout)
|
||||||
|
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(upconn_layout)
|
||||||
|
self.comb += [
|
||||||
|
pak_type_inserter.data.eq(0x04),
|
||||||
|
pak_type_inserter.k.eq(0x04),
|
||||||
|
|
||||||
|
testdata_src.connect(pak_type_inserter.sink),
|
||||||
|
pak_type_inserter.source.connect(pak_wrp.sink),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.source = pak_wrp.source
|
||||||
|
|
||||||
|
self.sync += \
|
||||||
|
If(self.stb.re,
|
||||||
|
self.busy.status.eq(1),
|
||||||
|
).Elif(self.source.eop & self.source.ack,
|
||||||
|
self.busy.status.eq(0)
|
||||||
|
)
|
||||||
|
|
|
@ -7,6 +7,8 @@ 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 *
|
||||||
|
|
||||||
|
from cxp_pipeline import upconn_layout
|
||||||
|
|
||||||
IDLE_CHARS = Array([
|
IDLE_CHARS = Array([
|
||||||
#[char, k]
|
#[char, k]
|
||||||
[0xBC, 1], #K28.5
|
[0xBC, 1], #K28.5
|
||||||
|
@ -93,23 +95,27 @@ class SERDES_10bits(Module):
|
||||||
]
|
]
|
||||||
|
|
||||||
@ResetInserter()
|
@ResetInserter()
|
||||||
@CEInserter()
|
class Transmit_Scheduler(Module):
|
||||||
class Packets_Scheduler(Module):
|
def __init__(self, interface, debug_buf):
|
||||||
def __init__(self, tx_fifos, debug_buf):
|
|
||||||
self.tx_enable = Signal()
|
self.tx_enable = Signal()
|
||||||
|
|
||||||
self.oe = Signal()
|
self.oe = Signal()
|
||||||
|
self.ce = Signal()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.startup_fsm = startup_fsm = FSM(reset_state="WAIT_TX_ENABLE")
|
self.submodules.startup_fsm = startup_fsm = CEInserter()(FSM(reset_state="WAIT_TX_ENABLE"))
|
||||||
self.submodules.encoder = encoder = SingleEncoder(True)
|
self.submodules.encoder = encoder = CEInserter()(SingleEncoder(True))
|
||||||
|
self.comb += [
|
||||||
|
startup_fsm.ce.eq(self.ce),
|
||||||
|
encoder.ce.eq(self.ce),
|
||||||
|
]
|
||||||
|
|
||||||
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.like(tx_fifos.pe.o)
|
priorities = Signal.like(interface.pe.o)
|
||||||
|
|
||||||
# DEBUG:
|
# DEBUG:
|
||||||
self.idling = Signal()
|
self.idling = Signal()
|
||||||
|
@ -143,20 +149,25 @@ class Packets_Scheduler(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# hold ack for only one sys clk cycle to prevent data loss
|
||||||
|
for ack in interface.sink_ack:
|
||||||
|
self.sync += ack.eq(0)
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
If(self.oe,
|
debug_buf.sink_stb.eq(0),
|
||||||
|
If(self.oe & self.ce,
|
||||||
encoder.disp_in.eq(encoder.disp_out),
|
encoder.disp_in.eq(encoder.disp_out),
|
||||||
If((~tx_fifos.pe.n) & (tx_fifos.pe.o == 0),
|
If((~interface.pe.n) & (interface.pe.o == 0),
|
||||||
# trigger packets are inserted at char boundary and don't contribute to word count
|
# trigger packets are inserted at char boundary and don't contribute to word count
|
||||||
tx_fifos.source_ack[0].eq(1),
|
interface.sink_ack[0].eq(1),
|
||||||
encoder.d.eq(tx_fifos.source_data[0]),
|
encoder.d.eq(interface.sink_data[0]),
|
||||||
encoder.k.eq(tx_fifos.source_k[0]),
|
encoder.k.eq(interface.sink_k[0]),
|
||||||
|
|
||||||
# DEBUG:
|
# DEBUG:
|
||||||
If(debug_buf.sink_ack,
|
If(debug_buf.sink_ack,
|
||||||
debug_buf.sink_stb.eq(1),
|
debug_buf.sink_stb.eq(1),
|
||||||
debug_buf.sink_data.eq(tx_fifos.source_data[0]),
|
debug_buf.sink_data.eq(interface.sink_data[0]),
|
||||||
debug_buf.sink_k.eq(tx_fifos.source_k[0]),
|
debug_buf.sink_k.eq(interface.sink_k[0]),
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
If(tx_charcount == 3,
|
If(tx_charcount == 3,
|
||||||
|
@ -164,20 +175,20 @@ class Packets_Scheduler(Module):
|
||||||
|
|
||||||
# Section 9.2.4 (CXP-001-2021)
|
# Section 9.2.4 (CXP-001-2021)
|
||||||
# other priorities packets are inserted at word boundary
|
# other priorities packets are inserted at word boundary
|
||||||
If((~tx_fifos.pe.n) & (tx_wordcount != 9999),
|
If((~interface.pe.n) & (tx_wordcount != 9999),
|
||||||
idling.eq(0),
|
idling.eq(0),
|
||||||
priorities.eq(tx_fifos.pe.o),
|
priorities.eq(interface.pe.o),
|
||||||
tx_wordcount.eq(tx_wordcount + 1),
|
tx_wordcount.eq(tx_wordcount + 1),
|
||||||
|
|
||||||
tx_fifos.source_ack[tx_fifos.pe.o].eq(1),
|
interface.sink_ack[interface.pe.o].eq(1),
|
||||||
encoder.d.eq(tx_fifos.source_data[tx_fifos.pe.o]),
|
encoder.d.eq(interface.sink_data[interface.pe.o]),
|
||||||
encoder.k.eq(tx_fifos.source_k[tx_fifos.pe.o]),
|
encoder.k.eq(interface.sink_k[interface.pe.o]),
|
||||||
|
|
||||||
# DEBUG:
|
# DEBUG:
|
||||||
If(debug_buf.sink_ack,
|
If(debug_buf.sink_ack,
|
||||||
debug_buf.sink_stb.eq(1),
|
debug_buf.sink_stb.eq(1),
|
||||||
debug_buf.sink_data.eq(tx_fifos.source_data[tx_fifos.pe.o]),
|
debug_buf.sink_data.eq(interface.sink_data[interface.pe.o]),
|
||||||
debug_buf.sink_k.eq(tx_fifos.source_k[tx_fifos.pe.o]),
|
debug_buf.sink_k.eq(interface.sink_k[interface.pe.o]),
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
# Section 9.2.5.1 (CXP-001-2021)
|
# Section 9.2.5.1 (CXP-001-2021)
|
||||||
|
@ -198,15 +209,16 @@ class Packets_Scheduler(Module):
|
||||||
).Else(
|
).Else(
|
||||||
tx_charcount.eq(tx_charcount + 1),
|
tx_charcount.eq(tx_charcount + 1),
|
||||||
If(~idling,
|
If(~idling,
|
||||||
tx_fifos.source_ack[priorities].eq(1),
|
tx_wordcount.eq(tx_wordcount + 1),
|
||||||
encoder.d.eq(tx_fifos.source_data[priorities]),
|
interface.sink_ack[priorities].eq(1),
|
||||||
encoder.k.eq(tx_fifos.source_k[priorities]),
|
encoder.d.eq(interface.sink_data[priorities]),
|
||||||
|
encoder.k.eq(interface.sink_k[priorities]),
|
||||||
|
|
||||||
# DEBUG:
|
# DEBUG:
|
||||||
If(debug_buf.sink_ack,
|
If(debug_buf.sink_ack,
|
||||||
debug_buf.sink_stb.eq(1),
|
debug_buf.sink_stb.eq(1),
|
||||||
debug_buf.sink_data.eq(tx_fifos.source_data[priorities]),
|
debug_buf.sink_data.eq(interface.sink_data[priorities]),
|
||||||
debug_buf.sink_k.eq(tx_fifos.source_k[priorities]),
|
debug_buf.sink_k.eq(interface.sink_k[priorities]),
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
encoder.d.eq(IDLE_CHARS[tx_charcount + 1][0]),
|
encoder.d.eq(IDLE_CHARS[tx_charcount + 1][0]),
|
||||||
|
@ -226,11 +238,10 @@ class Packets_Scheduler(Module):
|
||||||
|
|
||||||
class PHY_Interface(Module):
|
class PHY_Interface(Module):
|
||||||
def __init__(self, layout, nsink):
|
def __init__(self, layout, nsink):
|
||||||
|
sink_stb = Signal(nsink)
|
||||||
self.source_stb = Signal(nsink)
|
self.sink_ack = Array(Signal() for _ in range(nsink))
|
||||||
self.source_ack = Array(Signal() for _ in range(nsink))
|
self.sink_data = Array(Signal(8) for _ in range(nsink))
|
||||||
self.source_data = Array(Signal(8) for _ in range(nsink))
|
self.sink_k = Array(Signal() for _ in range(nsink))
|
||||||
self.source_k = Array(Signal() for _ in range(nsink))
|
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
|
@ -239,28 +250,19 @@ class PHY_Interface(Module):
|
||||||
sink = stream.Endpoint(layout)
|
sink = stream.Endpoint(layout)
|
||||||
self.sinks += [sink]
|
self.sinks += [sink]
|
||||||
|
|
||||||
self.sync += [
|
self.comb += [
|
||||||
If(self.source_ack[i],
|
sink.ack.eq(self.sink_ack[i]),
|
||||||
# reset ack after asserted
|
sink_stb[i].eq(sink.stb),
|
||||||
# since upconn clk run much slower, the ack will be high for longer than expected which will result in data loss
|
self.sink_data[i].eq(sink.data),
|
||||||
self.source_ack[i].eq(0),
|
self.sink_k[i].eq(sink.k),
|
||||||
sink.ack.eq(1),
|
|
||||||
).Else(
|
|
||||||
sink.ack.eq(0),
|
|
||||||
),
|
|
||||||
|
|
||||||
self.source_stb[i].eq(sink.stb),
|
|
||||||
self.source_data[i].eq(sink.data),
|
|
||||||
self.source_k[i].eq(sink.k),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# FIFOs transmission priority
|
# FIFOs transmission priority
|
||||||
self.submodules.pe = PriorityEncoder(nsink)
|
self.submodules.pe = PriorityEncoder(nsink)
|
||||||
self.comb += self.pe.i.eq(self.source_stb)
|
self.comb += self.pe.i.eq(sink_stb)
|
||||||
|
|
||||||
class Debug_buffer(Module,AutoCSR):
|
class Debug_buffer(Module,AutoCSR):
|
||||||
def __init__(self, layout):
|
def __init__(self, layout):
|
||||||
|
|
||||||
self.sink_stb = Signal()
|
self.sink_stb = Signal()
|
||||||
self.sink_ack = Signal()
|
self.sink_ack = Signal()
|
||||||
self.sink_data = Signal(8)
|
self.sink_data = Signal(8)
|
||||||
|
@ -271,19 +273,10 @@ class Debug_buffer(Module,AutoCSR):
|
||||||
self.submodules.buf_out = buf_out = stream.SyncFIFO(layout, 128)
|
self.submodules.buf_out = buf_out = stream.SyncFIFO(layout, 128)
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
If(self.sink_stb,
|
buf_out.sink.stb.eq(self.sink_stb),
|
||||||
# reset ack after asserted
|
|
||||||
# since upconn clk run much slower, the stb will be high for longer than expected which will result in multiple data entry
|
|
||||||
self.sink_stb.eq(0),
|
|
||||||
buf_out.sink.stb.eq(1),
|
|
||||||
).Else(
|
|
||||||
buf_out.sink.stb.eq(0),
|
|
||||||
),
|
|
||||||
|
|
||||||
self.sink_ack.eq(buf_out.sink.ack),
|
self.sink_ack.eq(buf_out.sink.ack),
|
||||||
buf_out.sink.data.eq(self.sink_data),
|
buf_out.sink.data.eq(self.sink_data),
|
||||||
buf_out.sink.k.eq(self.sink_k),
|
buf_out.sink.k.eq(self.sink_k),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
self.inc = CSR()
|
self.inc = CSR()
|
||||||
|
@ -301,7 +294,7 @@ class Debug_buffer(Module,AutoCSR):
|
||||||
|
|
||||||
|
|
||||||
class CXP_UpConn_PHY(Module, AutoCSR):
|
class CXP_UpConn_PHY(Module, AutoCSR):
|
||||||
def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, layout, nsink=3):
|
def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, nsink=3):
|
||||||
self.bitrate2x_enable = Signal()
|
self.bitrate2x_enable = Signal()
|
||||||
self.clk_reset = Signal()
|
self.clk_reset = Signal()
|
||||||
|
|
||||||
|
@ -311,18 +304,18 @@ class CXP_UpConn_PHY(Module, AutoCSR):
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.cg = cg = UpConn_ClockGen(sys_clk_freq)
|
self.submodules.cg = cg = UpConn_ClockGen(sys_clk_freq)
|
||||||
self.submodules.interface = interface = PHY_Interface(layout, nsink)
|
self.submodules.interface = interface = PHY_Interface(upconn_layout, nsink)
|
||||||
|
|
||||||
self.sinks = interface.sinks
|
self.sinks = interface.sinks
|
||||||
|
|
||||||
# DEBUG:
|
# DEBUG:
|
||||||
self.submodules.debug_buf = debug_buf = Debug_buffer(layout)
|
self.submodules.debug_buf = debug_buf = Debug_buffer(upconn_layout)
|
||||||
|
|
||||||
self.submodules.scheduler = scheduler = Packets_Scheduler(interface, debug_buf)
|
self.submodules.scheduler = scheduler = Transmit_Scheduler(interface, debug_buf)
|
||||||
self.submodules.serdes = serdes = SERDES_10bits(pad)
|
self.submodules.serdes = serdes = SERDES_10bits(pad)
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.tx_busy.eq(interface.source_stb != 0),
|
self.tx_busy.eq(~interface.pe.n),
|
||||||
|
|
||||||
cg.reset.eq(self.clk_reset),
|
cg.reset.eq(self.clk_reset),
|
||||||
cg.freq2x_enable.eq(self.bitrate2x_enable),
|
cg.freq2x_enable.eq(self.bitrate2x_enable),
|
||||||
|
@ -355,8 +348,8 @@ class CXP_UpConn_PHY(Module, AutoCSR):
|
||||||
]
|
]
|
||||||
self.specials += [
|
self.specials += [
|
||||||
# # debug sma
|
# # debug sma
|
||||||
# Instance("OBUF", i_I=cg.clk, o_O=debug_sma.p_tx),
|
Instance("OBUF", i_I=serdes.o, o_O=debug_sma.p_tx),
|
||||||
# Instance("OBUF", i_I=cg.clk_10x, o_O=debug_sma.n_rx),
|
Instance("OBUF", i_I=cg.clk_10x, o_O=debug_sma.n_rx),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,25 +26,25 @@ pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
||||||
timer.delay_us(50_000);
|
timer.delay_us(50_000);
|
||||||
info!(
|
info!(
|
||||||
"tx_phaligndone = {} | rx_phaligndone = {}",
|
"tx_phaligndone = {} | rx_phaligndone = {}",
|
||||||
csr::cxp::downconn_txinit_phaligndone_read(),
|
csr::cxp::downconn_phy_txinit_phaligndone_read(),
|
||||||
csr::cxp::downconn_rxinit_phaligndone_read(),
|
csr::cxp::downconn_phy_rxinit_phaligndone_read(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// enable txdata tranmission thought MGTXTXP, required by PMA loopback
|
// enable txdata tranmission thought MGTXTXP, required by PMA loopback
|
||||||
csr::cxp::downconn_txenable_write(1);
|
csr::cxp::downconn_phy_txenable_write(1);
|
||||||
|
|
||||||
info!("waiting for rx to align...");
|
info!("waiting for rx to align...");
|
||||||
while csr::cxp::downconn_rx_ready_read() != 1 {}
|
while csr::cxp::downconn_phy_rx_ready_read() != 1 {}
|
||||||
info!("rx ready!");
|
info!("rx ready!");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// for _ in 0..20 {
|
// for _ in 0..20 {
|
||||||
// NOTE: raw bits
|
// NOTE: raw bits
|
||||||
// let data0 = csr::cxp::downconn_rxdata_0_read();
|
// let data0 = csr::cxp::downconn_phy_rxdata_0_read();
|
||||||
// let data1 = csr::cxp::downconn_rxdata_1_read();
|
// let data1 = csr::cxp::downconn_phy_rxdata_1_read();
|
||||||
// let data2 = csr::cxp::downconn_rxdata_2_read();
|
// let data2 = csr::cxp::downconn_phy_rxdata_2_read();
|
||||||
// let data3 = csr::cxp::downconn_rxdata_3_read();
|
// let data3 = csr::cxp::downconn_phy_rxdata_3_read();
|
||||||
// let rxready = csr::cxp::downconn_rx_ready_read();
|
// let rxready = csr::cxp::downconn_phy_rx_ready_read();
|
||||||
// timer.delay_us(100);
|
// timer.delay_us(100);
|
||||||
// if data0 == 0b0101111100 || data0 == 0b1010000011 {
|
// if data0 == 0b0101111100 || data0 == 0b1010000011 {
|
||||||
// println!(
|
// println!(
|
||||||
|
@ -72,24 +72,24 @@ pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
||||||
|
|
||||||
timer.delay_us(1_000_000);
|
timer.delay_us(1_000_000);
|
||||||
// NOTE: raw bits
|
// NOTE: raw bits
|
||||||
// let data0 = csr::cxp::downconn_rxdata_0_read();
|
// let data0 = csr::cxp::downconn_phy_rxdata_0_read();
|
||||||
// let data1 = csr::cxp::downconn_rxdata_1_read();
|
// let data1 = csr::cxp::downconn_phy_rxdata_1_read();
|
||||||
// let data2 = csr::cxp::downconn_rxdata_2_read();
|
// let data2 = csr::cxp::downconn_phy_rxdata_2_read();
|
||||||
// let data3 = csr::cxp::downconn_rxdata_3_read();
|
// let data3 = csr::cxp::downconn_phy_rxdata_3_read();
|
||||||
// println!(
|
// println!(
|
||||||
// "0b{:010b} {:010b} {:010b} {:010b}",
|
// "0b{:010b} {:010b} {:010b} {:010b}",
|
||||||
// data0, data1, data2, data3
|
// data0, data1, data2, data3
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// NOTE:decode data
|
// NOTE:decode data
|
||||||
// let data0_k = csr::cxp::downconn_decoded_k_0_read();
|
// let data0_k = csr::cxp::downconn_phy_decoded_k_0_read();
|
||||||
// let data1_k = csr::cxp::downconn_decoded_k_1_read();
|
// let data1_k = csr::cxp::downconn_phy_decoded_k_1_read();
|
||||||
// let data2_k = csr::cxp::downconn_decoded_k_2_read();
|
// let data2_k = csr::cxp::downconn_phy_decoded_k_2_read();
|
||||||
// let data3_k = csr::cxp::downconn_decoded_k_3_read();
|
// let data3_k = csr::cxp::downconn_phy_decoded_k_3_read();
|
||||||
let data0_decoded = csr::cxp::downconn_decoded_data_0_read();
|
let data0_decoded = csr::cxp::downconn_phy_decoded_data_0_read();
|
||||||
let data1_decoded = csr::cxp::downconn_decoded_data_1_read();
|
let data1_decoded = csr::cxp::downconn_phy_decoded_data_1_read();
|
||||||
let data2_decoded = csr::cxp::downconn_decoded_data_2_read();
|
let data2_decoded = csr::cxp::downconn_phy_decoded_data_2_read();
|
||||||
let data3_decoded = csr::cxp::downconn_decoded_data_3_read();
|
let data3_decoded = csr::cxp::downconn_phy_decoded_data_3_read();
|
||||||
println!(
|
println!(
|
||||||
"{:#04x} {:#04x} {:#04x} {:#04x}",
|
"{:#04x} {:#04x} {:#04x} {:#04x}",
|
||||||
data0_decoded, data1_decoded, data2_decoded, data3_decoded,
|
data0_decoded, data1_decoded, data2_decoded, data3_decoded,
|
||||||
|
@ -108,24 +108,24 @@ pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) {
|
||||||
pub fn setup(timer: &mut GlobalTimer) {
|
pub fn setup(timer: &mut GlobalTimer) {
|
||||||
unsafe {
|
unsafe {
|
||||||
info!("turning on pmc loopback mode...");
|
info!("turning on pmc loopback mode...");
|
||||||
csr::cxp::downconn_loopback_mode_write(0b010); // Near-End PMA Loopback
|
csr::cxp::downconn_phy_loopback_mode_write(0b010); // Near-End PMA Loopback
|
||||||
|
|
||||||
// QPLL setup
|
// QPLL setup
|
||||||
csr::cxp::downconn_qpll_reset_write(1);
|
csr::cxp::downconn_phy_qpll_reset_write(1);
|
||||||
info!("waiting for QPLL/CPLL to lock...");
|
info!("waiting for QPLL/CPLL to lock...");
|
||||||
while csr::cxp::downconn_qpll_locked_read() != 1 {}
|
while csr::cxp::downconn_phy_qpll_locked_read() != 1 {}
|
||||||
info!("QPLL locked");
|
info!("QPLL locked");
|
||||||
|
|
||||||
// tx/rx setup
|
// tx/rx setup
|
||||||
csr::cxp::downconn_tx_start_init_write(1);
|
csr::cxp::downconn_phy_tx_start_init_write(1);
|
||||||
csr::cxp::downconn_rx_start_init_write(1);
|
csr::cxp::downconn_phy_rx_start_init_write(1);
|
||||||
|
|
||||||
info!("waiting for tx & rx setup...");
|
info!("waiting for tx & rx setup...");
|
||||||
timer.delay_us(50_000);
|
timer.delay_us(50_000);
|
||||||
info!(
|
info!(
|
||||||
"tx_phaligndone = {} | rx_phaligndone = {}",
|
"tx_phaligndone = {} | rx_phaligndone = {}",
|
||||||
csr::cxp::downconn_txinit_phaligndone_read(),
|
csr::cxp::downconn_phy_txinit_phaligndone_read(),
|
||||||
csr::cxp::downconn_rxinit_phaligndone_read(),
|
csr::cxp::downconn_phy_rxinit_phaligndone_read(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,15 +153,15 @@ pub mod cxp_gtx {
|
||||||
change_cdr_cfg(speed);
|
change_cdr_cfg(speed);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_qpll_reset_write(1);
|
csr::cxp::downconn_phy_qpll_reset_write(1);
|
||||||
info!("waiting for QPLL/CPLL to lock...");
|
info!("waiting for QPLL/CPLL to lock...");
|
||||||
while csr::cxp::downconn_qpll_locked_read() != 1 {}
|
while csr::cxp::downconn_phy_qpll_locked_read() != 1 {}
|
||||||
info!("QPLL locked");
|
info!("QPLL locked");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_tx_restart_write(1);
|
csr::cxp::downconn_phy_tx_restart_write(1);
|
||||||
csr::cxp::downconn_rx_restart_write(1);
|
csr::cxp::downconn_phy_rx_restart_write(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,19 +245,19 @@ pub mod cxp_gtx {
|
||||||
fn gtx_read(address: u16) -> u16 {
|
fn gtx_read(address: u16) -> u16 {
|
||||||
// DEBUG:
|
// DEBUG:
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_gtx_daddr_write(address);
|
csr::cxp::downconn_phy_gtx_daddr_write(address);
|
||||||
csr::cxp::downconn_gtx_dread_write(1);
|
csr::cxp::downconn_phy_gtx_dread_write(1);
|
||||||
while csr::cxp::downconn_gtx_dready_read() != 1 {}
|
while csr::cxp::downconn_phy_gtx_dready_read() != 1 {}
|
||||||
csr::cxp::downconn_gtx_dout_read()
|
csr::cxp::downconn_phy_gtx_dout_read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtx_write(address: u16, value: u16) {
|
fn gtx_write(address: u16, value: u16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_gtx_daddr_write(address);
|
csr::cxp::downconn_phy_gtx_daddr_write(address);
|
||||||
csr::cxp::downconn_gtx_din_write(value);
|
csr::cxp::downconn_phy_gtx_din_write(value);
|
||||||
csr::cxp::downconn_gtx_din_stb_write(1);
|
csr::cxp::downconn_phy_gtx_din_stb_write(1);
|
||||||
while csr::cxp::downconn_gtx_dready_read() != 1 {}
|
while csr::cxp::downconn_phy_gtx_dready_read() != 1 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,19 +265,19 @@ pub mod cxp_gtx {
|
||||||
fn qpll_read(address: u8) -> u16 {
|
fn qpll_read(address: u8) -> u16 {
|
||||||
// DEBUG:
|
// DEBUG:
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_qpll_daddr_write(address);
|
csr::cxp::downconn_phy_qpll_daddr_write(address);
|
||||||
csr::cxp::downconn_qpll_dread_write(1);
|
csr::cxp::downconn_phy_qpll_dread_write(1);
|
||||||
while csr::cxp::downconn_qpll_dready_read() != 1 {}
|
while csr::cxp::downconn_phy_qpll_dready_read() != 1 {}
|
||||||
csr::cxp::downconn_qpll_dout_read()
|
csr::cxp::downconn_phy_qpll_dout_read()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn qpll_write(address: u8, value: u16) {
|
fn qpll_write(address: u8, value: u16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_qpll_daddr_write(address);
|
csr::cxp::downconn_phy_qpll_daddr_write(address);
|
||||||
csr::cxp::downconn_qpll_din_write(value);
|
csr::cxp::downconn_phy_qpll_din_write(value);
|
||||||
csr::cxp::downconn_qpll_din_stb_write(1);
|
csr::cxp::downconn_phy_qpll_din_stb_write(1);
|
||||||
while csr::cxp::downconn_qpll_dready_read() != 1 {}
|
while csr::cxp::downconn_phy_qpll_dready_read() != 1 {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,43 +301,43 @@ pub mod txusrclk {
|
||||||
|
|
||||||
fn one_clock_cycle() {
|
fn one_clock_cycle() {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_pll_dclk_write(1);
|
csr::cxp::downconn_phy_pll_dclk_write(1);
|
||||||
csr::cxp::downconn_pll_dclk_write(0);
|
csr::cxp::downconn_phy_pll_dclk_write(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_addr(address: u8) {
|
fn set_addr(address: u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_pll_daddr_write(address);
|
csr::cxp::downconn_phy_pll_daddr_write(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_data(value: u16) {
|
fn set_data(value: u16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::cxp::downconn_pll_din_write(value);
|
csr::cxp::downconn_phy_pll_din_write(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_enable(en: bool) {
|
fn set_enable(en: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = if en { 1 } else { 0 };
|
let val = if en { 1 } else { 0 };
|
||||||
csr::cxp::downconn_pll_den_write(val);
|
csr::cxp::downconn_phy_pll_den_write(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_write_enable(en: bool) {
|
fn set_write_enable(en: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = if en { 1 } else { 0 };
|
let val = if en { 1 } else { 0 };
|
||||||
csr::cxp::downconn_pll_dwen_write(val);
|
csr::cxp::downconn_phy_pll_dwen_write(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_data() -> u16 {
|
fn get_data() -> u16 {
|
||||||
unsafe { csr::cxp::downconn_pll_dout_read() }
|
unsafe { csr::cxp::downconn_phy_pll_dout_read() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drp_ready() -> bool {
|
fn drp_ready() -> bool {
|
||||||
unsafe { csr::cxp::downconn_pll_dready_read() == 1 }
|
unsafe { csr::cxp::downconn_phy_pll_dready_read() == 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -374,7 +374,7 @@ pub mod txusrclk {
|
||||||
fn reset(rst: bool) {
|
fn reset(rst: bool) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = if rst { 1 } else { 0 };
|
let val = if rst { 1 } else { 0 };
|
||||||
csr::cxp::downconn_txpll_reset_write(val)
|
csr::cxp::downconn_phy_txpll_reset_write(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +411,7 @@ pub mod txusrclk {
|
||||||
// wait for the pll to lock
|
// wait for the pll to lock
|
||||||
timer.delay_us(100);
|
timer.delay_us(100);
|
||||||
|
|
||||||
let locked = unsafe { csr::cxp::downconn_txpll_locked_read() == 1 };
|
let locked = unsafe { csr::cxp::downconn_phy_txpll_locked_read() == 1 };
|
||||||
info!("txusrclk locked = {}", locked);
|
info!("txusrclk locked = {}", locked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,3 +540,5 @@ pub mod txusrclk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: add recv like in drtioaux
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
use core_io::{Error as IoError, Write};
|
||||||
|
use crc::crc32;
|
||||||
|
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||||
|
use io::Cursor;
|
||||||
|
use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
|
|
||||||
|
use crate::pl::csr;
|
||||||
|
|
||||||
|
const MAX_PACKET: usize = 128;
|
||||||
|
const DATA_MAXSIZE: usize = /*max size*/MAX_PACKET - /*Tag*/4 - /*Op code & length*/4 - /*addr*/4 - /*CRC*/4 ;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
BufferError,
|
||||||
|
LinkDown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IoError> for Error {
|
||||||
|
fn from(_: IoError) -> Error {
|
||||||
|
Error::BufferError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Packet {
|
||||||
|
CtrlRead {
|
||||||
|
addr: u32,
|
||||||
|
length: u8,
|
||||||
|
},
|
||||||
|
CtrlWrite {
|
||||||
|
addr: u32,
|
||||||
|
length: u8,
|
||||||
|
data: [u8; DATA_MAXSIZE],
|
||||||
|
}, // max register size is 8 bytes
|
||||||
|
CtrlReadWithTag {
|
||||||
|
tag: u8,
|
||||||
|
addr: u32,
|
||||||
|
length: u8,
|
||||||
|
},
|
||||||
|
CtrlWriteWithTag {
|
||||||
|
tag: u8,
|
||||||
|
addr: u32,
|
||||||
|
length: u8,
|
||||||
|
data: [u8; DATA_MAXSIZE],
|
||||||
|
}, // max register size is 8 bytes
|
||||||
|
EventAck {
|
||||||
|
packet_tag: u8,
|
||||||
|
},
|
||||||
|
TestPacket,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Packet {
|
||||||
|
pub fn write_to(&self, writer: &mut Cursor<&mut [u8]>) -> Result<(), Error> {
|
||||||
|
// CoaXpress use big endian
|
||||||
|
match *self {
|
||||||
|
Packet::CtrlRead { addr, length } => {
|
||||||
|
writer.write(&[0x02; 4])?;
|
||||||
|
writer.write(&[0x00, 0x00, 0x00, length])?;
|
||||||
|
writer.write(&addr.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
Packet::CtrlWrite { addr, length, data } => {
|
||||||
|
writer.write(&[0x02; 4])?;
|
||||||
|
writer.write(&[0x01, 0x00, 0x00, length])?;
|
||||||
|
writer.write(&addr.to_be_bytes())?;
|
||||||
|
writer.write(&data[0..length as usize])?;
|
||||||
|
}
|
||||||
|
Packet::CtrlReadWithTag { tag, addr, length } => {
|
||||||
|
writer.write(&[0x05; 4])?;
|
||||||
|
writer.write(&[tag; 4])?;
|
||||||
|
writer.write(&[0x00, 0x00, 0x00, length])?;
|
||||||
|
writer.write(&addr.to_be_bytes())?;
|
||||||
|
}
|
||||||
|
Packet::CtrlWriteWithTag {
|
||||||
|
tag,
|
||||||
|
addr,
|
||||||
|
length,
|
||||||
|
data,
|
||||||
|
} => {
|
||||||
|
writer.write(&[0x05; 4])?;
|
||||||
|
writer.write(&[tag; 4])?;
|
||||||
|
writer.write(&[0x01, 0x00, 0x00, length])?;
|
||||||
|
writer.write(&addr.to_be_bytes())?;
|
||||||
|
writer.write(&data[0..length as usize])?;
|
||||||
|
}
|
||||||
|
Packet::EventAck { packet_tag } => {
|
||||||
|
writer.write(&[0x08; 4])?;
|
||||||
|
writer.write(&[packet_tag; 4])?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
// Section 9.2.2.2 (CXP-001-2021)
|
||||||
|
// Only Control packet need CRC32 appended in the end of the packet
|
||||||
|
// CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different
|
||||||
|
// Also, the calculation does not include the first 4 bytes of packet_type
|
||||||
|
match *self {
|
||||||
|
Packet::CtrlRead { .. }
|
||||||
|
| Packet::CtrlWrite { .. }
|
||||||
|
| Packet::CtrlReadWithTag { .. }
|
||||||
|
| Packet::CtrlWriteWithTag { .. } => {
|
||||||
|
let checksum = crc32::checksum_ieee(&writer.get_ref()[4..writer.position()]);
|
||||||
|
writer.write(&(!checksum).to_le_bytes())?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(packet: &Packet) -> Result<(), Error> {
|
||||||
|
if unsafe { csr::cxp::upconn_tx_enable_read() } == 0 {
|
||||||
|
Err(Error::LinkDown)?
|
||||||
|
}
|
||||||
|
|
||||||
|
match *packet {
|
||||||
|
Packet::TestPacket => send_test_packet(),
|
||||||
|
_ => send_data_packet(packet),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_data_packet(packet: &Packet) -> Result<(), Error> {
|
||||||
|
let mut buffer: [u8; MAX_PACKET] = [0; MAX_PACKET];
|
||||||
|
let mut writer = Cursor::new(&mut buffer[..]);
|
||||||
|
|
||||||
|
packet.write_to(&mut writer)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let len = writer.position();
|
||||||
|
csr::cxp::upconn_command_len_write(len as u8);
|
||||||
|
for data in writer.get_ref()[..len].iter() {
|
||||||
|
while csr::cxp::upconn_command_writeable_read() == 0 {}
|
||||||
|
csr::cxp::upconn_command_data_write(*data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_test_packet() -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
while csr::cxp::upconn_tx_busy_read() == 1 {}
|
||||||
|
csr::cxp::upconn_tx_testmode_en_write(1);
|
||||||
|
// timer.delay_us(2);
|
||||||
|
csr::cxp::upconn_testseq_stb_write(1);
|
||||||
|
while csr::cxp::upconn_testseq_busy_read() == 1 {}
|
||||||
|
csr::cxp::upconn_tx_testmode_en_write(0);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_u32(addr: u32, data: u32) -> Result<(), Error> {
|
||||||
|
let mut data_slice: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
||||||
|
data_slice[..4].clone_from_slice(&data.to_be_bytes());
|
||||||
|
send(&Packet::CtrlWrite {
|
||||||
|
addr,
|
||||||
|
length: 4,
|
||||||
|
data: data_slice,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_u32(addr: u32) -> Result<(), Error> {
|
||||||
|
send(&Packet::CtrlRead { addr, length: 4 })?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_u64(addr: u32, data: u64) -> Result<(), Error> {
|
||||||
|
let mut data_slice: [u8; DATA_MAXSIZE] = [0; DATA_MAXSIZE];
|
||||||
|
data_slice[..8].clone_from_slice(&data.to_be_bytes());
|
||||||
|
send(&Packet::CtrlWrite {
|
||||||
|
addr,
|
||||||
|
length: 8,
|
||||||
|
data: data_slice,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG: use only
|
||||||
|
pub fn print_packet(pak: &[u8]) {
|
||||||
|
println!("pak = [");
|
||||||
|
for i in 0..(pak.len() / 4) {
|
||||||
|
println!(
|
||||||
|
"{:#03} {:#04X} {:#04X} {:#04X} {:#04X},",
|
||||||
|
i + 1,
|
||||||
|
pak[i * 4],
|
||||||
|
pak[i * 4 + 1],
|
||||||
|
pak[i * 4 + 2],
|
||||||
|
pak[i * 4 + 3]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println!("]");
|
||||||
|
println!("============================================");
|
||||||
|
}
|
|
@ -4,22 +4,11 @@ use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
|
||||||
use io::Cursor;
|
use io::Cursor;
|
||||||
use libboard_zynq::{println, timer::GlobalTimer};
|
use libboard_zynq::{println, timer::GlobalTimer};
|
||||||
|
|
||||||
|
pub use crate::cxp_proto;
|
||||||
use crate::pl::csr;
|
use crate::pl::csr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
BufferError,
|
|
||||||
LinkDown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IoError> for Error {
|
|
||||||
fn from(_: IoError) -> Error {
|
|
||||||
Error::BufferError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tx_test(timer: &mut GlobalTimer) {
|
pub fn tx_test(timer: &mut GlobalTimer) {
|
||||||
const LEN: usize = 4 * 20;
|
const LEN: usize = 4 * 50;
|
||||||
let mut pak_arr: [u8; LEN] = [0; LEN];
|
let mut pak_arr: [u8; LEN] = [0; LEN];
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -27,154 +16,36 @@ pub fn tx_test(timer: &mut GlobalTimer) {
|
||||||
// csr::cxp::upconn_bitrate2x_enable_write(1);
|
// csr::cxp::upconn_bitrate2x_enable_write(1);
|
||||||
csr::cxp::upconn_clk_reset_write(0);
|
csr::cxp::upconn_clk_reset_write(0);
|
||||||
|
|
||||||
send(&Packet::ControlU32Reg(Command::Read { addr: 0x00 })).expect("Cannot send CoaXpress packet");
|
// read_u32(0x00).expect("Cannot Write CoaXpress Register");
|
||||||
|
|
||||||
csr::cxp::upconn_tx_enable_write(1);
|
csr::cxp::upconn_tx_enable_write(1);
|
||||||
|
timer.delay_us(2); // send one word
|
||||||
|
cxp_proto::send(&cxp_proto::Packet::EventAck { packet_tag: 0x04 }).expect("Cannot send CoaXpress packet");
|
||||||
|
// cxp_proto::send(&cxp_proto::Packet::TestPacket).expect("Cannot send CoaXpress packet");
|
||||||
|
|
||||||
timer.delay_us(2);
|
// timer.delay_us(2);
|
||||||
// DEBUG: Trigger packet
|
// DEBUG: Trigger packet
|
||||||
let linktrig_mode: u8 = 0x01;
|
// let linktrig_mode: u8 = 0x01;
|
||||||
csr::cxp::upconn_trig_delay_write(0x05);
|
// csr::cxp::upconn_trig_delay_write(0x05);
|
||||||
csr::cxp::upconn_linktrigger_write(linktrig_mode);
|
// csr::cxp::upconn_linktrigger_write(linktrig_mode);
|
||||||
csr::cxp::upconn_trig_stb_write(1); // send trig
|
// csr::cxp::upconn_trig_stb_write(1); // send trig
|
||||||
|
|
||||||
// DEBUG: Trigger ACK packet
|
// DEBUG: Trigger ACK packet
|
||||||
// csr::cxp::upconn_ack_write(1);
|
// csr::cxp::upconn_ack_write(1);
|
||||||
timer.delay_us(20);
|
timer.delay_us(20);
|
||||||
|
|
||||||
csr::cxp::upconn_tx_enable_write(0);
|
csr::cxp::upconn_tx_enable_write(0);
|
||||||
|
|
||||||
// Collect data
|
// Collect data
|
||||||
let mut i: usize = 0;
|
let mut i: usize = 0;
|
||||||
while csr::cxp::upconn_upconn_phy_debug_buf_dout_valid_read() == 1 {
|
while csr::cxp::upconn_phy_debug_buf_dout_valid_read() == 1 {
|
||||||
pak_arr[i] = csr::cxp::upconn_upconn_phy_debug_buf_dout_pak_read();
|
pak_arr[i] = csr::cxp::upconn_phy_debug_buf_dout_pak_read();
|
||||||
// println!("received {:#04X}", pak_arr[i]);
|
// println!("received {:#04X}", pak_arr[i]);
|
||||||
csr::cxp::upconn_upconn_phy_debug_buf_inc_write(1);
|
csr::cxp::upconn_phy_debug_buf_inc_write(1);
|
||||||
i += 1;
|
i += 1;
|
||||||
if i == LEN {
|
if i == LEN {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_packet(&pak_arr);
|
cxp_proto::print_packet(&pak_arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Command<T> {
|
|
||||||
Read { addr: u32 },
|
|
||||||
Write { addr: u32, data: T },
|
|
||||||
ReadWithTag { addr: u32, tag: u8 },
|
|
||||||
WriteWithTag { addr: u32, data: T, tag: u8 },
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Packet {
|
|
||||||
ControlU32Reg(Command<u32>),
|
|
||||||
ControlU64Reg(Command<u64>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Packet {
|
|
||||||
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
|
|
||||||
where W: Write {
|
|
||||||
match self {
|
|
||||||
Packet::ControlU32Reg(cmd) => match cmd {
|
|
||||||
Command::Read { addr } => {
|
|
||||||
writer.write(&[0x02; 4])?;
|
|
||||||
writer.write(&[0x00, 0x00, 0x00, 0x04])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
Command::Write { addr, data } => {
|
|
||||||
writer.write(&[0x02; 4])?;
|
|
||||||
writer.write(&[0x01, 0x00, 0x00, 0x04])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
writer.write(&data.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
Command::ReadWithTag { addr, tag } => {
|
|
||||||
writer.write(&[0x05; 4])?;
|
|
||||||
writer.write(&[*tag; 4])?;
|
|
||||||
writer.write(&[0x00, 0x00, 0x00, 0x04])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
Command::WriteWithTag { addr, data, tag } => {
|
|
||||||
writer.write(&[0x05; 4])?;
|
|
||||||
writer.write(&[*tag; 4])?;
|
|
||||||
writer.write(&[0x01, 0x00, 0x00, 0x04])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
writer.write(&data.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Packet::ControlU64Reg(cmd) => match cmd {
|
|
||||||
Command::Read { addr } => {
|
|
||||||
writer.write(&[0x02; 4])?;
|
|
||||||
writer.write(&[0x00, 0x00, 0x00, 0x08])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
Command::Write { addr, data } => {
|
|
||||||
writer.write(&[0x02; 4])?;
|
|
||||||
writer.write(&[0x01, 0x00, 0x00, 0x08])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
writer.write(&data.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
Command::ReadWithTag { addr, tag } => {
|
|
||||||
writer.write(&[0x05; 4])?;
|
|
||||||
writer.write(&[*tag; 4])?;
|
|
||||||
writer.write(&[0x00, 0x00, 0x00, 0x08])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
Command::WriteWithTag { addr, data, tag } => {
|
|
||||||
writer.write(&[0x05; 4])?;
|
|
||||||
writer.write(&[*tag; 4])?;
|
|
||||||
writer.write(&[0x01, 0x00, 0x00, 0x08])?;
|
|
||||||
writer.write(&addr.to_be_bytes())?;
|
|
||||||
writer.write(&data.to_be_bytes())?;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send(packet: &Packet) -> Result<(), Error> {
|
|
||||||
// DEBUG: remove the comment out section
|
|
||||||
// if unsafe { csr::cxp::upconn_tx_enable_read() } == 0 {
|
|
||||||
// Err(Error::LinkDown)?
|
|
||||||
// }
|
|
||||||
|
|
||||||
const LEN: usize = 4 * 20;
|
|
||||||
let mut buffer: [u8; LEN] = [0; LEN];
|
|
||||||
let mut writer = Cursor::new(&mut buffer[..]);
|
|
||||||
|
|
||||||
packet.write_to(&mut writer)?;
|
|
||||||
|
|
||||||
// Section 9.2.2.2 (CXP-001-2021)
|
|
||||||
// CoaXpress use the polynomial of IEEE-802.3 (Ethernet) CRC but the checksum calculation is different
|
|
||||||
// Also, the calculation does not include the first 4 bytes of packet_type
|
|
||||||
let checksum = crc32::checksum_ieee(&writer.get_ref()[4..writer.position()]);
|
|
||||||
writer.write(&(!checksum).to_le_bytes())?;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let len = writer.position();
|
|
||||||
csr::cxp::upconn_command_len_write(len as u8);
|
|
||||||
for data in writer.get_ref()[..len].iter() {
|
|
||||||
while csr::cxp::upconn_command_writeable_read() == 0 {}
|
|
||||||
csr::cxp::upconn_command_data_write(*data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_packet(pak: &[u8]) {
|
|
||||||
println!("pak = [");
|
|
||||||
for i in 0..(pak.len() / 4) {
|
|
||||||
println!(
|
|
||||||
"{:#03} {:#04X} {:#04X} {:#04X} {:#04X},",
|
|
||||||
i + 1,
|
|
||||||
pak[i * 4],
|
|
||||||
pak[i * 4 + 1],
|
|
||||||
pak[i * 4 + 2],
|
|
||||||
pak[i * 4 + 3]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
println!("]");
|
|
||||||
println!("============================================");
|
|
||||||
}
|
|
||||||
|
|
|
@ -47,6 +47,8 @@ pub mod cxp_downconn;
|
||||||
#[cfg(has_cxp)]
|
#[cfg(has_cxp)]
|
||||||
pub mod cxp_upconn;
|
pub mod cxp_upconn;
|
||||||
|
|
||||||
|
pub mod cxp_proto;
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -150,5 +150,16 @@ pub fn main_core0() {
|
||||||
|
|
||||||
task::spawn(ksupport::report_async_rtio_errors());
|
task::spawn(ksupport::report_async_rtio_errors());
|
||||||
|
|
||||||
|
use libboard_artiq::{cxp_downconn, cxp_upconn};
|
||||||
|
cxp_downconn::setup(&mut timer);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_1);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_2);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_3);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_5);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_6);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_10);
|
||||||
|
// cxp_downconn::loopback_testing(&mut timer, cxp_downconn::CXP_SPEED::CXP_12);
|
||||||
|
cxp_upconn::tx_test(&mut timer);
|
||||||
|
|
||||||
comms::main(timer, cfg);
|
comms::main(timer, cfg);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue