Skip to content

Commit

Permalink
applet.video.vga_output: convert to nmigen
Browse files Browse the repository at this point in the history
  • Loading branch information
attie-argentum committed Nov 12, 2020
1 parent c60a65d commit a66fe3a
Showing 1 changed file with 98 additions and 74 deletions.
172 changes: 98 additions & 74 deletions software/glasgow/applet/video/vga_output/__init__.py
Original file line number Diff line number Diff line change
@@ -1,100 +1,132 @@
import logging
from nmigen.compat import *
from nmigen import *
from nmigen.hdl.cd import ClockDomain
from nmigen.hdl.rec import Record

from ....gateware.pads import *
from ....gateware.pll import *
from ... import *


class VGAOutput(Module):
class VGAOutput(Elaboratable):
def __init__(self, pads):
self.pads = pads

self.hs = Signal()
self.vs = Signal()
self.r = Signal()
self.g = Signal()
self.b = Signal()

###

self.comb += [
pads.hs_t.oe.eq(1),
pads.hs_t.o.eq(self.hs),
pads.vs_t.oe.eq(1),
pads.vs_t.o.eq(self.vs),
pads.r_t.oe.eq(1),
pads.r_t.o.eq(self.r),
pads.g_t.oe.eq(1),
pads.g_t.o.eq(self.g),
pads.b_t.oe.eq(1),
pads.b_t.o.eq(self.b),
def elaborate(self, platform):
m = Module()

m.d.comb += [
self.pads.hs_t.oe.eq(1),
self.pads.hs_t.o.eq(self.hs),
self.pads.vs_t.oe.eq(1),
self.pads.vs_t.o.eq(self.vs),
self.pads.r_t.oe.eq(1),
self.pads.r_t.o.eq(self.r),
self.pads.g_t.oe.eq(1),
self.pads.g_t.o.eq(self.g),
self.pads.b_t.oe.eq(1),
self.pads.b_t.o.eq(self.b),
]

return m

class VGAOutputSubtarget(Module):
def __init__(self, pads, h_front, h_sync, h_back, h_active, v_front, v_sync, v_back, v_active,
sys_clk_freq, pix_clk_freq):
self.submodules.output = output = VGAOutput(pads)

self.clock_domains.cd_pix = ClockDomain(reset_less=True)
self.specials += PLL(f_in=sys_clk_freq, f_out=pix_clk_freq, odomain="pix")
class VGAOutputSubtarget(Elaboratable):
def __init__(self, pads, h_front, h_sync, h_back, h_active, v_front, v_sync, v_back, v_active, pix_clk_freq):
self.pads = pads
self.h_front = h_front
self.h_sync = h_sync
self.h_back = h_back
self.h_active = h_active
self.v_front = v_front
self.v_sync = v_sync
self.v_back = v_back
self.v_active, = v_active,
self.pix_clk_freq = pix_clk_freq

h_total = h_front + h_sync + h_back + h_active
v_total = v_front + v_sync + v_back + v_active
self.h_total = self.h_front + self.h_sync + self.h_back + self.h_active
self.v_total = self.v_front + self.v_sync + self.v_back + self.v_active

self.h_ctr = Signal(max=h_total)
self.v_ctr = Signal(max=v_total)
self.h_en = Signal()
self.v_en = Signal()
self.h_stb = Signal()
self.v_stb = Signal()
self.pix = Record([
self.h_ctr = Signal(range(self.h_total))
self.v_ctr = Signal(range(self.v_total))
self.pix = Record([
("r", 1),
("g", 1),
("b", 1),
])
self.comb += [
self.h_stb.eq(self.h_ctr == h_active),
self.v_stb.eq(self.h_stb & (self.v_ctr == v_active)),

def elaborate(self, platform):
m = Module()

m.submodules.output = output = VGAOutput(self.pads)

# TDOD: re-assert the clock constraint?
m.domains.pix = ClockDomain(reset_less=True)
m.submodules += PLL(f_in=platform.default_clk_frequency, f_out=self.pix_clk_freq, odomain="pix")
#platform.add_clock_constraint(m.domains.pix.clk, self.pix_clk_freq)

h_en = Signal()
v_en = Signal()
h_stb = Signal()
v_stb = Signal()

m.d.comb += [
h_stb.eq(self.h_ctr == self.h_active),
v_stb.eq(h_stb & (self.v_ctr == self.v_active)),
]
self.sync.pix += [
If(self.h_ctr == h_total - 1,
If(self.v_ctr == v_total - 1,
self.v_ctr.eq(0)
).Else(
self.v_ctr.eq(self.v_ctr + 1)
),
self.h_ctr.eq(0),
).Else(
self.h_ctr.eq(self.h_ctr + 1)
),
If(self.h_ctr == 0,
self.h_en.eq(1),
).Elif(self.h_ctr == h_active,
self.h_en.eq(0),
).Elif(self.h_ctr == h_active + h_front,
output.hs.eq(1)
).Elif(self.h_ctr == h_active + h_front + h_sync,
output.hs.eq(0)
),
If(self.v_ctr == 0,
self.v_en.eq(1),
).Elif(self.v_ctr == v_active,
self.v_en.eq(0),
).Elif(self.v_ctr == v_active + v_front,
output.vs.eq(1)
).Elif(self.v_ctr == v_active + v_front + v_sync,
output.vs.eq(0)
),
If(self.v_en & self.h_en,

with m.If(self.h_ctr == self.h_total - 1):
with m.If(self.v_ctr == self.v_total - 1):
m.d.pix += self.v_ctr.eq(0)
with m.Else():
m.d.pix += self.v_ctr.eq(self.v_ctr + 1)
m.d.pix += self.h_ctr.eq(0)
with m.Else():
m.d.pix += self.h_ctr.eq(self.h_ctr + 1)

with m.If(self.h_ctr == 0):
m.d.pix += h_en.eq(1)
with m.Elif(self.h_ctr == self.h_active):
m.d.pix += h_en.eq(0)
with m.Elif(self.h_ctr == self.h_active + self.h_front):
m.d.pix += output.hs.eq(1)
with m.Elif(self.h_ctr == self.h_active + self.h_front + self.h_sync):
m.d.pix += output.hs.eq(0)

with m.If(self.v_ctr == 0):
m.d.pix += v_en.eq(1)
with m.Elif(self.v_ctr == self.v_active):
m.d.pix += v_en.eq(0)
with m.Elif(self.v_ctr == self.v_active + self.v_front):
m.d.pix += output.vs.eq(1)
with m.Elif(self.v_ctr == self.v_active + self.v_front + self.v_sync):
m.d.pix += output.vs.eq(0)

with m.If(v_en & h_en):
m.d.pix += [
output.r.eq(self.pix.r),
output.g.eq(self.pix.g),
output.b.eq(self.pix.b),
).Else(
]
with m.Else():
m.d.pix += [
output.r.eq(0),
output.g.eq(0),
output.b.eq(0),
)
]
]

# TODO: relocate out of the module
m.d.comb += \
Cat(self.pix.r, self.pix.g, self.pix.b) \
.eq(self.h_ctr[5:] + self.v_ctr[5:])

return m


# video video graphics adapter is dumb, so the applet is just called VGAOutputApplet
Expand Down Expand Up @@ -167,16 +199,8 @@ def build(self, target, args, test_pattern=True):
v_sync=args.v_sync,
v_back=args.v_back,
v_active=args.v_active,
sys_clk_freq=target.sys_clk_freq,
pix_clk_freq=args.pix_clk_freq * 1e6,
))
target.platform.add_clock_constraint(subtarget.cd_pix.clk, args.pix_clk_freq * 1e6)

if test_pattern:
subtarget.comb += \
Cat(subtarget.pix.r, subtarget.pix.g, subtarget.pix.b) \
.eq(subtarget.h_ctr[5:] + subtarget.v_ctr[5:])

return subtarget

async def run(self, device, args):
Expand Down

0 comments on commit a66fe3a

Please sign in to comment.