1
0
Fork 0

Compare commits

..

8 Commits

Author SHA1 Message Date
morgan 074e8e94d1 cxp downconn firmware: GTX setup
testing: add loopmode mode & tsusrclk mmcm drp bitbang
testing: add IDLE word printout
downconn: add QPLL and GTX setup
downconn: add DRP to support all CXP linerate up to 12.5Gbps
2024-09-05 17:24:43 +08:00
morgan 354949baab cxp upconn firmware: low speed serial setup
testing: add trigger & trigger ack CSR to test tranmission prioirty
upconn: add some upconn error for control flow
upconn: add control packet writer
control packet: add u32 & u64 register control
control packet: add CRC calculation & packet type inserter in fw
2024-09-05 17:24:43 +08:00
morgan b534129d08 zc706: add CXP_DEMO variant
zc706: add fmc pads
zc706: add constraint to fix comma alignment & setup/hold time issue
2024-09-05 17:21:09 +08:00
morgan 0f4a8754c3 cxp: add upconn interface, downconn PHY & crc
testing: add CSR control for tx trigger & trigger ack
upconn: connect trigger, trigger ack & command_packet to UpConnPHY
downconn: add GTX PHY
2024-09-05 17:21:09 +08:00
morgan d5096781d3 cxp pipeline: packet handling pipeline
tx pipeline: add CRC32 inserter
tx pipeline: add start & end of packet code inserter
tx pipeline: add packet wrapper for start & stop packet indication
tx pipeline: add code source for trigger & trigger ack packet
tx pipeline: add packet for trigger & trigger ack
tx pipeline: add tx_command_packet for firmware
tx command packet: add fifo to store control packet
2024-09-05 17:16:29 +08:00
morgan 030c4c13b9 cxp upconn gw: add low speed serial PHY
testing: add debug fifo output b4 encoder
cxp upconn: add low speed serial
cxp upconn: add reset, tx_busy, tx_enable
cxp upconn: add clockgen module for 20.83Mbps & 41.66Mbps using counters
cxp upconn: add oserdes using CEInserter
cxp upconn: add packet scheduler with CEInserter
scheduler: send priority packet during word/char boundary
scheduler: send IDLE every 10000 words
scheduler: encode packet before sending to oserdes
2024-09-05 17:07:59 +08:00
morgan 223c32a4dc cxp downconn gw: add gtx up to 12.5Gbps
testing: add txusrclk mmcm & loopback mode
testing: add debug output
downconn: add GTX and QPLL support
downconn: add DRP for GTX and QPLL to support all CXP linerates
GTX: add gtx with mmcm for TXUSRCLK freq requirement
GTX: add loopback mode parameter for testing
GTX: add gtx with 40bits internal width
GTX: use built-in comma aligner
GTX: add comma checker to ensure comma is aligner on highest linerate
GTX: set QPLL as CLK source for GTX
2024-09-05 17:07:38 +08:00
morgan 46f88a7793 fmc: add cxp_4r_fmc adepter io 2024-09-05 17:06:07 +08:00
4 changed files with 72 additions and 163 deletions

View File

