Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked HDMI_OUT with Dummy Mixer #300

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions firmware/lm32/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ int main(void)
#endif
ci_prompt();
while(1) {
hdmi_out0_driver_hdout_source_write(1);
processor_service();
ci_service();

Expand Down
8 changes: 6 additions & 2 deletions firmware/lm32/processor.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,15 +510,19 @@ void processor_update(void)
#ifdef CSR_HDMI_OUT0_BASE
/* hdmi_out0 */
#ifdef CSR_HDMI_IN0_BASE
if(processor_hdmi_out0_source == VIDEO_IN_HDMI_IN0)
if(processor_hdmi_out0_source == VIDEO_IN_HDMI_IN0) {
hdmi_out0_fi_base0_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_index));
hdmi_out0_fi_base1_write(pattern_framebuffer_base());
}
#endif
#ifdef CSR_HDMI_IN1_BASE
if(processor_hdmi_out0_source == VIDEO_IN_HDMI_IN1)
hdmi_out0_fi_base0_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_index));
#endif
if(processor_hdmi_out0_source == VIDEO_IN_PATTERN)
if(processor_hdmi_out0_source == VIDEO_IN_PATTERN) {
hdmi_out0_fi_base0_write(pattern_framebuffer_base());
hdmi_out0_fi_base1_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_index));
}

hb_service(VIDEO_OUT_HDMI_OUT0);
#endif
Expand Down
162 changes: 148 additions & 14 deletions gateware/hdmi_out/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,167 @@
from migen.actorlib import structuring, misc

from misoclib.mem.sdram.frontend import dma_lasmi
from gateware.hdmi_out.format import bpp, pixel_layout, FrameInitiator, VTG
from gateware.hdmi_out.format import bpp, pixel_layout, pixel_layout_c, FrameInitiator, VTG
from gateware.hdmi_out.phy import Driver
from gateware.i2c import I2C


class HDMIOut(Module, AutoCSR):
def __init__(self, pads, lasmim, external_clocking=None):
pack_factor = lasmim.dw//bpp
"""HDMIOut Module

The HDMIOut Module defined the neccesary objects and function neccesary to
read HDMI_OUT data from relevant base address from main memory and output
that data to corresponding HDMI_OUT port.

This is derived from standard VGA core, description can be found here.
https://migen.readthedocs.io/en/latest/casestudies.html

The blockdiagram corresponding to reworked HDMI_OUT are added here.
<add a permanent doc link with all block diagrams added>

Parameters
----------
pads: ???
This contains the information regarding the FPGA pins that are mapped to
HDMi_OUT pins.

dma: ???
Instance of sdram class defined in target file for DMA access.

ndmas: int
Number of DMA engines to be initiated, specified in target file.

external_clocking: ???
Clocking realted information, by default None defined in Driver class

"""
def __init__(self, pads, dma, ndmas=1, external_clocking=None):

if hasattr(pads, "scl"):
self.submodules.i2c = I2C(pads)

lasmim_list = [dma.crossbar.get_master() for i in range(ndmas)]
pack_factor = lasmim_list[0].dw//bpp
g = DataFlowGraph()

self.fi = FrameInitiator(lasmim.aw, pack_factor)
# Define Modules

intseq = misc.IntSequence(lasmim.aw, lasmim.aw)
dma_out = AbstractActor(plumbing.Buffer)
g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr())
g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmim), dma_out)
self.fi = FrameInitiator(lasmim_list[0].aw, pack_factor, ndmas)
self.pg = PixelGather(self.fi, lasmim_list, pack_factor, ndmas, g)
vtg = VTG(pack_factor, ndmas)
self.driver = Driver(pack_factor, ndmas, pads, external_clocking)

cast = structuring.Cast(lasmim.dw, pixel_layout(pack_factor), reverse_to=True)
vtg = VTG(pack_factor)
self.driver = Driver(pack_factor, pads, external_clocking)
# Define Connections

g.add_connection(self.fi, vtg, source_subr=self.fi.timing_subr, sink_ep="timing")
g.add_connection(dma_out, cast)
g.add_connection(cast, vtg, sink_ep="pixels")
g.add_connection(self.pg.combiner, vtg , sink_ep='pixels')
g.add_connection(self.pg.fi, vtg, source_subr=self.pg.fi.timing_subr, sink_ep="timing")
g.add_connection(vtg, self.driver)

self.submodules += CompositeActor(g)

class PixelGather(Module):
"""Pixel Gathere Module

The Pixel Gather module defines number of dma engines. Each dma gets
it base address from FrameInitiator Module. Each DMA outputs a data of
the form pixel_layout() and these are combined in a single layout
pixel_layout_c() using DMACombinator, which is the final output of this
module.

This is derived from standard VGA core, description can be found here.
https://migen.readthedocs.io/en/latest/casestudies.html

Parameters
----------
fi: FrameInitiator
Instance of FrameInitiator() class defined in HDMIOut.

lasmim_list: list
List of dma.crossbar.get_master() to define each DMA.

pack_factor: int
DMA Data Width/data per pixel or number of pixels read in a time from DMA.

ndmas: int
Number of DMA engines to be initiated, specified in target file.

g: DataFlowGraph
Instance of DataFlowGraph() class, defined in HDMIOut.

Attributes
----------
fi : list of Signals, in
Instance of FrameInitiator class.
combiner : Instance of DMACombinat class, out
Output from each DMA combined in a single layout.
"""
def __init__(self, fi, lasmim_list, pack_factor, ndmas, g):

