forked from M-Labs/artiq-zynq
frameline GW: add proto pixel parser
frameline GW: update doc frameline GW: add doc
This commit is contained in:
parent
a02d6fce85
commit
d6a0b4644c
@ -4,8 +4,8 @@ from misoc.interconnect.csr import *
|
||||
from misoc.interconnect import stream
|
||||
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
|
||||
|
||||
from cxp_pipeline import *
|
||||
# from src.gateware.cxp_pipeline import * # for sim only
|
||||
# from cxp_pipeline import *
|
||||
from src.gateware.cxp_pipeline import * # for sim only
|
||||
|
||||
from types import SimpleNamespace
|
||||
from math import lcm
|
||||
@ -118,8 +118,8 @@ class CXPCRC32(Module):
|
||||
self.error.eq(reg != self.check),
|
||||
]
|
||||
|
||||
# For verifying crc in stream data packet
|
||||
class CXPCRC32_Checker(Module):
|
||||
"""Verify crc in stream data packet"""
|
||||
def __init__(self):
|
||||
self.error_cnt = Signal(16)
|
||||
|
||||
@ -285,7 +285,6 @@ class Frame_Header_Decoder(Module):
|
||||
|
||||
# # #
|
||||
|
||||
# TODO: decode Image header, line break
|
||||
self.sink = stream.Endpoint(word_layout_dchar)
|
||||
self.source = stream.Endpoint(word_layout_dchar)
|
||||
|
||||
@ -363,7 +362,9 @@ class Frame_Header_Decoder(Module):
|
||||
idx += size
|
||||
|
||||
class Pixel_Gearbox(Module):
|
||||
"""Convert 32 bits word into 4x pixel"""
|
||||
def __init__(self, size):
|
||||
assert size <= pixel_width
|
||||
assert size in [8, 10, 12, 14, 16]
|
||||
|
||||
self.x_size = Signal(3*char_width)
|
||||
@ -483,12 +484,12 @@ class Pixel_Gearbox(Module):
|
||||
NextState("MOVE_REMAINING_PIX"),
|
||||
)
|
||||
|
||||
stb_valid = Signal()
|
||||
stb_remaining_pix = Signal()
|
||||
fsm.act(
|
||||
"MOVE_REMAINING_PIX",
|
||||
reset_reg.eq(1),
|
||||
self.source.stb.eq(1),
|
||||
stb_valid.eq(1),
|
||||
stb_remaining_pix.eq(1),
|
||||
NextState("SHIFTING"),
|
||||
)
|
||||
|
||||
@ -525,26 +526,87 @@ class Pixel_Gearbox(Module):
|
||||
|
||||
self.comb += [
|
||||
Case(r_cnt, source_cases),
|
||||
If(stb_valid,
|
||||
If(stb_remaining_pix,
|
||||
self.source.valid.eq(valid),
|
||||
self.source.eop.eq(1),
|
||||
).Else(
|
||||
self.source.valid.eq(0b1111),
|
||||
),
|
||||
]
|
||||
|
||||
class Pixel_Parser(Module):
|
||||
"""Parses the 4x pixels and track pixel coordinates."""
|
||||
def __init__(self, res_width):
|
||||
self.y_size = Signal(3*char_width)
|
||||
self.sink = stream.Endpoint(pixel4x_layout)
|
||||
|
||||
# # #
|
||||
|
||||
# NOTE: no need for last_x/last_y csr which is use to indicate how big is the frame
|
||||
# layout = Record([
|
||||
# ("x", res_width),
|
||||
# ("y", res_width),
|
||||
# ("d", pixel_width),
|
||||
# ("stb", 1),
|
||||
# ("eof", 1), # end of frame
|
||||
# ])
|
||||
# self.pixel4x = [layout for _ in range(4)]
|
||||
|
||||
# DEBUG: for sim only, to show all record in sim
|
||||
self.pixel4x = []
|
||||
for _ in range(4):
|
||||
self.pixel4x.append(Record([
|
||||
("x", res_width),
|
||||
("y", res_width),
|
||||
("d", pixel_width),
|
||||
("stb", 1),
|
||||
("eof", 1), # end of frame
|
||||
]))
|
||||
|
||||
x_4x = [Signal(len(self.pixel4x[0].x), reset=i) for i in range(4)]
|
||||
y_r = Signal(len(self.pixel4x[0].y))
|
||||
|
||||
self.sync += self.sink.ack.eq(1),
|
||||
for i, (x_r, pix) in enumerate(zip(x_4x, self.pixel4x)):
|
||||
self.sync += [
|
||||
pix.stb.eq(0),
|
||||
pix.eof.eq(0),
|
||||
If(self.sink.stb,
|
||||
If(self.sink.eop,
|
||||
# new line
|
||||
x_r.eq(x_r.reset),
|
||||
|
||||
If(y_r == self.y_size - 1,
|
||||
pix.eof.eq(y_r == self.y_size - 1),
|
||||
y_r.eq(0),
|
||||
).Else(
|
||||
y_r.eq(y_r + 1),
|
||||
)
|
||||
).Else(
|
||||
x_r.eq(x_r + 4),
|
||||
),
|
||||
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)]),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
|
||||
class Frame_Deserializer(Module):
|
||||
def __init__(self, width, pixel_size):
|
||||
def __init__(self, res_width):
|
||||
# TODO: use new_frame or remove it
|
||||
self.new_frame = Signal()
|
||||
self.l_size = Signal(3*char_width)
|
||||
self.x_size = Signal(3*char_width)
|
||||
self.y_size = Signal(3*char_width)
|
||||
self.pixel_format = Signal(2*char_width)
|
||||
|
||||
self.source = stream.Endpoint(pixel4x_layout)
|
||||
# # #
|
||||
|
||||
self.submodules.eol_inserter = eol_inserter = End_Of_Line_Inserter()
|
||||
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
|
||||
|
||||
|
||||
@ -564,16 +626,19 @@ class Frame_Deserializer(Module):
|
||||
"mono16": 0x0105,
|
||||
}
|
||||
|
||||
self.submodules.parser = parser = Pixel_Parser(res_width)
|
||||
self.sync += parser.y_size.eq(self.y_size)
|
||||
|
||||
mux_cases = {
|
||||
"default": [
|
||||
# discard unknown pixel format data
|
||||
# discard unknown pixel format
|
||||
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(self.source),
|
||||
gearboxes[fmt].source.connect(parser.sink),
|
||||
]
|
||||
|
||||
self.comb += Case(self.pixel_format, mux_cases)
|
||||
@ -581,7 +646,8 @@ class Frame_Deserializer(Module):
|
||||
|
||||
|
||||
class ROI_Pipeline(Module):
|
||||
def __init__(self, res_width=32, pixel_size=16):
|
||||
# TODO: but header xsize/ysize is only 24bits, change this to 24?
|
||||
def __init__(self, res_width=32):
|
||||
|
||||
# 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
|
||||
@ -590,12 +656,13 @@ class ROI_Pipeline(Module):
|
||||
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.deserializer = deserializer = Frame_Deserializer(res_width, pixel_size)
|
||||
self.submodules.deserializer = deserializer = Frame_Deserializer(res_width)
|
||||
|
||||
self.comb += [
|
||||
deserializer.new_frame.eq(header_decoder.new_frame),
|
||||
deserializer.l_size.eq(header_decoder.metadata.l_size),
|
||||
deserializer.x_size.eq(header_decoder.metadata.x_size),
|
||||
deserializer.y_size.eq(header_decoder.metadata.y_size),
|
||||
deserializer.pixel_format.eq(header_decoder.metadata.pixel_format),
|
||||
]
|
||||
|
||||
@ -605,5 +672,6 @@ class ROI_Pipeline(Module):
|
||||
self.sink = self.pipeline[0].sink
|
||||
|
||||
# DEBUG
|
||||
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
|
||||
# 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
|
||||
|
Loading…
Reference in New Issue
Block a user