frameline: add pixeldata layout & add docs

This commit is contained in:
morgan 2025-02-06 17:46:29 +08:00
parent 3a03d7c52c
commit f6ad1ee97a

View File

@ -21,19 +21,17 @@ pixel4x_layout = [
("data", pixel_width*4),
("valid", 4),
]
pixeldata_layout = [("data", word_width)] # pixel data don't need k code
# TODO: rename this to signalify eol marker & kcode/other data dropper
class End_Of_Line_Marker(Module):
class End_of_line_Marker(Module):
"""
Repurpose eop to indicate end of line
And drop the K codes and Duplicate char
"""
def __init__(self):
self.l_size = Signal(3*char_width)
self.sink = Endpoint(word_layout_dchar)
self.source = Endpoint([("data", word_width)]) # pixel data don't need k code
self.sink = Endpoint(pixeldata_layout)
self.source = Endpoint(pixeldata_layout)
# # #
@ -46,7 +44,7 @@ class End_Of_Line_Marker(Module):
cnt = Signal.like(self.l_size, reset=1)
self.sync += [
If((~self.source.stb | self.source.ack),
self.sink.connect(self.source, omit={"ack", "eop", "k", "dchar", "dchar_k"}),
self.sink.connect(self.source, omit={"ack", "eop"}),
If(self.sink.stb,
If(cnt == 1,
cnt.eq(self.l_size)
@ -127,9 +125,8 @@ class CXPCRC32(Module):
]
class CXPCRC32_Checker(Module):
"""Verify crc in stream data packet"""
"""Verify crc in stream packet"""
def __init__(self):
# TODO: handle the error into a counter
self.error = Signal()
self.sink = Endpoint(word_layout_dchar)
@ -267,7 +264,7 @@ class Stream_Broadcaster(Module):
class Frame_Header_Reader(Module):
"""
Extract the frame header information
Extract the frame header information and pass pixel data downstream
"""
def __init__(self):
self.decode_err = Signal()
@ -291,11 +288,11 @@ class Frame_Header_Reader(Module):
]
assert layout_len(img_header_layout) == n_metadata_chars*char_width
self.sink = Endpoint(word_layout_dchar)
self.source = Endpoint(pixeldata_layout)
# # #
self.sink = Endpoint(word_layout_dchar)
self.source = Endpoint(word_layout_dchar)
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
@ -312,7 +309,7 @@ class Frame_Header_Reader(Module):
self.sink.ack.eq(1),
NextState("DECODE"),
).Else(
self.sink.connect(self.source),
self.sink.connect(self.source, omit={"k", "dchar", "dchar_k"}),
)
)
@ -370,7 +367,7 @@ class Frame_Header_Reader(Module):
setattr(self.metadata, name, switch_endianness(packet_buffer[idx:idx+size]))
idx += size
class Pixel_Gearbox(Module):
class Pixel_Unpacker(Module):
"""Convert 32 bits word into 4x pixel"""
def __init__(self, size):
assert size <= pixel_width
@ -378,12 +375,12 @@ class Pixel_Gearbox(Module):
self.x_size = Signal(3*char_width)
sink_dw, source_dw = word_width, size*4
self.sink = Endpoint([("data", sink_dw)])
self.sink = Endpoint(pixeldata_layout)
self.source = Endpoint(pixel4x_layout)
# # #
sink_dw, source_dw = layout_len(pixeldata_layout), size*4
ring_buf_size = lcm(sink_dw, source_dw)
# ensure the shift register is at least twice the size of sink/source dw
if (ring_buf_size//sink_dw) < 2:
@ -831,14 +828,14 @@ class Pixel_Parser(Module):
# inserter Tracker w/ coord
#
self.submodules.eol_inserter = eol_inserter = End_Of_Line_Marker()
self.submodules.eol_inserter = eol_inserter = End_of_line_Marker()
self.sync += eol_inserter.l_size.eq(self.l_size)
self.sink = eol_inserter.sink
gearboxes = {}
for s in [8, 10, 12, 14, 16]:
gearbox = Pixel_Gearbox(s)
gearbox = Pixel_Unpacker(s)
gearboxes["mono"+str(s)] = gearbox
self.submodules += gearbox
self.sync += gearbox.x_size.eq(self.x_size),
@ -921,36 +918,33 @@ class Stream2Pixel4x_Converter(Module):
"""
def __init__(self, res_width, count_width):
# 32+8(dchar)
# ----/----> crc checker ------> frame header ------> eol inserter
# decoder
#
# 32 pixel 4x
# ---/---> 32:8/10/12/14/16 Pixel Gearboxes ----/----> Pixel Coordinate ------> pixel 4x
# Tracker w/ coord
# 32+8(dchar) 32 4x pixel
# sink ────/────> crc checker ─────> frame header ───/───> eol inserter ─────> 8, 10, 12, 14, 16 bits ───/───> pixel coordinate ─────> 4x pixel with
# reader pixel unpacker tracker coordinate
#
self.submodules.crc_checker = crc_checker = CXPCRC32_Checker()
self.submodules.header_reader = header_reader = Frame_Header_Reader()
# Pixel Praser
self.submodules.eol_inserter = eol_inserter = End_Of_Line_Marker()
self.sync += eol_inserter.l_size.eq(header_reader.metadata.l_size)
self.sink = eol_inserter.sink
self.submodules.formatter = formatter = End_of_line_Marker()
self.sync += formatter.l_size.eq(header_reader.metadata.l_size)
self.sink = formatter.sink
self.pipeline = [crc_checker, header_reader, eol_inserter]
self.pipeline = [crc_checker, header_reader, formatter]
for s, d in zip(self.pipeline, self.pipeline[1:]):
self.comb += s.source.connect(d.sink)
self.sink = self.pipeline[0].sink
gearboxes = {}
unpackers = {}
for s in [8, 10, 12, 14, 16]:
gearbox = Pixel_Gearbox(s)
gearboxes["mono"+str(s)] = gearbox
self.submodules += gearbox
self.sync += gearbox.x_size.eq(header_reader.metadata.x_size),
unpacker = Pixel_Unpacker(s)
unpackers["mono"+str(s)] = unpacker
self.submodules += unpacker
self.sync += unpacker.x_size.eq(header_reader.metadata.x_size),
# From Table 34 (CXP-001-2021)
pix_fmt = {
@ -966,11 +960,11 @@ class Stream2Pixel4x_Converter(Module):
self.pixel4x = tracker.pixel4x
# discard unknown pixel format
mux_cases = {"default": [eol_inserter.source.ack.eq(1)]}
mux_cases = {"default": [formatter.source.ack.eq(1)]}
for fmt in pix_fmt:
mux_cases[pix_fmt[fmt]] = [
eol_inserter.source.connect(gearboxes[fmt].sink),
gearboxes[fmt].source.connect(tracker.sink),
formatter.source.connect(unpackers[fmt].sink),
unpackers[fmt].source.connect(tracker.sink),
]
self.comb += Case(header_reader.metadata.pixel_format, mux_cases)