combine_layout = [pixel_layout(pack_factor) for i in range(ndmas)]

self.fi = fi
self.combiner = DMACombinator(pixel_layout_c(pack_factor, ndmas), combine_layout, ndmas)

for i in range(ndmas):

# Define Modules
lasmimb = lasmim_list[i]
intseq = misc.IntSequence(lasmimb.aw, lasmimb.aw)
dma_out = AbstractActor(plumbing.Buffer)
cast = structuring.Cast(lasmimb.dw, pixel_layout(pack_factor), reverse_to=True)

# Define Connections
g.add_connection(self.fi, intseq, source_subr=self.fi.dma_subr(i))
g.add_pipeline(intseq, AbstractActor(plumbing.Buffer), dma_lasmi.Reader(lasmimb), dma_out, cast)
g.add_connection(cast, self.combiner, sink_ep="sink"+str(i))


class DMACombinator(Module):
"""DMACombinator Module

This is a simple combinatonal block which takes pixel_layout() signals from
each of the dma and combines them to a single layout pixel_layout_c().

Parameters
----------
layout: list
This represents the complete layout at output that is pixel_layout_c()

subrecords: list
List of containg pixel_layout() repeated ndmas times

ndmas: int
Number of DMA engines to be initiated, specified in target file

Attributes
----------
source : Source class, out
EndPointDescription of output layout

sink0 : Sink class, in
EndPointDescription of input layout
Similarly for all other instantiations of Sink

"""
def __init__(self, layout, subrecords, ndmas):
self.source = Source(layout) # pixel_layout_c
sinks = []
for n, r in enumerate(subrecords):
s = Sink(r)
setattr(self, "sink"+str(n), s)
sinks.append(s) # pixel_layout
self.busy = Signal()

###

self.comb += [
self.busy.eq(0),
self.source.stb.eq(optree("&", [sink.stb for sink in sinks]))
]

self.comb += [sink.ack.eq(self.source.ack & self.source.stb) for sink in sinks]
self.comb += [self.source.param.eq(sink.param) for sink in sinks]

for i in range(ndmas):
self.comb += [ getattr(self.source.payload, "n"+str(i) ).eq(sinks[i].payload)]

25 changes: 20 additions & 5 deletions gateware/hdmi_out/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
def pixel_layout(pack_factor):
return [("p"+str(i), pixel_layout_s) for i in range(pack_factor)]

def pixel_layout_c(pack_factor, ndmas):
r = []
for j in range(ndmas):
r.append(("n"+str(j), pixel_layout(pack_factor)))
return r

bpc_phy = 8
phy_layout_s = [
("cb_cr", bpc_phy),
Expand All @@ -32,6 +38,11 @@ def phy_layout(pack_factor):
r.append(("p"+str(i), phy_layout_s))
return r

def phy_layout_c(pack_factor, ndmas):
r = [("hsync", 1), ("vsync", 1), ("de", 1)]
for j in range(ndmas):
r.append(("n"+str(j), phy_layout(pack_factor)[3:]))
return r

class FrameInitiator(spi.SingleGenerator):
def __init__(self, bus_aw, pack_factor, ndmas=1):
Expand Down Expand Up @@ -63,7 +74,7 @@ def dma_subr(self, i=0):


class VTG(Module):
def __init__(self, pack_factor):
def __init__(self, pack_factor, ndmas):
hbits_dyn = _hbits - log2_int(pack_factor)
timing_layout = [
("hres", hbits_dyn),
Expand All @@ -75,8 +86,8 @@ def __init__(self, pack_factor):
("vsync_end", _vbits),
("vscan", _vbits)]
self.timing = Sink(timing_layout)
self.pixels = Sink(pixel_layout(pack_factor))
self.phy = Source(phy_layout(pack_factor))
self.pixels = Sink(pixel_layout_c(pack_factor, ndmas))
self.phy = Source(phy_layout_c(pack_factor, ndmas))
self.busy = Signal()

###
Expand All @@ -92,8 +103,12 @@ def __init__(self, pack_factor):
self.comb += [
active.eq(hactive & vactive),
If(active,
[getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:])
for p in ["p"+str(i) for i in range(pack_factor)] for c in ["y", "cb_cr"]],
[getattr(getattr(getattr(self.phy.payload, n), p), c).
eq(getattr(getattr(getattr(self.pixels.payload, n), p), c)[skip:])
for n in ["n"+str(i) for i in range(ndmas)]
for p in ["p"+str(i) for i in range(pack_factor)]
for c in ["y", "cb_cr"]],

self.phy.de.eq(1)
),
self.pixels.ack.eq(self.phy.ack & active)
Expand Down
Loading