Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: whitequark/glasgow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 65b3b2cd767d
Choose a base ref
...
head repository: whitequark/glasgow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c9af4768db0c
Choose a head ref
  • 1 commit
  • 5 files changed
  • 1 contributor

Commits on Dec 1, 2018

  1. Copy the full SHA
    c9af476 View commit details
1 change: 1 addition & 0 deletions software/glasgow/applet/__init__.py
Original file line number Diff line number Diff line change
@@ -357,3 +357,4 @@ def run_test():
from .swd import SWDApplet
from .uart import UARTApplet
from .vga_output import VGAOutputApplet
from .vga_terminal import VGATerminalApplet
82 changes: 45 additions & 37 deletions software/glasgow/applet/vga_output/__init__.py
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ def __init__(self, pads):


class VGAOutputSubtarget(Module):
def __init__(self, pads, v_front, v_sync, v_back, v_active, h_front, h_sync, h_back, h_active,
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)

@@ -41,49 +41,54 @@ def __init__(self, pads, v_front, v_sync, v_back, v_active, h_front, h_sync, h_b
h_total = h_front + h_sync + h_back + h_active
v_total = v_front + v_sync + v_back + v_active

self.h_ctr = h_ctr = Signal(max=h_total)
self.v_ctr = v_ctr = Signal(max=v_total)
self.pix = pix = Record([
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([
("r", 1),
("g", 1),
("b", 1),
])

h_en = Signal()
v_en = Signal()
self.comb += [
self.h_stb.eq(self.h_ctr == h_active),
self.v_stb.eq(self.h_stb & (self.v_ctr == v_active)),
]
self.sync.pix += [
If(h_ctr == h_total - 1,
If(v_ctr == v_total - 1,
v_ctr.eq(0)
If(self.h_ctr == h_total - 1,
If(self.v_ctr == v_total - 1,
self.v_ctr.eq(0)
).Else(
v_ctr.eq(v_ctr + 1)
self.v_ctr.eq(self.v_ctr + 1)
),
h_ctr.eq(0),
self.h_ctr.eq(0),
).Else(
h_ctr.eq(h_ctr + 1)
self.h_ctr.eq(self.h_ctr + 1)
),
If(h_ctr == 0,
h_en.eq(1),
).Elif(h_ctr == h_active,
h_en.eq(0),
).Elif(h_ctr == h_active + h_front,
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(h_ctr == h_active + h_front + h_sync,
).Elif(self.h_ctr == h_active + h_front + h_sync,
output.hs.eq(0)
),
If(v_ctr == 0,
v_en.eq(1),
).Elif(v_ctr == v_active,
v_en.eq(0),
).Elif(v_ctr == v_active + v_front,
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(v_ctr == v_active + v_front + v_sync,
).Elif(self.v_ctr == v_active + v_front + v_sync,
output.vs.eq(0)
),
If(v_en & h_en,
output.r.eq(pix.r),
output.g.eq(pix.g),
output.b.eq(pix.b),
If(self.v_en & self.h_en,
output.r.eq(self.pix.r),
output.g.eq(self.pix.g),
output.b.eq(self.pix.b),
).Else(
output.r.eq(0),
output.g.eq(0),
@@ -149,26 +154,29 @@ def add_build_arguments(cls, parser, access):
"-va", "--v-active", metavar="N", type=int, default=480,
help="set vertical resolution to N line clocks (default: %(default)s)")

def build(self, target, args):
def build(self, target, args, test_pattern=True):
self.mux_interface = iface = target.multiplexer.claim_interface(self, args)
subtarget = iface.add_subtarget(VGAOutputSubtarget(
pads=iface.get_pads(args, pins=self.__pins),
v_front=args.v_front,
v_sync=args.v_sync,
v_back=args.v_back,
v_active=args.v_active,
h_front=args.h_front,
h_sync=args.h_sync,
h_back=args.h_back,
h_active=args.h_active,
v_front=args.v_front,
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_period_constraint(subtarget.cd_pix.clk, 1e3 / args.pix_clk_freq)

subtarget.comb += \
Cat(subtarget.pix.r, subtarget.pix.g, subtarget.pix.b) \
.eq(subtarget.h_ctr[5:] + subtarget.v_ctr[5:])
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):
return await device.demultiplexer.claim_interface(self, self.mux_interface, args)
2 changes: 2 additions & 0 deletions software/glasgow/applet/vga_terminal/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ibmvga*.bin extracted from ROM BIOS for IBM VGA Adapter. Typefaces cannot be
protected by copyright in the United States per 37 CFR 202.1(e).
156 changes: 156 additions & 0 deletions software/glasgow/applet/vga_terminal/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import logging
import argparse
import os
from migen import *

from .. import *
from ..vga_output import VGAOutputApplet


class VGATerminalSubtarget(Module):
def __init__(self, vga, h_active, v_active, font_data, font_width, font_height, blink_cyc,
char_mem_init=[], attr_mem_init=[]):
char_mem = Memory(width=8, depth=(h_active // font_width) * (v_active // font_height),
init=char_mem_init)
attr_mem = Memory(width=5, depth=char_mem.depth,
init=attr_mem_init)
self.specials += [char_mem, attr_mem]

char_rdport = char_mem.get_port(has_re=True, clock_domain="pix")
attr_rdport = attr_mem.get_port(has_re=True, clock_domain="pix")
self.specials += [char_rdport, attr_rdport]

char_ctr = Signal(max=char_mem.depth)
char_l_ctr = Signal.like(char_ctr)
char_data = Signal.like(char_rdport.dat_r)
attr_data = Signal.like(attr_rdport.dat_r)
self.comb += [
char_rdport.re.eq(1),
char_rdport.adr.eq(char_ctr),
char_data.eq(char_rdport.dat_r),
attr_rdport.re.eq(1),
attr_rdport.adr.eq(char_ctr),
attr_data.eq(attr_rdport.dat_r),
]

font_mem = Memory(width=font_width, depth=font_height * 256, init=font_data)
self.specials += font_mem

font_rdport = font_mem.get_port(has_re=True, clock_domain="pix")
self.specials += font_rdport

font_h_ctr = Signal(max=font_width)
font_v_ctr = Signal(max=font_height)
font_line = Signal(font_width)
font_shreg = Signal.like(font_line)
attr_reg = Signal.like(attr_data)
undrl_reg = Signal()
self.comb += [
font_rdport.re.eq(1),
font_rdport.adr.eq(char_data * font_height + font_v_ctr),
font_line.eq(Cat(reversed([font_rdport.dat_r[n] for n in range(font_width)])))
]
self.sync.pix += [
If(vga.v_stb,
char_ctr.eq(0),
char_l_ctr.eq(0),
font_v_ctr.eq(0),
font_h_ctr.eq(0),
).Elif(vga.h_stb & vga.v_en,
If(font_v_ctr == font_height - 1,
char_l_ctr.eq(char_ctr),
font_v_ctr.eq(0),
).Else(
char_ctr.eq(char_l_ctr),
font_v_ctr.eq(font_v_ctr + 1),
),
font_h_ctr.eq(0),
).Elif(vga.v_en & vga.h_en,
If(font_h_ctr == 0,
char_ctr.eq(char_ctr + 1)
),
If(font_h_ctr == font_width - 1,
font_h_ctr.eq(0),
).Else(
font_h_ctr.eq(font_h_ctr + 1),
)
),
If(~vga.h_en | (font_h_ctr == font_width - 1),
font_shreg.eq(font_line),
attr_reg.eq(attr_data),
undrl_reg.eq(font_v_ctr == font_height - 1),
).Else(
font_shreg.eq(font_shreg[1:])
)
]

blink_ctr = Signal(max=blink_cyc)
blink_reg = Signal()
self.sync.pix += [
If(blink_ctr == blink_cyc - 1,
blink_ctr.eq(0),
blink_reg.eq(~blink_reg),
).Else(
blink_ctr.eq(blink_ctr + 1),
)
]

pix_fg = Signal()
self.comb += [
pix_fg.eq((font_shreg[0] | (undrl_reg & attr_reg[3])) & (~attr_reg[4] | blink_reg)),
vga.pix.r.eq(pix_fg & attr_reg[0]),
vga.pix.g.eq(pix_fg & attr_reg[1]),
vga.pix.b.eq(pix_fg & attr_reg[2]),
]


class VGATerminalApplet(VGAOutputApplet, name="vga-terminal"):
logger = logging.getLogger(__name__)
help = "emulate a teleprinter using a VGA monitor"
description = """
TBD
"""

@classmethod
def add_build_arguments(cls, parser, access):
super().add_build_arguments(parser, access)

parser.add_argument(
"-fd", "--font-data", metavar="FILE", type=argparse.FileType("rb"),
default=os.path.join(os.path.dirname(__file__), "ibmvga8x16.bin"),
help="load character generator ROM from FILE (default: ibmvga8x16.bin)")
parser.add_argument(
"-fw", "--font-width", metavar="PX", type=int, default=8,
help="set font width to PX pixels (default: %(default)s)")
parser.add_argument(
"-fh", "--font-height", metavar="PX", type=int, default=16,
help="set font height to PX pixels (default: %(default)s)")

def build(self, target, args):
vga = super().build(target, args, test_pattern=False)
iface = self.mux_interface

subtarget = iface.add_subtarget(VGATerminalSubtarget(
vga=vga,
h_active=args.h_active,
v_active=args.v_active,
font_data=args.font_data.read(),
font_width=args.font_width,
font_height=args.font_height,
blink_cyc=int(args.pix_clk_freq * 1e6 / 2),
char_mem_init=
b"Hello world! " +
b"0123456789" * 120 +
b" imgay",
attr_mem_init=
[0x7] * 13 +
(list(range(9,16)) + list(range(1,8))) * 86 +
[16|3,16|5,16|7,16|5,16|3],
))

# -------------------------------------------------------------------------------------------------

class VGATerminalAppletTestCase(GlasgowAppletTestCase, applet=VGATerminalApplet):
@synthesis_test
def test_build(self):
self.assertBuilds(args=["--port", "B"])
Binary file not shown.