diff --git a/src/gateware/cxp.py b/src/gateware/cxp.py index aace844..6451284 100644 --- a/src/gateware/cxp.py +++ b/src/gateware/cxp.py @@ -9,6 +9,8 @@ from cxp_upconn import CXP_TXPHYs from cxp_pipeline import * from cxp_frame_pipeline import * +import cxp_router + from functools import reduce from operator import add from types import SimpleNamespace @@ -153,40 +155,55 @@ class RX_Pipeline(Module, AutoCSR): ), ] - # TODO: rewrite this to follow crc_error_cnt from frameline # test packet error & packet counters - self.test_error_counter = CSRStatus(len(reader.test_err_cnt)) - self.test_packet_counter = CSRStatus(len(reader.test_pak_cnt)) + self.test_error_counter = CSRStatus(16) + self.test_packet_counter = CSRStatus(16) self.test_counts_reset = CSR() - - test_reset_ps = PulseSynchronizer("sys", "cxp_gtx_rx") - self.submodules += test_reset_ps + test_err_cnt_sys = Signal.like(self.test_error_counter.status) + test_pak_cnt_sys = Signal.like(self.test_packet_counter.status) + self.sync += [ + self.test_error_counter.status.eq(test_err_cnt_sys), + self.test_packet_counter.status.eq(test_pak_cnt_sys), + ] + self.submodules.test_reset_ps = test_reset_ps = PulseSynchronizer("sys", "cxp_gtx_rx") self.sync += test_reset_ps.i.eq(self.test_counts_reset.re), - test_err_cnt_r = Signal.like(reader.test_err_cnt) - test_pak_cnt_r = Signal.like(reader.test_pak_cnt) + test_err_cnt_rx = Signal.like(test_err_cnt_sys) + test_pak_cnt_rx = Signal.like(test_pak_cnt_sys) + test_err_r, test_pak_r = Signal(), Signal() self.sync.cxp_gtx_rx += [ - reader.test_cnt_reset.eq(test_reset_ps.o), - test_err_cnt_r.eq(reader.test_err_cnt), - test_pak_cnt_r.eq(reader.test_pak_cnt), + test_err_r.eq(reader.test_err), + test_pak_r.eq(reader.test_pak), + + If(test_reset_ps.o, + test_err_cnt_rx.eq(test_err_cnt_rx.reset), + ).Elif(test_err_r, + test_err_cnt_rx.eq(test_err_cnt_rx + 1), + ), + If(test_reset_ps.o, + test_pak_cnt_rx.eq(test_pak_cnt_rx.reset), + ).Elif(test_pak_r, + test_pak_cnt_rx.eq(test_pak_cnt_rx + 1), + ), ] self.specials += [ - MultiReg(test_err_cnt_r, self.test_error_counter.status), - MultiReg(test_pak_cnt_r, self.test_packet_counter.status), + MultiReg(test_err_cnt_rx, test_err_cnt_sys), + MultiReg(test_pak_cnt_rx, test_pak_cnt_sys), ] - # reader cicular memory control interface - self.packet_type = CSRStatus(8) + # reader nslot buffer control interface self.pending_packet = CSR() - self.read_ptr = CSRStatus(log2_int(nslot)) + self.read_ptr = CSRStatus(len(reader.read_ptr)) + write_ptr_sys = Signal.like(reader.write_ptr) + self.specials += [ - MultiReg(reader.packet_type, self.packet_type.status), - MultiReg(self.read_ptr.status, reader.read_ptr_rx, odomain="cxp_gtx_rx"), + MultiReg(self.read_ptr.status, reader.read_ptr, odomain="cxp_gtx_rx"), + MultiReg(reader.write_ptr, write_ptr_sys) ] self.sync += [ - self.pending_packet.w.eq(self.read_ptr.status != reader.write_ptr_sys), + self.pending_packet.w.eq(self.read_ptr.status != write_ptr_sys), If(~gtx.rx_ready, self.read_ptr.status.eq(0), ).Elif(self.pending_packet.re & self.pending_packet.w, @@ -194,6 +211,7 @@ class RX_Pipeline(Module, AutoCSR): ) ] + # TODO: remove this self.submodules.fifo = fifo = cdr(stream.SyncFIFO(word_layout_dchar, 32, True)) # Drop the K29.7 and mark the EOP for arbiter and crc cheker @@ -483,6 +501,68 @@ class CXP_Frame_Pipeline(Module, AutoCSR): rx_stb = Signal() self.sync.cxp_gtx_rx += rx_stb.eq(p.rx.source.stb) self.specials += [ - Instance("OBUF", i_I=rx_stb, o_O=pmod_pads[i]), + # Instance("OBUF", i_I=rx_stb, o_O=pmod_pads[i]), # Instance("OBUF", i_I=arbiter.sinks[i].stb, o_O=pmod_pads[i]), ] + +class NEO_CXP_Frame_pipeline(Module): + # optimal stream packet size is 2 KiB - Section 9.5.2 (CXP-001-2021) + def __init__(self, pipelines, pmod_pads, roi_engine_count=1, res_width=16, count_width=31, master=0, packet_size=16384): + n_channels = len(pipelines) + assert n_channels > 0 + assert count_width <= 31 + + # Trigger rtio + nbit_trigdelay = 8 + nbit_linktrig = 1 + self.trigger = rtlink.Interface( + rtlink.OInterface(nbit_trigdelay + nbit_linktrig), + rtlink.IInterface(word_width, timestamped=False) + ) + + self.sync.rio += [ + If(self.trigger.o.stb, + pipelines[master].tx.trig.delay.eq(self.trigger.o.data[nbit_linktrig:]), + pipelines[master].tx.trig.linktrig_mode.eq(self.trigger.o.data[:nbit_linktrig]), + ), + pipelines[master].tx.trig.stb.eq(self.trigger.o.stb), + ] + + + # ROI rtio + + # 4 cfg (x0, y0, x1, y1) per roi_engine + self.config = rtlink.Interface(rtlink.OInterface(res_width, bits_for(4*roi_engine_count-1))) + + # select which roi engine can output rtio_input signal + self.gate_data = rtlink.Interface( + rtlink.OInterface(roi_engine_count), + # the 32th bits is for sentinel (gate detection) + rtlink.IInterface(count_width+1, timestamped=False) + ) + + + # # # + + cdr = ClockDomainsRenamer("cxp_gtx_rx") + + debug_out = False + + if debug_out: + pass + + + # + # downconn pipline -----> router -----> arbiter ------> crc checker ------> 4x converters + # + + # Connect pipeline + for i, p in enumerate(pipelines): + broadcaster = cdr(cxp_router.Stream_Router()) # strip the packet id, tag & packet size + crc_checker = cdr(CXPCRC32_Checker()) + self.submodules += broadcaster, crc_checker + + self.comb += [ + p.rx.source.connect(broadcaster.sink), + broadcaster.sources[0].connect(crc_checker), + ]