@ -17,18 +17,17 @@ class CXP(Module, AutoCSR):
class UpConn_Interface(Module, AutoCSR): class UpConn_Interface(Module, AutoCSR):
def __init__(self, upconn_pads, sys_clk_freq, debug_sma, pmod_pads, fifos_depth=64): def __init__(self, upconn_pads, sys_clk_freq, debug_sma, pmod_pads):
self.clk_reset = CSRStorage(reset=1) self.clk_reset = CSRStorage(reset=1)
self.bitrate2x_enable = CSRStorage() self.bitrate2x_enable = CSRStorage()
self.tx_enable = CSRStorage() self.tx_enable = CSRStorage()
self.tx_busy = CSRStatus() self.tx_busy = CSRStatus()
self.encoded_data = CSRStatus(10)
# # # # # #
layout = [("data", 8), ("k", 1)] layout = [("data", 8), ("k", 1)]
self.submodules.upconn_phy = upconn_phy = CXP_UpConn_PHY(upconn_pads, sys_clk_freq, debug_sma, pmod_pads, layout, fifos_depth) 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), upconn_phy.bitrate2x_enable.eq(self.bitrate2x_enable.storage),
@ -36,14 +35,12 @@ class UpConn_Interface(Module, AutoCSR):
upconn_phy.clk_reset.eq(self.clk_reset.re), upconn_phy.clk_reset.eq(self.clk_reset.re),
self.tx_busy.status.eq(upconn_phy.tx_busy), self.tx_busy.status.eq(upconn_phy.tx_busy),
] ]
self.sync += [
self.encoded_data.status.eq(upconn_phy.scheduler.encoder.output),
]
# Packet FIFOs with transmission priority # Packet FIFOs with transmission priority
# NOTE: 0 Trigger packet # 0: Trigger packet
self.submodules.trig = trig = TX_Trigger(layout) self.submodules.trig = trig = TX_Trigger(layout)
self.comb += trig.source.connect(upconn_phy.sinks[0])
# DEBUG: INPUT # DEBUG: INPUT
self.trig_stb = CSR() self.trig_stb = CSR()
@ -56,97 +53,17 @@ class UpConn_Interface(Module, AutoCSR):
trig.linktrig_mode.eq(self.linktrigger.storage), trig.linktrig_mode.eq(self.linktrigger.storage),
] ]
# DEBUG: OUTPUT
self.submodules.trig_out = trig_out = stream.SyncFIFO(layout, 64)
self.comb += trig.source.connect(trig_out.sink)
self.trig_inc = CSR()
self.trig_dout_pak = CSRStatus(8)
self.trig_kout_pak = CSRStatus()
self.trig_dout_valid = CSRStatus()
self.sync += [
# output
trig_out.source.ack.eq(self.trig_inc.re),
self.trig_dout_pak.status.eq(trig_out.source.data),
self.trig_kout_pak.status.eq(trig_out.source.k),
self.trig_dout_valid.status.eq(trig_out.source.stb),
]
self.symbol0 = CSR(9)
self.sync += [
upconn_phy.tx_fifos.sink[0].stb.eq(self.symbol0.re),
upconn_phy.tx_fifos.sink[0].data.eq(self.symbol0.r[:8]),
upconn_phy.tx_fifos.sink[0].k.eq(self.symbol0.r[8]),
]
# NOTE: 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(layout)
self.comb += trig_ack.source.connect(upconn_phy.sinks[1])
# DEBUG: INPUT # DEBUG: INPUT
self.ack = CSR() self.ack = CSR()
self.sync += [ self.sync += trig_ack.ack.eq(self.ack.re),
trig_ack.ack.eq(self.ack.re),
]
# DEBUG: OUTPUT
self.submodules.trig_ack_out = trig_ack_out = stream.SyncFIFO(layout, 64)
self.comb += trig_ack.source.connect(trig_ack_out.sink)
self.trig_ack_inc = CSR()
self.trig_ack_dout_pak = CSRStatus(8)
self.trig_ack_kout_pak = CSRStatus()
self.trig_ack_dout_valid = CSRStatus()
self.sync += [ # 2: All other packets
# output
trig_ack_out.source.ack.eq(self.trig_ack_inc.re),
self.trig_ack_dout_pak.status.eq(trig_ack_out.source.data),
self.trig_ack_kout_pak.status.eq(trig_ack_out.source.k),
self.trig_ack_dout_valid.status.eq(trig_ack_out.source.stb),
]
self.symbol1 = CSR(9)
self.sync += [
upconn_phy.tx_fifos.sink[1].stb.eq(self.symbol1.re),
upconn_phy.tx_fifos.sink[1].data.eq(self.symbol1.r[:8]),
upconn_phy.tx_fifos.sink[1].k.eq(self.symbol1.r[8]),
]
# NOTE: 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
# Table 54 (CXP-001-2021)
# Largest CXP register is 8 byte
# increment after ack
# for CXP 2.0 or latest, command packet need to includet tags
# section 9.6.1.2 (CXP-001-2021)
# tags implementation is on firmware
self.submodules.command = command = TX_Command_Packet(layout) self.submodules.command = command = TX_Command_Packet(layout)
self.comb += command.source.connect(upconn_phy.tx_fifos.sink[2]) self.comb += command.source.connect(upconn_phy.sinks[2])
# DEBUG: OUTPUT
# self.submodules.command_out = command_out = stream.SyncFIFO(layout, 64)
# self.comb += command.source.connect(command_out.sink)
# self.command_inc = CSR()
# self.command_dout_pak = CSRStatus(8)
# self.command_kout_pak = CSRStatus()
# self.command_dout_valid = CSRStatus()
# self.sync += [
# # output
# command_out.source.ack.eq(self.command_inc.re),
# self.command_dout_pak.status.eq(command_out.source.data),
# self.command_kout_pak.status.eq(command_out.source.k),
# self.command_dout_valid.status.eq(command_out.source.stb),
# ]
# self.symbol2 = CSR(9)
# self.sync += [
# upconn_phy.tx_fifos.sink[2].stb.eq(self.symbol2.re),
# upconn_phy.tx_fifos.sink[2].data.eq(self.symbol2.r[:8]),
# upconn_phy.tx_fifos.sink[2].k.eq(self.symbol2.r[8]),
# ]

