1
0
Fork 0

Compare commits

..

13 Commits

5 changed files with 282 additions and 115 deletions

View File

@ -23,6 +23,41 @@ class DownConn_Interface(Module, AutoCSR):
self.submodules.phy = phy = CXP_DownConn_PHY(refclk, downconn_pads, sys_clk_freq, debug_sma, pmod_pads)
self.gtxs = phy.gtxs
# DEBUG: TX pipeline
self.submodules.debug_src = debug_src = TX_Command_Packet()
self.submodules.trig_ack = trig_ack = Trigger_ACK()
self.submodules.mux = mux = stream.Multiplexer(upconn_layout, 2)
self.submodules.conv = conv = stream.StrideConverter(upconn_layout, downconn_layout, reverse=True)
self.ack = CSR()
self.mux_sel = CSRStorage()
self.sync += trig_ack.ack.eq(self.ack.re),
self.comb += [
debug_src.source.connect(mux.sink0),
trig_ack.source.connect(mux.sink1),
mux.sel.eq(self.mux_sel.storage)
]
tx_pipeline = [mux , conv, phy.sinks[0]]
for s, d in zip(tx_pipeline, tx_pipeline[1:]):
self.comb += s.source.connect(d.sink)
# NOTE: RX pipeline
self.submodules.debug_out = debug_out = RX_Debug_Buffer()
self.submodules.recv_path = recv_path = Receiver_Path()
rx_pipeline = [phy.sources[0], recv_path, debug_out]
for s, d in zip(rx_pipeline, rx_pipeline[1:]):
self.comb += s.source.connect(d.sink)
# DEBUG: CSR
self.trig_ack = CSRStatus()
self.trig_clr = CSR()
self.comb += [
self.trig_ack.status.eq(recv_path.trig_ack),
recv_path.trig_clr.eq(self.trig_clr.re),
]
class UpConn_Interface(Module, AutoCSR):

View File

