forked from M-Labs/artiq-zynq
cxp GW: add cxp grabber properly
This commit is contained in:
parent
39c4fe5f6e
commit
1fc3181fca
@ -1,6 +1,7 @@
|
|||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib.cdc import MultiReg, PulseSynchronizer
|
from migen.genlib.cdc import MultiReg, PulseSynchronizer
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
|
from misoc.interconnect.stream import Buffer
|
||||||
from misoc.cores.coaxpress.core import HostTXCore, HostRXCore
|
from misoc.cores.coaxpress.core import HostTXCore, HostRXCore
|
||||||
from misoc.cores.coaxpress.phy.high_speed_gtx import HostRXPHYs
|
from misoc.cores.coaxpress.phy.high_speed_gtx import HostRXPHYs
|
||||||
from misoc.cores.coaxpress.phy.low_speed_serdes import HostTXPHYs
|
from misoc.cores.coaxpress.phy.low_speed_serdes import HostTXPHYs
|
||||||
@ -9,8 +10,6 @@ from artiq.gateware.rtio import rtlink
|
|||||||
|
|
||||||
from cxp_frame_pipeline import *
|
from cxp_frame_pipeline import *
|
||||||
|
|
||||||
import cxp_router
|
|
||||||
|
|
||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
|
|
||||||
class CXP_Host_PHYS(Module, AutoCSR):
|
class CXP_Host_PHYS(Module, AutoCSR):
|
||||||
@ -285,30 +284,38 @@ class CXP_Frame_Pipeline(Module, AutoCSR):
|
|||||||
# Instance("OBUF", i_I=arbiter.sinks[i].stb, o_O=pmod_pads[i]),
|
# Instance("OBUF", i_I=arbiter.sinks[i].stb, o_O=pmod_pads[i]),
|
||||||
]
|
]
|
||||||
|
|
||||||
class NEO_CXP_Frame_pipeline(Module):
|
class CXP_Grabber(Module, AutoCSR):
|
||||||
# optimal stream packet size is 2 KiB - Section 9.5.2 (CXP-001-2021)
|
# optimal stream packet size is 2 KiB - Section 9.5.2 (CXP-001-2021)
|
||||||
def __init__(self, pipelines, pmod_pads, roi_engine_count=1, res_width=16, count_width=31, master=0, packet_size=16384):
|
def __init__(self, host, roi_engine_count=1, res_width=16, count_width=31):
|
||||||
n_channels = len(pipelines)
|
|
||||||
assert n_channels > 0
|
|
||||||
assert count_width <= 31
|
assert count_width <= 31
|
||||||
|
|
||||||
|
self.crc_error_cnt = CSRStatus(16)
|
||||||
|
self.crc_error_reset = CSR()
|
||||||
|
|
||||||
|
self.roi_counter = CSRStatus(count_width)
|
||||||
|
self.roi_update = CSR()
|
||||||
|
self.pix_y = CSRStatus(res_width)
|
||||||
|
|
||||||
|
self.header_l_size = CSRStatus(3*char_width)
|
||||||
|
self.header_x_size = CSRStatus(3*char_width)
|
||||||
|
self.header_y_size = CSRStatus(3*char_width)
|
||||||
|
self.header_new_line = CSRStatus(3*char_width)
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
# Trigger rtio
|
# Trigger rtio
|
||||||
nbit_trigdelay = 8
|
nbit_trigdelay = 8
|
||||||
nbit_linktrig = 1
|
nbit_linktrig = 1
|
||||||
self.trigger = rtlink.Interface(
|
self.trigger = rtlink.Interface(rtlink.OInterface(nbit_trigdelay + nbit_linktrig))
|
||||||
rtlink.OInterface(nbit_trigdelay + nbit_linktrig),
|
|
||||||
rtlink.IInterface(word_width, timestamped=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sync.rio += [
|
self.sync.rio += [
|
||||||
If(self.trigger.o.stb,
|
If(self.trigger.o.stb,
|
||||||
pipelines[master].tx.trig.delay.eq(self.trigger.o.data[nbit_linktrig:]),
|
host.tx.trig_delay.eq(self.trigger.o.data[nbit_linktrig:]),
|
||||||
pipelines[master].tx.trig.linktrig_mode.eq(self.trigger.o.data[:nbit_linktrig]),
|
host.tx.trig_linktrigger_mode.eq(self.trigger.o.data[:nbit_linktrig]),
|
||||||
),
|
),
|
||||||
pipelines[master].tx.trig.stb.eq(self.trigger.o.stb),
|
host.tx.trig_stb.eq(self.trigger.o.stb),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# ROI rtio
|
# ROI rtio
|
||||||
|
|
||||||
# 4 cfg (x0, y0, x1, y1) per roi_engine
|
# 4 cfg (x0, y0, x1, y1) per roi_engine
|
||||||
@ -325,24 +332,103 @@ class NEO_CXP_Frame_pipeline(Module):
|
|||||||
# # #
|
# # #
|
||||||
|
|
||||||
cdr = ClockDomainsRenamer("cxp_gt_rx")
|
cdr = ClockDomainsRenamer("cxp_gt_rx")
|
||||||
|
|
||||||
debug_out = False
|
|
||||||
|
|
||||||
if debug_out:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# downconn pipline -----> router -----> arbiter ------> crc checker ------> 4x converters
|
# 32+8(dchar) 4 pixel
|
||||||
|
# HostRXCore ─────/─────> Stream broadcaster ────> buffer ────> Pixel Core ───/───> Roi engines
|
||||||
#
|
#
|
||||||
|
|
||||||
# Connect pipeline
|
# that drops the K29.7 and mark eop on the crc word
|
||||||
for i, p in enumerate(pipelines):
|
self.submodules.broadcaster = broadcaster = cdr(Stream_Broadcaster())
|
||||||
broadcaster = cdr(cxp_router.Stream_Router()) # strip the packet id, tag & packet size
|
self.submodules.buffer = buffer = cdr(Buffer(word_layout_dchar)) # to improve timinig
|
||||||
crc_checker = cdr(CXPCRC32_Checker())
|
self.submodules.conv = conv = cdr(Stream2Pixel4x_Converter(res_width, count_width))
|
||||||
self.submodules += broadcaster, crc_checker
|
# CRC error counter
|
||||||
|
self.submodules.crc_reset_ps = crc_reset_ps = PulseSynchronizer("sys", "cxp_gt_rx")
|
||||||
|
self.comb += crc_reset_ps.i.eq(self.crc_error_reset.re)
|
||||||
|
|
||||||
self.comb += [
|
crc_error_cnt_rx = Signal.like(self.crc_error_cnt.status)
|
||||||
p.rx.source.connect(broadcaster.sink),
|
crc_error_r = Signal()
|
||||||
broadcaster.sources[0].connect(crc_checker),
|
self.sync.cxp_gt_rx += [
|
||||||
|
# to improve timinig
|
||||||
|
crc_error_r.eq(conv.crc_checker.error),
|
||||||
|
|
||||||
|
If(crc_reset_ps.o,
|
||||||
|
crc_error_cnt_rx.eq(crc_error_cnt_rx.reset),
|
||||||
|
).Elif(crc_error_r,
|
||||||
|
crc_error_cnt_rx.eq(crc_error_cnt_rx + 1),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
self.specials += MultiReg(crc_error_cnt_rx, self.crc_error_cnt.status)
|
||||||
|
|
||||||
|
# Connecting the pipeline
|
||||||
|
self.comb += [
|
||||||
|
host.rx.source.connect(broadcaster.sink),
|
||||||
|
broadcaster.sources[0].connect(buffer.sink),
|
||||||
|
buffer.source.connect(conv.sink),
|
||||||
|
]
|
||||||
|
|
||||||
|
roi_engines = [cdr(ROI(conv.pixel4x, count_width)) for _ in range(roi_engine_count)]
|
||||||
|
self.submodules += roi_engines
|
||||||
|
|
||||||
|
for n, roi in enumerate(roi_engines):
|
||||||
|
cfg = roi.cfg
|
||||||
|
for offset, target in enumerate([cfg.x0, cfg.y0, cfg.x1, cfg.y1]):
|
||||||
|
roi_boundary = Signal.like(target)
|
||||||
|
self.sync.rio += If(self.config.o.stb & (self.config.o.address == 4*n+offset),
|
||||||
|
roi_boundary.eq(self.config.o.data))
|
||||||
|
self.specials += MultiReg(roi_boundary, target, "cxp_gt_rx")
|
||||||
|
|
||||||
|
roi_out = roi.out
|
||||||
|
update = Signal()
|
||||||
|
self.submodules.ps = ps = PulseSynchronizer("cxp_gt_rx", "sys")
|
||||||
|
self.sync.cxp_gt_rx += ps.i.eq(roi_out.update)
|
||||||
|
self.sync += update.eq(ps.o)
|
||||||
|
|
||||||
|
sentinel = 2**count_width
|
||||||
|
count_sys = Signal.like(roi_out.count)
|
||||||
|
|
||||||
|
self.specials += MultiReg(roi_out.count, count_sys),
|
||||||
|
self.sync.rio += [
|
||||||
|
# TODO: add gating
|
||||||
|
self.gate_data.i.stb.eq(update),
|
||||||
|
# without the slice, unspecified bits will be 1 for some reason
|
||||||
|
# i.e. data[count_wdith:] = 0b111111... when using data.eq(count_sys)
|
||||||
|
self.gate_data.i.data[:count_width].eq(count_sys),
|
||||||
|
]
|
||||||
|
|
||||||
|
# DEBUG:
|
||||||
|
new_line_cnt_rx, new_line_cnt_sys = Signal(3*char_width), Signal(3*char_width)
|
||||||
|
l_size_rx, l_size_sys = Signal(3*char_width), Signal(3*char_width)
|
||||||
|
x_size_rx, x_size_sys = Signal(3*char_width), Signal(3*char_width)
|
||||||
|
y_size_rx, y_size_sys = Signal(3*char_width), Signal(3*char_width)
|
||||||
|
y_pix_rx, y_pix_sys = Signal(res_width), Signal(res_width)
|
||||||
|
self.sync.cxp_gt_rx += [
|
||||||
|
If(conv.header_reader.new_line,
|
||||||
|
new_line_cnt_rx.eq(new_line_cnt_rx + 1),
|
||||||
|
),
|
||||||
|
|
||||||
|
l_size_rx.eq(conv.header_reader.metadata.l_size),
|
||||||
|
x_size_rx.eq(conv.header_reader.metadata.x_size),
|
||||||
|
y_size_rx.eq(conv.header_reader.metadata.y_size),
|
||||||
|
|
||||||
|
y_pix_rx.eq(conv.pixel4x[0].y),
|
||||||
|
]
|
||||||
|
self.specials += [
|
||||||
|
MultiReg(new_line_cnt_rx, new_line_cnt_sys),
|
||||||
|
MultiReg(l_size_rx, l_size_sys),
|
||||||
|
MultiReg(x_size_rx, x_size_sys),
|
||||||
|
MultiReg(y_size_rx, y_size_sys),
|
||||||
|
MultiReg(y_pix_rx, y_pix_sys),
|
||||||
|
]
|
||||||
|
self.sync += [
|
||||||
|
self.header_new_line.status.eq(new_line_cnt_sys),
|
||||||
|
self.pix_y.status.eq(y_pix_sys),
|
||||||
|
self.header_l_size.status.eq(l_size_sys),
|
||||||
|
self.header_x_size.status.eq(x_size_sys),
|
||||||
|
self.header_y_size.status.eq(y_size_sys),
|
||||||
|
self.roi_counter.status.eq(count_sys),
|
||||||
|
If(update,
|
||||||
|
self.roi_update.w.eq(1),
|
||||||
|
).Elif(self.roi_update.re,
|
||||||
|
self.roi_update.w.eq(0),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user