diff --git a/src/gateware/cxp.py b/src/gateware/cxp.py index 0e8cc7d..2dd0326 100644 --- a/src/gateware/cxp.py +++ b/src/gateware/cxp.py @@ -7,6 +7,7 @@ from misoc.cores.coaxpress.phy.high_speed_gtx import HostRXPHYs from misoc.cores.coaxpress.phy.low_speed_serdes import HostTXPHYs from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio.phy.grabber import Serializer from cxp_frame_pipeline import * @@ -286,7 +287,7 @@ class CXP_Frame_Pipeline(Module, AutoCSR): class CXP_Grabber(Module, AutoCSR): # optimal stream packet size is 2 KiB - Section 9.5.2 (CXP-001-2021) - def __init__(self, host, roi_engine_count=1, res_width=16, count_width=31): + def __init__(self, host, roi_engine_count=2, res_width=16, count_width=31): assert count_width <= 31 self.crc_error_cnt = CSRStatus(16) @@ -377,58 +378,70 @@ class CXP_Grabber(Module, AutoCSR): 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) + # 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) + # 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), - ] + # 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(stream2pix.header_reader.new_line, - new_line_cnt_rx.eq(new_line_cnt_rx + 1), - ), - l_size_rx.eq(stream2pix.header_reader.metadata.l_size), - x_size_rx.eq(stream2pix.header_reader.metadata.x_size), - y_size_rx.eq(stream2pix.header_reader.metadata.y_size), + self.submodules.synchronizer = synchronizer = CXP_Synchronizer(roi_engines) + self.submodules.serializer = serializer = Serializer(synchronizer.update, synchronizer.counts, self.gate_data.i) + + self.sync.rio += If(self.gate_data.o.stb, + serializer.gate.eq(self.gate_data.o.data)) - y_pix_rx.eq(stream2pix.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), - ), - ] + + # DEBUG: + 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 += [ + l_size_rx.eq(stream2pix.header_reader.metadata.l_size), + x_size_rx.eq(stream2pix.header_reader.metadata.x_size), + y_size_rx.eq(stream2pix.header_reader.metadata.y_size), + y_pix_rx.eq(stream2pix.pixel4x[0].y), + ] + self.specials += [ + 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.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), + ] + +class CXP_Synchronizer(Module): + def __init__(self, roi_engines): + counts_in = [roi_engine.out.count for roi_engine in roi_engines] + + # This assumes all ROI engines update at the same time. + self.update = Signal() + # stays valid until the next frame after self.update is pulsed. + self.counts = [Signal.like(count) for count in counts_in] + + # # # + + for i, o in zip(counts_in, self.counts): + self.specials += MultiReg(i, o) + + self.submodules.ps = ps = PulseSynchronizer("cxp_gt_rx", "sys") + self.sync.cxp_gt_rx += ps.i.eq(roi_engines[0].out.update) + self.sync += self.update.eq(ps.o)