cores/video/framebuffer: Add support for video clock faster than sys_clk with DRAM's data-width > 32.

In this, CDC has to be done first and Data-width conversion is then done in Video clock domain.
This commit is contained in:
Florent Kermarrec 2021-03-30 10:14:10 +02:00
parent c182f4db5f
commit 70d11974fc
2 changed files with 32 additions and 22 deletions

View File

@ -143,7 +143,7 @@ class VideoTimingGenerator(Module, AutoCSR):
def __init__(self, default_video_timings="800x600@60Hz"): def __init__(self, default_video_timings="800x600@60Hz"):
# Check / Get Video Timings. # Check / Get Video Timings.
try: try:
vt = video_timings[default_video_timings] self.video_timings = vt = video_timings[default_video_timings]
except KeyError: except KeyError:
msg = [f"Video Timings {default_video_timings} not supported, availables:"] msg = [f"Video Timings {default_video_timings} not supported, availables:"]
for video_timing in video_timings.keys(): for video_timing in video_timings.keys():
@ -581,7 +581,7 @@ class VideoTerminal(Module):
class VideoFrameBuffer(Module, AutoCSR): class VideoFrameBuffer(Module, AutoCSR):
"""Video FrameBuffer""" """Video FrameBuffer"""
def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=8192, clock_domain="sys"): def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False):
self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout)
self.source = source = stream.Endpoint(video_data_layout) self.source = source = stream.Endpoint(video_data_layout)
self.underflow = Signal() self.underflow = Signal()
@ -598,32 +598,41 @@ class VideoFrameBuffer(Module, AutoCSR):
default_loop = 1 default_loop = 1
) )
# FIXME: Make sure it will work for all DRAM's data-width/all Video resolutions. # If DRAM Data Width > 32-bit and Video clock is faster than sys_clk:
if (dram_port.data_width > 32) and clock_faster_than_sys:
# Video Data-Width Converter. # Do Clock Domain Crossing first...
self.submodules.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain)
self.comb += self.dma.source.connect(self.cdc.sink)
# ... and then Data-Width Conversion.
self.submodules.conv = stream.Converter(dram_port.data_width, 32)
self.comb += self.cdc.source.connect(self.conv.sink)
video_pipe_source = self.conv.source
# Elsif DRAM Data Widt < 32-bit or Video clock is slower than sys_clk:
else:
# Do Data-Width Conversion first...
self.submodules.conv = stream.Converter(dram_port.data_width, 32) self.submodules.conv = stream.Converter(dram_port.data_width, 32)
self.comb += self.dma.source.connect(self.conv.sink) self.comb += self.dma.source.connect(self.conv.sink)
# ... and then Clock Domain Crossing.
# Video CDC.
self.submodules.cdc = stream.ClockDomainCrossing([("data", 32)], cd_from="sys", cd_to=clock_domain) self.submodules.cdc = stream.ClockDomainCrossing([("data", 32)], cd_from="sys", cd_to=clock_domain)
self.comb += self.conv.source.connect(self.cdc.sink) self.comb += self.conv.source.connect(self.cdc.sink)
self.comb += If(dram_port.data_width < 32, # FIXME. self.comb += If(dram_port.data_width < 32, # FIXME.
self.cdc.sink.data[ 0: 8].eq(self.conv.source.data[16:24]), self.cdc.sink.data[ 0: 8].eq(self.conv.source.data[16:24]),
self.cdc.sink.data[16:24].eq(self.conv.source.data[ 0: 8]), self.cdc.sink.data[16:24].eq(self.conv.source.data[ 0: 8]),
) )
video_pipe_source = self.cdc.source
# Video Generation. # Video Generation.
self.comb += [ self.comb += [
vtg_sink.ready.eq(1), vtg_sink.ready.eq(1),
If(vtg_sink.valid & vtg_sink.de, If(vtg_sink.valid & vtg_sink.de,
self.cdc.source.connect(source, keep={"valid", "ready"}), video_pipe_source.connect(source, keep={"valid", "ready"}),
vtg_sink.ready.eq(source.valid & source.ready), vtg_sink.ready.eq(source.valid & source.ready),
), ),
vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}),
source.r.eq(self.cdc.source.data[16:24]), source.r.eq(video_pipe_source.data[16:24]),
source.g.eq(self.cdc.source.data[ 8:16]), source.g.eq(video_pipe_source.data[ 8:16]),
source.b.eq(self.cdc.source.data[ 0: 8]), source.b.eq(video_pipe_source.data[ 0: 8]),
] ]
# Underflow. # Underflow.

View File

@ -1719,6 +1719,7 @@ class LiteXSoC(SoC):
vres = vres, vres = vres,
base = base, base = base,
clock_domain = clock_domain, clock_domain = clock_domain,
clock_faster_than_sys = vtg.video_timings["pix_clk"] > self.sys_clk_freq
) )
setattr(self.submodules, name, vfb) setattr(self.submodules, name, vfb)