View File

@ -249,23 +249,31 @@ class TX_Command_Packet(Module, AutoCSR):
# # # # # #
# TODO: use RAM instead of FIFO ?
# Section 12.1.2 (CXP-001-2021)
# Max control packet size is 128 bytes
# NOTE: The firmware will lock up if there is not enough space for the packet
self.submodules.fifo = fifo = stream.SyncFIFO(layout, 128)
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(layout) 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)
len = Signal(6, reset=1) len = Signal(6, reset=1)
self.sync += [ self.sync += [
self.writeable.status.eq(pak_wrp.sink.ack), self.writeable.status.eq(fifo.sink.ack),
If(pak_wrp.sink.ack,pak_wrp.sink.stb.eq(0)), If(fifo.sink.ack, fifo.sink.stb.eq(0)),
If(self.data.re, If(self.data.re,
pak_wrp.sink.stb.eq(1), fifo.sink.stb.eq(1),
pak_wrp.sink.data.eq(self.data.r), fifo.sink.data.eq(self.data.r),
pak_wrp.sink.k.eq(0), fifo.sink.k.eq(0),
If(len == self.len.storage, If(len == self.len.storage,
pak_wrp.sink.eop.eq(1), fifo.sink.eop.eq(1),
len.eq(len.reset), len.eq(len.reset),
).Else( ).Else(
pak_wrp.sink.eop.eq(0), fifo.sink.eop.eq(0),
len.eq(len + 1), len.eq(len + 1),
), ),
) )

View File

@ -224,41 +224,38 @@ class Packets_Scheduler(Module):
) )
] ]
class TxFIFOs(Module): class PHY_Interface(Module):
def __init__(self, layout, nfifos, fifo_depth): def __init__(self, layout, nsink):
self.sink = [] self.source_stb = Signal(nsink)
self.source_ack = Array(Signal() for _ in range(nsink))
self.source_stb = Signal(nfifos) self.source_data = Array(Signal(8) for _ in range(nsink))
self.source_ack = Array(Signal() for _ in range(nfifos)) self.source_k = Array(Signal() for _ in range(nsink))
self.source_data = Array(Signal(8) for _ in range(nfifos))
self.source_k = Array(Signal() for _ in range(nfifos))
# # # # # #
for i in range(nfifos): self.sinks = []
fifo = stream.SyncFIFO(layout, fifo_depth) for i in range(nsink):
setattr(self.submodules, "tx_fifo" + str(i), fifo) sink = stream.Endpoint(layout)
self.sinks += [sink]
self.sink += [fifo.sink]
self.sync += [ self.sync += [
If(self.source_ack[i], If(self.source_ack[i],
# reset ack after asserted # reset ack after asserted
# since upconn clk run much slower, the ack will be high for longer than expected which will result in data loss # since upconn clk run much slower, the ack will be high for longer than expected which will result in data loss
self.source_ack[i].eq(0), self.source_ack[i].eq(0),
fifo.source.ack.eq(1), sink.ack.eq(1),
).Else( ).Else(
fifo.source.ack.eq(0), sink.ack.eq(0),
), ),
self.source_stb[i].eq(fifo.source.stb), self.source_stb[i].eq(sink.stb),
self.source_data[i].eq(fifo.source.data), self.source_data[i].eq(sink.data),
self.source_k[i].eq(fifo.source.k), self.source_k[i].eq(sink.k),
] ]
# FIFOs transmission priority # FIFOs transmission priority
self.submodules.pe = PriorityEncoder(nfifos) self.submodules.pe = PriorityEncoder(nsink)
self.comb += self.pe.i.eq(self.source_stb) self.comb += self.pe.i.eq(self.source_stb)
class Debug_buffer(Module,AutoCSR): class Debug_buffer(Module,AutoCSR):
@ -304,7 +301,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, fifo_depth, nfifos=3): def __init__(self, pad, sys_clk_freq, debug_sma, pmod_pads, layout, nsink=3):
self.bitrate2x_enable = Signal() self.bitrate2x_enable = Signal()
self.clk_reset = Signal() self.clk_reset = Signal()
@ -314,16 +311,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.tx_fifos = tx_fifos = TxFIFOs(layout, nfifos, fifo_depth) self.submodules.interface = interface = PHY_Interface(layout, nsink)
self.sinks = interface.sinks
# DEBUG: # DEBUG:
self.submodules.debug_buf = debug_buf = Debug_buffer(layout) self.submodules.debug_buf = debug_buf = Debug_buffer(layout)
self.submodules.scheduler = scheduler = Packets_Scheduler(tx_fifos, debug_buf) self.submodules.scheduler = scheduler = Packets_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(tx_fifos.source_stb != 0), self.tx_busy.eq(interface.source_stb != 0),
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),
@ -346,7 +345,7 @@ class CXP_UpConn_PHY(Module, AutoCSR):
p0 = Signal() p0 = Signal()
p3 = Signal() p3 = Signal()
self.comb += [ self.comb += [
prioity_0.eq((~tx_fifos.pe.n) & (tx_fifos.pe.o == 0)), prioity_0.eq((~interface.pe.n) & (interface.pe.o == 0)),
word_bound.eq(scheduler.tx_charcount == 3), word_bound.eq(scheduler.tx_charcount == 3),
# because of clk delay # because of clk delay

View File

@ -6,46 +6,15 @@ use libboard_zynq::{println, timer::GlobalTimer};
use crate::pl::csr; use crate::pl::csr;
pub fn trigger_test(timer: &mut GlobalTimer, linktrig_mode: u8) { #[derive(Debug)]
const LEN: usize = 4 * 8; pub enum Error {
let mut pak_arr: [u8; LEN] = [0; LEN]; BufferError,
LinkDown,
unsafe {
csr::cxp::upconn_trig_delay_write(0x05);
csr::cxp::upconn_linktrigger_write(linktrig_mode);
csr::cxp::upconn_trig_stb_write(1); // send trig
timer.delay_us(1);
let mut i: usize = 0;
while csr::cxp::upconn_trig_dout_valid_read() == 1 {
pak_arr[i] = csr::cxp::upconn_trig_dout_pak_read();
// println!("received {:#04X}", pak_arr[i]);
csr::cxp::upconn_trig_inc_write(1);
i += 1;
}
println!("trigger packet | linktrigger = {}", linktrig_mode);
print_packet(&pak_arr);
}
} }
pub fn trigger_ack_test(timer: &mut GlobalTimer) { impl From<IoError> for Error {
const LEN: usize = 4 * 8; fn from(_: IoError) -> Error {
let mut pak_arr: [u8; LEN] = [0; LEN]; Error::BufferError
unsafe {
csr::cxp::upconn_ack_write(1); // send IO ack
let mut i: usize = 0;
while csr::cxp::upconn_trig_ack_dout_valid_read() == 1 {
pak_arr[i] = csr::cxp::upconn_trig_ack_dout_pak_read();
// println!("received {:#04X}", pak_arr[i]);
csr::cxp::upconn_trig_ack_inc_write(1);
i += 1;
}
println!("trigger ack packet");
print_packet(&pak_arr);
} }
} }
@ -61,7 +30,18 @@ pub fn tx_test(timer: &mut GlobalTimer) {
send(&Packet::ControlU32Reg(Command::Read { addr: 0x00 })).expect("Cannot send CoaXpress packet"); send(&Packet::ControlU32Reg(Command::Read { addr: 0x00 })).expect("Cannot send CoaXpress packet");
csr::cxp::upconn_tx_enable_write(1); csr::cxp::upconn_tx_enable_write(1);
timer.delay_us(2);
// DEBUG: Trigger packet
let linktrig_mode: u8 = 0x01;
csr::cxp::upconn_trig_delay_write(0x05);
csr::cxp::upconn_linktrigger_write(linktrig_mode);
csr::cxp::upconn_trig_stb_write(1); // send trig
// DEBUG: Trigger ACK packet
// 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
@ -93,7 +73,7 @@ pub enum Packet {
} }
impl Packet { impl Packet {
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError> pub fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
where W: Write { where W: Write {
match self { match self {
Packet::ControlU32Reg(cmd) => match cmd { Packet::ControlU32Reg(cmd) => match cmd {
@ -153,7 +133,12 @@ impl Packet {
} }
} }
pub fn send(packet: &Packet) -> Result<(), IoError> { 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; const LEN: usize = 4 * 20;
let mut buffer: [u8; LEN] = [0; LEN]; let mut buffer: [u8; LEN] = [0; LEN];
let mut writer = Cursor::new(&mut buffer[..]); let mut writer = Cursor::new(&mut buffer[..]);