From 1fc3181fca7d8c61e938dc8f2c7286337c9a6604 Mon Sep 17 00:00:00 2001 From: morgan Date: Thu, 6 Feb 2025 17:05:56 +0800 Subject: [PATCH] cxp GW: add cxp grabber properly --- src/gateware/cxp.py | 146 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 116 insertions(+), 30 deletions(-) diff --git a/src/gateware/cxp.py b/src/gateware/cxp.py index 7371c2a..fa3b405 100644 --- a/src/gateware/cxp.py +++ b/src/gateware/cxp.py @@ -1,6 +1,7 @@ from migen import * from migen.genlib.cdc import MultiReg, PulseSynchronizer from misoc.interconnect.csr import * +from misoc.interconnect.stream import Buffer from misoc.cores.coaxpress.core import HostTXCore, HostRXCore from misoc.cores.coaxpress.phy.high_speed_gtx import HostRXPHYs from misoc.cores.coaxpress.phy.low_speed_serdes import HostTXPHYs @@ -9,8 +10,6 @@ from artiq.gateware.rtio import rtlink from cxp_frame_pipeline import * -import cxp_router - from types import SimpleNamespace class CXP_Host_PHYS(Module, AutoCSR): @@ -285,29 +284,37 @@ class CXP_Frame_Pipeline(Module, AutoCSR): # Instance("OBUF", i_I=arbiter.sinks[i].stb, o_O=pmod_pads[i]), ] -class NEO_CXP_Frame_pipeline(Module): +class CXP_Grabber(Module, AutoCSR): # 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 + def __init__(self, host, roi_engine_count=1, res_width=16, count_width=31): assert count_width <= 31 + self.crc_error_cnt = CSRStatus(16) + self.crc_error_reset = CSR() + + self.roi_counter = CSRStatus(count_width) + self.roi_update = CSR() + self.pix_y = CSRStatus(res_width) + + self.header_l_size = CSRStatus(3*char_width) + self.header_x_size = CSRStatus(3*char_width) + self.header_y_size = CSRStatus(3*char_width) + self.header_new_line = CSRStatus(3*char_width) + + # # # + # 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.trigger = rtlink.Interface(rtlink.OInterface(nbit_trigdelay + nbit_linktrig)) 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]), + host.tx.trig_delay.eq(self.trigger.o.data[nbit_linktrig:]), + host.tx.trig_linktrigger_mode.eq(self.trigger.o.data[:nbit_linktrig]), ), - pipelines[master].tx.trig.stb.eq(self.trigger.o.stb), + host.tx.trig_stb.eq(self.trigger.o.stb), ] - # ROI rtio @@ -325,24 +332,103 @@ class NEO_CXP_Frame_pipeline(Module): # # # cdr = ClockDomainsRenamer("cxp_gt_rx") - - debug_out = False - - if debug_out: - pass - - # - # downconn pipline -----> router -----> arbiter ------> crc checker ------> 4x converters + # 32+8(dchar) 4 pixel + # HostRXCore ─────/─────> Stream broadcaster ────> buffer ────> Pixel Core ───/───> Roi engines # + + # that drops the K29.7 and mark eop on the crc word + self.submodules.broadcaster = broadcaster = cdr(Stream_Broadcaster()) + self.submodules.buffer = buffer = cdr(Buffer(word_layout_dchar)) # to improve timinig + self.submodules.conv = conv = cdr(Stream2Pixel4x_Converter(res_width, count_width)) + # CRC error counter + self.submodules.crc_reset_ps = crc_reset_ps = PulseSynchronizer("sys", "cxp_gt_rx") + self.comb += crc_reset_ps.i.eq(self.crc_error_reset.re) - # 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 + crc_error_cnt_rx = Signal.like(self.crc_error_cnt.status) + crc_error_r = Signal() + self.sync.cxp_gt_rx += [ + # to improve timinig + crc_error_r.eq(conv.crc_checker.error), - self.comb += [ - p.rx.source.connect(broadcaster.sink), - broadcaster.sources[0].connect(crc_checker), + If(crc_reset_ps.o, + crc_error_cnt_rx.eq(crc_error_cnt_rx.reset), + ).Elif(crc_error_r, + crc_error_cnt_rx.eq(crc_error_cnt_rx + 1), + ), + ] + self.specials += MultiReg(crc_error_cnt_rx, self.crc_error_cnt.status) + + # Connecting the pipeline + self.comb += [ + host.rx.source.connect(broadcaster.sink), + broadcaster.sources[0].connect(buffer.sink), + buffer.source.connect(conv.sink), + ] + + roi_engines = [cdr(ROI(conv.pixel4x, count_width)) for _ in range(roi_engine_count)] + self.submodules += roi_engines + + for n, roi in enumerate(roi_engines): + cfg = roi.cfg + for offset, target in enumerate([cfg.x0, cfg.y0, cfg.x1, cfg.y1]): + roi_boundary = Signal.like(target) + self.sync.rio += If(self.config.o.stb & (self.config.o.address == 4*n+offset), + roi_boundary.eq(self.config.o.data)) + self.specials += MultiReg(roi_boundary, target, "cxp_gt_rx") + + roi_out = roi.out + update = Signal() + self.submodules.ps = ps = PulseSynchronizer("cxp_gt_rx", "sys") + self.sync.cxp_gt_rx += ps.i.eq(roi_out.update) + self.sync += update.eq(ps.o) + + sentinel = 2**count_width + count_sys = Signal.like(roi_out.count) + + self.specials += MultiReg(roi_out.count, count_sys), + self.sync.rio += [ + # TODO: add gating + self.gate_data.i.stb.eq(update), + # without the slice, unspecified bits will be 1 for some reason + # i.e. data[count_wdith:] = 0b111111... when using data.eq(count_sys) + self.gate_data.i.data[:count_width].eq(count_sys), + ] + + # DEBUG: + new_line_cnt_rx, new_line_cnt_sys = Signal(3*char_width), Signal(3*char_width) + l_size_rx, l_size_sys = Signal(3*char_width), Signal(3*char_width) + x_size_rx, x_size_sys = Signal(3*char_width), Signal(3*char_width) + y_size_rx, y_size_sys = Signal(3*char_width), Signal(3*char_width) + y_pix_rx, y_pix_sys = Signal(res_width), Signal(res_width) + self.sync.cxp_gt_rx += [ + If(conv.header_reader.new_line, + new_line_cnt_rx.eq(new_line_cnt_rx + 1), + ), + + l_size_rx.eq(conv.header_reader.metadata.l_size), + x_size_rx.eq(conv.header_reader.metadata.x_size), + y_size_rx.eq(conv.header_reader.metadata.y_size), + + y_pix_rx.eq(conv.pixel4x[0].y), + ] + self.specials += [ + MultiReg(new_line_cnt_rx, new_line_cnt_sys), + MultiReg(l_size_rx, l_size_sys), + MultiReg(x_size_rx, x_size_sys), + MultiReg(y_size_rx, y_size_sys), + MultiReg(y_pix_rx, y_pix_sys), + ] + self.sync += [ + self.header_new_line.status.eq(new_line_cnt_sys), + self.pix_y.status.eq(y_pix_sys), + self.header_l_size.status.eq(l_size_sys), + self.header_x_size.status.eq(x_size_sys), + self.header_y_size.status.eq(y_size_sys), + self.roi_counter.status.eq(count_sys), + If(update, + self.roi_update.w.eq(1), + ).Elif(self.roi_update.re, + self.roi_update.w.eq(0), + ), ]