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