diff --git a/src/gateware/cxp_frame_pipeline.py b/src/gateware/cxp_frame_pipeline.py index 32dffd0..74bce1c 100644 --- a/src/gateware/cxp_frame_pipeline.py +++ b/src/gateware/cxp_frame_pipeline.py @@ -22,9 +22,10 @@ pixel4x_layout = [ ("valid", 4), ] -class End_Of_Line_Inserter(Module): +# TODO: rename this to signalify eol marker & kcode/other data dropper +class End_Of_Line_Marker(Module): """ - Insert eop to indicate end of line + Repurpose eop to indicate end of line And drop the K codes and Duplicate char """ @@ -264,7 +265,10 @@ class Stream_Broadcaster(Module): NextState("WAIT_HEADER"), ) -class Frame_Header_Decoder(Module): +class Frame_Header_Reader(Module): + """ + Extract the frame header information + """ def __init__(self): self.decode_err = Signal() @@ -827,7 +831,7 @@ class Pixel_Parser(Module): # inserter Tracker w/ coord # - self.submodules.eol_inserter = eol_inserter = End_Of_Line_Inserter() + 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 @@ -883,7 +887,7 @@ class Pixel_Pipeline(Module): self.submodules.buffer = buffer = SyncFIFO(word_layout_dchar, 32, True) # self.submodules.buffer = buffer = Buffer(word_layout_dchar) # to improve timing from broadcaster self.submodules.crc_checker = crc_checker = CXPCRC32_Checker() - self.submodules.header_decoder = header_decoder = Frame_Header_Decoder() + self.submodules.header_decoder = header_decoder = Frame_Header_Reader() self.submodules.parser = parser = Pixel_Parser(res_width) self.submodules.roi = ROI(parser.pixel4x, count_width) @@ -904,3 +908,70 @@ class Pixel_Pipeline(Module): # self.pix = self.pipeline[-1].pix # self.source = self.pipeline[-1].source # self.comb += self.source.ack.eq(1) # simulated a proper consumer, idk why but without this it will destory timing + +class Stream2Pixel4x_Converter(Module): + """ + Convert the raw frame data into pixel data + + Currently only support: + - Pixel format: mono8, mono10, mono12, mono14, mono16 + - Tap geometry: 1X-1Y + - Scaning mode: area scanning + + """ + 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 + # + + 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.pipeline = [crc_checker, header_reader, eol_inserter] + for s, d in zip(self.pipeline, self.pipeline[1:]): + self.comb += s.source.connect(d.sink) + self.sink = self.pipeline[0].sink + + + gearboxes = {} + 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), + + # From Table 34 (CXP-001-2021) + pix_fmt = { + "mono8": 0x0101, + "mono10": 0x0102, + "mono12": 0x0103, + "mono14": 0x0104, + "mono16": 0x0105, + } + + self.submodules.tracker = tracker = Pixel_Coordinate_Tracker(res_width) + self.sync += tracker.y_size.eq(header_reader.metadata.y_size) + self.pixel4x = tracker.pixel4x + + # discard unknown pixel format + mux_cases = {"default": [eol_inserter.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), + ] + + self.comb += Case(header_reader.metadata.pixel_format, mux_cases) +