@ -4,8 +4,10 @@ from migen.genlib.resetsync import AsyncResetSynchronizer
from misoc.cores.code_8b10b import Encoder, Decoder
from misoc.interconnect.csr import *
from misoc.interconnect import stream
from artiq.gateware.drtio.transceiver.gtx_7series_init import *
from cxp_pipeline import downconn_layout
from functools import reduce
from operator import add
@ -46,7 +48,6 @@ class CXP_DownConn_PHY(Module, AutoCSR):
# TODO: add extension gtx connections
# TODO: add connection interface
# TODO: Connect slave cxp_gtx_rx clock tgt
# checkout channel interfaces & drtio_gtx
# GTPTXPhaseAlignement for inspiration
@ -99,9 +100,30 @@ class CXP_DownConn_PHY(Module, AutoCSR):
),
]
self.sources = []
for n, gtx in enumerate(self.gtxs):
# DEBUG: remove cdc fifo
# gtx rx -> fifo out -> cdc out
fifo_out = stream.AsyncFIFO(downconn_layout, 128)
self.submodules += ClockDomainsRenamer({"write": "cxp_gtx_rx", "read": "sys"})(fifo_out)
self.sources.append(fifo_out)
for i in range(4):
self.sync.cxp_gtx_rx += [
fifo_out.sink.stb.eq(0),
# don't store idle word in fifo
If(gtx.rx_ready & fifo_out.sink.ack & (gtx.decoders[0].d != 0xBC),
fifo_out.sink.stb.eq(1),
fifo_out.sink.data[i*8:(i*8)+8].eq(gtx.decoders[i].d),
fifo_out.sink.k[i].eq(gtx.decoders[i].k),
),
]
# DEBUG: tx of gtx is not used in CXP
# DEBUG: txusrclk PLL DRG
self.txpll_reset = CSRStorage()
@ -118,6 +140,9 @@ class CXP_DownConn_PHY(Module, AutoCSR):
self.txinit_phaligndone = CSRStatus()
self.rxinit_phaligndone = CSRStatus()
self.tx_stb = CSRStorage()
self.sinks = []
for n, gtx in enumerate(self.gtxs):
self.comb += [
gtx.txpll_reset.eq(self.txpll_reset.storage),
@ -137,6 +162,48 @@ class CXP_DownConn_PHY(Module, AutoCSR):
self.loopback_mode = CSRStorage(3)
self.comb += gtx.loopback_mode.eq(self.loopback_mode.storage)
# DEBUG: datain
# fw -> fifo (sys) -> cdc fifo -> gtx tx
fifo_in = stream.AsyncFIFO(downconn_layout, 128)
self.submodules += ClockDomainsRenamer({"write": "sys", "read": "cxp_gtx_tx"})(fifo_in)
self.sinks.append(fifo_in)
# TODO: why there this send an extra 0xFB word
txstb = Signal()
self.specials += MultiReg(self.tx_stb.storage, txstb, odomain="cxp_gtx_tx")
self.sync.cxp_gtx_tx += [
fifo_in.source.ack.eq(0),
If(fifo_in.source.stb & txstb,
fifo_in.source.ack.eq(1),
)
]
# NOTE: prevent the first word send twice due to stream stb delay
self.comb += [
If(fifo_in.source.stb & fifo_in.source.ack,
gtx.encoder.d[0].eq(fifo_in.source.data[:8]),
gtx.encoder.d[1].eq(fifo_in.source.data[8:16]),
gtx.encoder.d[2].eq(fifo_in.source.data[16:24]),
gtx.encoder.d[3].eq(fifo_in.source.data[24:]),
gtx.encoder.k[0].eq(fifo_in.source.k[0]),
gtx.encoder.k[1].eq(fifo_in.source.k[1]),
gtx.encoder.k[2].eq(fifo_in.source.k[2]),
gtx.encoder.k[3].eq(fifo_in.source.k[3]),
).Else(
# NOTE: IDLE WORD
gtx.encoder.d[0].eq(0xBC),
gtx.encoder.k[0].eq(1),
gtx.encoder.d[1].eq(0x3C),
gtx.encoder.k[1].eq(1),
gtx.encoder.d[2].eq(0x3C),
gtx.encoder.k[2].eq(1),
gtx.encoder.d[3].eq(0xB5),
gtx.encoder.k[3].eq(0),
)
]
# DEBUG: IO SMA & PMOD
if n == 0:
self.specials += [
@ -144,9 +211,9 @@ class CXP_DownConn_PHY(Module, AutoCSR):
# Instance("OBUF", i_I=gtx.cd_cxp_gtx_tx.clk, o_O=debug_sma.n_rx),
# # pmod 0-7 pin
# Instance("OBUF", i_I=gtx.comma_checker.comma_aligned, o_O=pmod_pads[0]),
# Instance("OBUF", i_I=gtx.comma_checker.comma_det, o_O=pmod_pads[1]),
# Instance("OBUF", i_I=gtx.comma_checker.restart_sys, o_O=pmod_pads[2]),
Instance("OBUF", i_I=txstb, o_O=pmod_pads[0]),
Instance("OBUF", i_I=fifo_in.source.stb, o_O=pmod_pads[1]),
Instance("OBUF", i_I=fifo_in.source.ack, o_O=pmod_pads[2]),
# Instance("OBUF", i_I=gtx.comma_checker.aligner_en, o_O=pmod_pads[3]),
# Instance("OBUF", i_I=gtx.comma_checker.check_reset, o_O=pmod_pads[4]),
# Instance("OBUF", i_I=gtx.comma_checker.has_comma, o_O=pmod_pads[5]),
@ -159,43 +226,6 @@ class CXP_DownConn_PHY(Module, AutoCSR):
# Instance("OBUF", i_I=gtx.dready, o_O=pmod_pads[3]),
]
# DEBUG: datain
self.sync.cxp_gtx_tx += [
gtx.encoder.d[0].eq(0xBC),
gtx.encoder.k[0].eq(1),
gtx.encoder.d[1].eq(0x3C),
gtx.encoder.k[1].eq(1),
gtx.encoder.d[2].eq(0x3C),
gtx.encoder.k[2].eq(1),
gtx.encoder.d[3].eq(0xB5),
gtx.encoder.k[3].eq(0),
]
for i in range(4):
gtx.decoders[i].input.attr.add("no_retiming")
gtx.decoders[i].d.attr.add("no_retiming")
gtx.decoders[i].k.attr.add("no_retiming")
rxdata_name = "rxdata_" + str(i)
rxdata_csr = CSRStatus(10, name=rxdata_name)
setattr(self, rxdata_name, rxdata_csr)
decoded_name = "decoded_data_" + str(i)
decoded_csr = CSRStatus(8, name=decoded_name)
setattr(self, decoded_name, decoded_csr)
k_name = "rxdata_" + str(i)
k_csr = CSRStatus(1, name=k_name)
setattr(self, k_name, k_csr)
self.sync.cxp_gtx_rx += [
rxdata_csr.status.eq(gtx.decoders[i].input),
decoded_csr.status.eq(gtx.decoders[i].d),
k_csr.status.eq(gtx.decoders[i].k),
]
class QPLL(Module, AutoCSR):
def __init__(self, refclk, sys_clk_freq):
self.clk = Signal()

View File

@ -6,11 +6,20 @@ from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine, LiteEthMACCRCC
upconn_dw = 8
upconn_layout = [("data", upconn_dw), ("k", upconn_dw//8)]
downconn_dw = 32
downconn_layout = [("data", downconn_dw), ("k", downconn_dw//8)]
def K(x, y):
return ((y << 5) | x)
def bytes2word(arr):
assert len(arr) == 4
sum = 0
for i, val in enumerate(arr):
sum += (val & 0xFF) << i*8
return sum
class Code_Source(Module):
def __init__(self, layout, counts=4):
@ -247,22 +256,22 @@ class Trigger_ACK(Module):
self.source = k_code_inserter.source
class TX_Command_Packet(Module, AutoCSR):
def __init__(self):
self.len = CSRStorage(6)
# Section 12.1.2 (CXP-001-2021)
# Max control packet size is 128 bytes
def __init__(self, fifo_depth=128):
self.len = CSRStorage(log2_int(fifo_depth))
self.data = CSR(upconn_dw)
self.writeable = CSRStatus()
# # #
# Section 12.1.2 (CXP-001-2021)
# Max control packet size is 128 bytes
self.submodules.fifo = fifo = stream.SyncFIFO(upconn_layout, 128)
self.submodules.fifo = fifo = stream.SyncFIFO(upconn_layout, fifo_depth)
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(upconn_layout)
self.source = pak_wrp.source
self.comb += fifo.source.connect(pak_wrp.sink)
len = Signal(6, reset=1)
cnt = Signal(log2_int(fifo_depth), reset=1)
self.sync += [
self.writeable.status.eq(fifo.sink.ack),
If(fifo.sink.ack, fifo.sink.stb.eq(0)),
@ -271,12 +280,12 @@ class TX_Command_Packet(Module, AutoCSR):
fifo.sink.data.eq(self.data.r),
fifo.sink.k.eq(0),
If(len == self.len.storage,
If(cnt == self.len.storage,
fifo.sink.eop.eq(1),
len.eq(len.reset),
cnt.eq(cnt.reset),
).Else(
fifo.sink.eop.eq(0),
len.eq(len + 1),
cnt.eq(cnt + 1),
),
)
]
@ -332,7 +341,7 @@ class TX_Test_Packet(Module, AutoCSR):
self.submodules.pak_wrp = pak_wrp = Packet_Wrapper(upconn_layout)
self.comb += [
pak_type_inserter.data.eq(0x04),
pak_type_inserter.k.eq(0x04),
pak_type_inserter.k.eq(0),
testdata_src.connect(pak_type_inserter.sink),
pak_type_inserter.source.connect(pak_wrp.sink),
@ -346,3 +355,81 @@ class TX_Test_Packet(Module, AutoCSR):
).Elif(self.source.eop & self.source.ack,
self.busy.status.eq(0)
)
class RX_Debug_Buffer(Module,AutoCSR):
def __init__(self):
self.submodules.buf_out = buf_out = stream.SyncFIFO(downconn_layout, 128)
self.sink = buf_out.sink
self.inc = CSR()
self.dout_pak = CSRStatus(downconn_dw)
self.kout_pak = CSRStatus(downconn_dw//8)
self.dout_valid = CSRStatus()
self.sync += [
# output
buf_out.source.ack.eq(self.inc.re),
self.dout_pak.status.eq(buf_out.source.data),
self.kout_pak.status.eq(buf_out.source.k),
self.dout_valid.status.eq(buf_out.source.stb),
]
class Receiver_Path(Module, AutoCSR):
def __init__(self):
self.trig_ack = Signal()
self.trig_clr = Signal()
# TODO:
self.packet_type = Signal(8)
class CXP_Data_Packet_Decode(Module):
def __init__(self):
self.sink = stream.Endpoint(downconn_layout)
# This is where data stream comes out
self.source = stream.Endpoint(downconn_layout)
# # #
self.comb += self.sink.connect(self.source)
class CXP_Trig_Ack_Checker(Module, AutoCSR):
def __init__(self):
self.sink = stream.Endpoint(downconn_layout)
self.source = stream.Endpoint(downconn_layout)
self.ack = Signal()
# # #
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
self.sink.ack.eq(1),
If(self.sink.stb,
self.sink.ack.eq(0),
NextState("COPY"),
)
)
fsm.act("COPY",
If((self.sink.stb & (self.sink.data == bytes2word([K(28, 6)]*4)) & (self.sink.k == 0b1111)),
# discard K28,6
self.sink.ack.eq(1),
NextState("CHECK_ACK")
).Else(
self.sink.connect(self.source),
)
)
fsm.act("CHECK_ACK",
If(self.sink.stb,
NextState("IDLE"),
# discard the word after K28,6
self.sink.ack.eq(1),
If(self.sink.data == bytes2word([0x01]*4),
self.ack.eq(1),
)
)
)

View File

@ -3,7 +3,7 @@ use libboard_zynq::{println, timer::GlobalTimer};
use log::info;
// use log::info;
use crate::pl::csr;
use crate::{cxp_proto, pl::csr};
#[derive(Clone, Copy, Debug)]
#[allow(non_camel_case_types)]
@ -37,72 +37,42 @@ pub fn loopback_testing(timer: &mut GlobalTimer, speed: CXP_SPEED) {
while csr::cxp::downconn_phy_rx_ready_read() != 1 {}
info!("rx ready!");
loop {
// for _ in 0..20 {
// NOTE: raw bits
// let data0 = csr::cxp::downconn_phy_rxdata_0_read();
// let data1 = csr::cxp::downconn_phy_rxdata_1_read();
// let data2 = csr::cxp::downconn_phy_rxdata_2_read();
// let data3 = csr::cxp::downconn_phy_rxdata_3_read();
// let rxready = csr::cxp::downconn_phy_rx_ready_read();
// timer.delay_us(100);
// if data0 == 0b0101111100 || data0 == 0b1010000011 {
// println!(
// "data[0] = {:#012b} comma = {} | rx ready = {}",
// data0,
// data0 == 0b0101111100 || data0 == 0b1010000011,
// rxready,
// );
// timer.delay_us(1_000_000);
// } else if data0 == 0b1001111100 || data0 == 0b0110000011 {
// println!(
// "data[0] = {:#012b} K28.1 | rx ready = {}",
// data0,
// rxready,
// );
// timer.delay_us(1_000_000);
// } else {
// println!(
// "data[0] = {:#012b} | rx ready = {}",
// data0,
// rxready,
// );
// timer.delay_us(1_000_000);
// }
cxp_proto::downconn_debug_send_trig_ack();
timer.delay_us(1_000_000);
// NOTE: raw bits
// let data0 = csr::cxp::downconn_phy_rxdata_0_read();
// let data1 = csr::cxp::downconn_phy_rxdata_1_read();
// let data2 = csr::cxp::downconn_phy_rxdata_2_read();
// let data3 = csr::cxp::downconn_phy_rxdata_3_read();
// println!(
// "0b{:010b} {:010b} {:010b} {:010b}",
// data0, data1, data2, data3
// );
cxp_proto::downconn_debug_send(&cxp_proto::Packet::CtrlRead {
addr: 0x00,
length: 0x04,
});
// NOTE:decode data
// let data0_k = csr::cxp::downconn_phy_decoded_k_0_read();
// let data1_k = csr::cxp::downconn_phy_decoded_k_1_read();
// let data2_k = csr::cxp::downconn_phy_decoded_k_2_read();
// let data3_k = csr::cxp::downconn_phy_decoded_k_3_read();
let data0_decoded = csr::cxp::downconn_phy_decoded_data_0_read();
let data1_decoded = csr::cxp::downconn_phy_decoded_data_1_read();
let data2_decoded = csr::cxp::downconn_phy_decoded_data_2_read();
let data3_decoded = csr::cxp::downconn_phy_decoded_data_3_read();
println!(
"{:#04x} {:#04x} {:#04x} {:#04x}",
data0_decoded, data1_decoded, data2_decoded, data3_decoded,
);
// println!(
// "decoded_data[0] = {:#04x} decoded_k[0] = {:#b} decoded_data[1] = {:#04x} decoded_k[1] = {:#b}",
// data0_decoded,
// data0_k,
// data1_decoded,
// data1_k,
// );
timer.delay_us(200); // wait packet has arrive at async fifo in
csr::cxp::downconn_phy_tx_stb_write(1);
timer.delay_us(200);
csr::cxp::downconn_phy_tx_stb_write(0);
info!("trig ack = {}", csr::cxp::downconn_trig_ack_read());
csr::cxp::downconn_trig_clr_write(1);
info!("after clr trig ack = {}", csr::cxp::downconn_trig_ack_read());
// TODO: investigate how to make my packet appear
// TODO: discard idle word
// DEBUG: print loopback packets
const LEN: usize = 20;
let mut pak_arr: [u32; LEN] = [0; LEN];
let mut k_arr: [u8; LEN] = [0; LEN];
let mut i: usize = 0;
while csr::cxp::downconn_debug_out_dout_valid_read() == 1 {
pak_arr[i] = csr::cxp::downconn_debug_out_dout_pak_read();
k_arr[i] = csr::cxp::downconn_debug_out_kout_pak_read();
// println!("received {:#04X}", pak_arr[i]);
csr::cxp::downconn_debug_out_inc_write(1);
i += 1;
if i == LEN {
break;
}
}
cxp_proto::print_packetu32(&pak_arr, &k_arr);
}
}
pub fn setup(timer: &mut GlobalTimer) {

View File

@ -191,3 +191,48 @@ pub fn print_packet(pak: &[u8]) {
println!("]");
println!("============================================");
}
pub fn print_packetu32(pak: &[u32], k: &[u8]) {
println!("pak = [");
for i in 0..(pak.len()) {
let data: [u8; 4] = pak[i].to_be_bytes();
println!(
"{:#03} {:#04X} {:#04X} {:#04X} {:#04X} | K {:04b},",
i + 1,
data[0],
data[1],
data[2],
data[3],
k[i],
)
}
println!("]");
println!("============================================");
}
pub fn downconn_debug_send(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 {
csr::cxp::downconn_mux_sel_write(0);
let len = writer.position();
csr::cxp::downconn_debug_src_len_write(len as u8);
for data in writer.get_ref()[..len].iter() {
while csr::cxp::downconn_debug_src_writeable_read() == 0 {}
csr::cxp::upconn_command_data_write(*data);
csr::cxp::downconn_debug_src_data_write(*data);
}
}
Ok(())
}
pub fn downconn_debug_send_trig_ack() {
unsafe {
csr::cxp::downconn_mux_sel_write(1);
csr::cxp::downconn_ack_write(1);
}
}