frameline GW: add roi proto

This commit is contained in:
morgan 2025-01-15 13:20:51 +08:00
parent d6a0b4644c
commit 2cd588df35

View File

@ -9,6 +9,7 @@ from src.gateware.cxp_pipeline import * # for sim only
from types import SimpleNamespace
from math import lcm
from operator import or_, add
pixel_width = 16
pixel4x_layout = [
@ -558,7 +559,7 @@ class Pixel_Parser(Module):
self.pixel4x.append(Record([
("x", res_width),
("y", res_width),
("d", pixel_width),
("gray", pixel_width),
("stb", 1),
("eof", 1), # end of frame
]))
@ -588,10 +589,98 @@ class Pixel_Parser(Module):
pix.stb.eq(self.sink.valid[i]),
pix.x.eq(x_r),
pix.y.eq(y_r),
pix.d.eq(self.sink.data[pixel_width*i:pixel_width*(i+1)]),
pix.gray.eq(self.sink.data[pixel_width*i:pixel_width*(i+1)]),
)
]
class ROI(Module):
"""
ROI Engine. For each frame, accumulates pixels values within a
rectangular region of interest, and reports the total.
"""
def __init__(self, pixel_4x, count_len):
assert count_len <= 31
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),
("count", count_len),
])
# # #
#
self.roi_4x = []
for _ in range(4):
self.roi_4x.append(Record([
("x_good", 1),
("y_good", 1),
("gray", len(pixel_4x[0].gray)),
("stb", 1),
("count", count_len),
]))
# x_good = [Signal() for _ in range(4)]
# y_good = [Signal() for _ in range(4)]
# gray = [Signal(len(pixel_4x[0].gray)) for _ in range(4)]
# stb = [Signal() for _ in range(4)]
# count = [Signal(count_len) for _ in range(4)]
for pix, roi in zip(pixel_4x, self.roi_4x):
self.sync += [
# stage 1 - generate "good" (in-ROI) signals
If(pix.x == self.cfg.x0,
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
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()
# stage 3 - update
self.sync += [
eof.eq(reduce(or_, [pix.eof for pix in pixel_4x])),
self.out.update.eq(0),
If(eof,
[roi.count.eq(0) for roi in self.roi_4x],
self.out.update.eq(1),
self.out.count.eq(reduce(add, [roi.count for roi in self.roi_4x]))
)
]
class Frame_Deserializer(Module):
@ -628,6 +717,7 @@ class Frame_Deserializer(Module):
self.submodules.parser = parser = Pixel_Parser(res_width)
self.sync += parser.y_size.eq(self.y_size)
self.pixel4x = parser.pixel4x
mux_cases = {
"default": [
@ -646,8 +736,8 @@ class Frame_Deserializer(Module):
class ROI_Pipeline(Module):
# TODO: but header xsize/ysize is only 24bits, change this to 24?
def __init__(self, res_width=32):
# largest x/y pixel size supported by frame header are 24 bits
def __init__(self, res_width=24):
# NOTE: csr need to stay outside since this module need to be cdr in the CXP_FRAME_Pipeline module
# NOTE: TapGeo other than 1X-1Y are not supported
@ -658,6 +748,8 @@ class ROI_Pipeline(Module):
self.submodules.header_decoder = header_decoder = Frame_Header_Decoder()
self.submodules.deserializer = deserializer = Frame_Deserializer(res_width)
self.submodules.roi = ROI(deserializer.pixel4x, 31)
self.comb += [
deserializer.new_frame.eq(header_decoder.new_frame),
deserializer.l_size.eq(header_decoder.metadata.l_size),