From 58b05a2877a5390e22b3820a5cabfa62032b5193 Mon Sep 17 00:00:00 2001 From: morgan Date: Fri, 24 Jan 2025 11:53:38 +0800 Subject: [PATCH] frameline GW: fix roi frameline GW: remove unused import frameline GW: add econ roi --- src/gateware/cxp_frame_pipeline.py | 133 +++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 18 deletions(-) diff --git a/src/gateware/cxp_frame_pipeline.py b/src/gateware/cxp_frame_pipeline.py index afdfa16..57c35fb 100644 --- a/src/gateware/cxp_frame_pipeline.py +++ b/src/gateware/cxp_frame_pipeline.py @@ -1,5 +1,4 @@ from migen import * -from migen.genlib.coding import PriorityEncoder from misoc.interconnect.csr import * from misoc.interconnect import stream from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine @@ -631,31 +630,26 @@ class ROI(Module): # # # - # TODO: remove the self. from self.roi_4x - self.roi_4x = [] - for _ in range(4): - self.roi_4x.append(Record([ + roi_4x = [ + Record([ ("x_good", 1), ("y_good", 1), ("gray", len(pixel_4x[0].gray)), ("stb", 1), ("count", count_width), - ])) + ]) for _ in range(4) + + ] - for pix, roi in zip(pixel_4x, self.roi_4x): + for pix, roi in zip(pixel_4x, roi_4x): self.sync += [ - # TODO: replace the comparision with preprocess equal - # e.g. pix.x == self.cfg.x0 - i # stage 1 - generate "good" (in-ROI) signals - If(pix.x <= self.cfg.x0, + roi.x_good.eq(0), + If((self.cfg.x0 <= pix.x) & (pix.x < self.cfg.x1), roi.x_good.eq(1) ), - # NOTE: this gate doens't work as 4 pixes are coming in - If(pix.x >= self.cfg.x1, - roi.x_good.eq(0) - ), - # This is fine because 4x pixel are on the same line + # the 4 pixels are on the same y level, no need for extra calculation If(pix.y == self.cfg.y0, roi.y_good.eq(1) ), @@ -683,12 +677,115 @@ class ROI(Module): self.sync += [ eof.eq(reduce(or_, [pix.eof for pix in pixel_4x])), eof_buf.eq(eof), - count_buf[0].eq(self.roi_4x[0].count + self.roi_4x[1].count), - count_buf[1].eq(self.roi_4x[2].count + self.roi_4x[3].count), + count_buf[0].eq(roi_4x[0].count + roi_4x[1].count), + count_buf[1].eq(roi_4x[2].count + roi_4x[3].count), self.out.update.eq(0), If(eof_buf, - [roi.count.eq(0) for roi in self.roi_4x], + [roi.count.eq(0) for roi in roi_4x], + self.out.update.eq(1), + self.out.count.eq(reduce(add, count_buf)) + ), + ] + +class Economical_ROI(Module): + """ + ROI Engine. For each frame, accumulates pixels values within a + rectangular region of interest, and reports the total. + + This econ version limits the distance between x0 and x1 need to be at least 4 pixel long + """ + def __init__(self, pixel_4x, count_width): + assert len(pixel_4x) == 4 + + self.cfg = Record([ + ("x0", len(pixel_4x[0].x)), + ("y0", len(pixel_4x[0].y)), + ("x1", len(pixel_4x[0].x)), + ("y1", len(pixel_4x[0].y)), + ]) + + self.out = Record([ + ("update", 1), + # registered output - can be used as CDC input + ("count", count_width), + ]) + + # # # + + roi_4x = [ + Record([ + ("x_good", 1), + ("y_good", 1), + ("gray", len(pixel_4x[0].gray)), + ("stb", 1), + ("count", count_width), + ]) for _ in range(4) + + ] + + # Pipeline the offset calculation + x0_offset = [Signal.like(self.cfg.x0) for _ in range(4)] + x1_offset = [Signal.like(self.cfg.x1) for _ in range(4)] + + for offset, (x0, x1) in enumerate(zip(x0_offset, x1_offset)): + self.sync += [ + x0.eq(self.cfg.x0 + offset), + x1.eq(self.cfg.x1 + offset), + ] + + for pix, roi in zip(pixel_4x, roi_4x): + # stage 1 - generate "good" (in-ROI) signals + + # if p in [x0, x0+3] => x_good == 1 + # if p in [x1, x1+3] => x_good == 0 + # when [x0, x0+3] overlap with [x1, x1+3]: + # some x_good won't have the chance to fall and keep accmulated extra data + # Thus, x1-x0 >= 4 need to be match for pixel to accmulated correctly + for x0, x1 in zip(x0_offset, x1_offset): + self.sync += [ + If(pix.x == x0, + roi.x_good.eq(1), + ), + If(pix.x == x1, + roi.x_good.eq(0), + ), + ] + self.sync += [ + # the 4 pixels are on the same y level, no need for extra calculation + If(pix.y == self.cfg.y0, + roi.y_good.eq(1) + ), + If(pix.y == self.cfg.y1, + roi.y_good.eq(0) + ), + If(pix.eof, + roi.x_good.eq(0), + roi.y_good.eq(0) + ), + roi.gray.eq(pix.gray), + roi.stb.eq(pix.stb), + + # stage 2 - accumulate + If((roi.stb & roi.x_good & roi.y_good), + roi.count.eq(roi.count + roi.gray) + ) + ] + + eof = Signal() + eof_buf = Signal() + count_buf = [Signal(count_width), Signal(count_width)] + + # stage 3 - update + self.sync += [ + eof.eq(reduce(or_, [pix.eof for pix in pixel_4x])), + eof_buf.eq(eof), + count_buf[0].eq(roi_4x[0].count + roi_4x[1].count), + count_buf[1].eq(roi_4x[2].count + roi_4x[3].count), + + self.out.update.eq(0), + If(eof_buf, + [roi.count.eq(0) for roi in roi_4x], self.out.update.eq(1), self.out.count.eq(reduce(add, count_buf)) ),