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.interconnect import stream
|
||||||
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
|
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
|
||||||
|
|
||||||
from cxp_pipeline import *
|
# from cxp_pipeline import *
|
||||||
# from src.gateware.cxp_pipeline import * # for sim only
|
from src.gateware.cxp_pipeline import * # for sim only
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from math import lcm
|
from math import lcm
|
||||||
@ -118,8 +118,8 @@ class CXPCRC32(Module):
|
|||||||
self.error.eq(reg != self.check),
|
self.error.eq(reg != self.check),
|
||||||
]
|
]
|
||||||
|
|
||||||
# For verifying crc in stream data packet
|
|
||||||
class CXPCRC32_Checker(Module):
|
class CXPCRC32_Checker(Module):
|
||||||
|
"""Verify crc in stream data packet"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.error_cnt = Signal(16)
|
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.sink = stream.Endpoint(word_layout_dchar)
|
||||||
self.source = stream.Endpoint(word_layout_dchar)
|
self.source = stream.Endpoint(word_layout_dchar)
|
||||||
|
|
||||||
@ -363,7 +362,9 @@ class Frame_Header_Decoder(Module):
|
|||||||
idx += size
|
idx += size
|
||||||
|
|
||||||
class Pixel_Gearbox(Module):
|
class Pixel_Gearbox(Module):
|
||||||
|
"""Convert 32 bits word into 4x pixel"""
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
|
assert size <= pixel_width
|
||||||
assert size in [8, 10, 12, 14, 16]
|
assert size in [8, 10, 12, 14, 16]
|
||||||
|
|
||||||
self.x_size = Signal(3*char_width)
|
self.x_size = Signal(3*char_width)
|
||||||
@ -483,12 +484,12 @@ class Pixel_Gearbox(Module):
|
|||||||
NextState("MOVE_REMAINING_PIX"),
|
NextState("MOVE_REMAINING_PIX"),
|
||||||
)
|
)
|
||||||
|
|
||||||
stb_valid = Signal()
|
stb_remaining_pix = Signal()
|
||||||
fsm.act(
|
fsm.act(
|
||||||
"MOVE_REMAINING_PIX",
|
"MOVE_REMAINING_PIX",
|
||||||
reset_reg.eq(1),
|
reset_reg.eq(1),
|
||||||
self.source.stb.eq(1),
|
self.source.stb.eq(1),
|
||||||
stb_valid.eq(1),
|
stb_remaining_pix.eq(1),
|
||||||
NextState("SHIFTING"),
|
NextState("SHIFTING"),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -525,26 +526,87 @@ class Pixel_Gearbox(Module):
|
|||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
Case(r_cnt, source_cases),
|
Case(r_cnt, source_cases),
|
||||||
If(stb_valid,
|
If(stb_remaining_pix,
|
||||||
self.source.valid.eq(valid),
|
self.source.valid.eq(valid),
|
||||||
|
self.source.eop.eq(1),
|
||||||
).Else(
|
).Else(
|
||||||
self.source.valid.eq(0b1111),
|
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):
|
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.new_frame = Signal()
|
||||||
self.l_size = Signal(3*char_width)
|
self.l_size = Signal(3*char_width)
|
||||||
self.x_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.pixel_format = Signal(2*char_width)
|
||||||
|
|
||||||
self.source = stream.Endpoint(pixel4x_layout)
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
self.submodules.eol_inserter = eol_inserter = End_Of_Line_Inserter()
|
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
|
self.sink = eol_inserter.sink
|
||||||
|
|
||||||
|
|
||||||
@ -564,16 +626,19 @@ class Frame_Deserializer(Module):
|
|||||||
"mono16": 0x0105,
|
"mono16": 0x0105,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.submodules.parser = parser = Pixel_Parser(res_width)
|
||||||
|
self.sync += parser.y_size.eq(self.y_size)
|
||||||
|
|
||||||
mux_cases = {
|
mux_cases = {
|
||||||
"default": [
|
"default": [
|
||||||
# discard unknown pixel format data
|
# discard unknown pixel format
|
||||||
eol_inserter.source.ack.eq(1),
|
eol_inserter.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),
|
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)
|
self.comb += Case(self.pixel_format, mux_cases)
|
||||||
@ -581,7 +646,8 @@ class Frame_Deserializer(Module):
|
|||||||
|
|
||||||
|
|
||||||
class ROI_Pipeline(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: 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
|
# 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.buffer = buffer = Buffer(word_layout_dchar) # to improve timing from broadcaster
|
||||||
self.submodules.crc_checker = crc_checker = CXPCRC32_Checker()
|
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_Decoder()
|
||||||
self.submodules.deserializer = deserializer = Frame_Deserializer(res_width, pixel_size)
|
self.submodules.deserializer = deserializer = Frame_Deserializer(res_width)
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
deserializer.new_frame.eq(header_decoder.new_frame),
|
deserializer.new_frame.eq(header_decoder.new_frame),
|
||||||
deserializer.l_size.eq(header_decoder.metadata.l_size),
|
deserializer.l_size.eq(header_decoder.metadata.l_size),
|
||||||
deserializer.x_size.eq(header_decoder.metadata.x_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),
|
deserializer.pixel_format.eq(header_decoder.metadata.pixel_format),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -605,5 +672,6 @@ class ROI_Pipeline(Module):
|
|||||||
self.sink = self.pipeline[0].sink
|
self.sink = self.pipeline[0].sink
|
||||||
|
|
||||||
# DEBUG
|
# DEBUG
|
||||||
self.source = self.pipeline[-1].source
|
# self.pix = self.pipeline[-1].pix
|
||||||
self.comb += self.source.ack.eq(1) # simulated a proper consumer, idk why but without this it will destory timing
|
# 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