Skip to content

Instantly share code, notes, and snippets.

@hinzundcode
Last active September 20, 2024 20:41
Show Gist options
  • Save hinzundcode/129d0f81fe24257240d55401f04cdb5a to your computer and use it in GitHub Desktop.
Save hinzundcode/129d0f81fe24257240d55401f04cdb5a to your computer and use it in GitHub Desktop.
fomu litex vga
user_1 is R, G and B (VGA pins 1, 2 and 3)
user_2 is Ground
user_3 is HSYNC (VGA pin 13)
user_4 is VSYNC (VGA pin 15)
$ python workshop_vga.py --board pvt && dfu-util -D build/gateware/top.dfu
$ wishbone-tool 0x60003000 150
csr_register,gpu_x0,0x60003000,2,rw
csr_register,gpu_x1,0x60003008,2,rw
csr_register,gpu_y0,0x60003010,2,rw
csr_register,gpu_y1,0x60003018,2,rw
module gpu(clk, hsync, vsync, color, x0, x1, y0, y1);
input clk;
output hsync, vsync;
output color;
wire pclk;
wire display_on;
wire signed [15:0] hpos;
wire signed [15:0] vpos;
input signed [15:0] x0;
input signed [15:0] x1;
input signed [15:0] y0;
input signed [15:0] y1;
// VGA 640x480 @60Hz needs a 25.175MHz pixel clock
// but the PLL is already in use
// I split the horizontal resolution in half and use the existing 12MHz clock instead
// front and back porch are manually adjusted until VSYNC reaches the expected 60Hz
hvsync_generator #(
.H_DISPLAY(320), // horizontal display width
.H_BACK(12), // horizontal left border (back porch)
.H_FRONT(8), // horizontal right border (front porch)
.H_SYNC(48), // horizontal sync width
.V_DISPLAY(480), // vertical display height
.V_TOP(33), // vertical top border
.V_BOTTOM(8), // vertical bottom border
.V_SYNC(2), // vertical s
) hvsync_gen (
.clk(clk),
.reset(0),
.hsync(hsync),
.vsync(vsync),
.display_on(display_on),
.hpos(hpos),
.vpos(vpos),
);
assign color = display_on && (hpos >= x0 && hpos < x1 && vpos >= y0 && vpos < y1);
endmodule
// from https://8bitworkshop.com/v3.6.0/?file=hvsync_generator.v&platform=verilog-vga
module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos);
input clk;
input reset;
output reg hsync, vsync;
output display_on;
output reg signed [15:0] hpos;
output reg signed [15:0] vpos;
// declarations for TV-simulator sync parameters
// horizontal constants
parameter H_DISPLAY = 640; // horizontal display width
parameter H_BACK = 48; // horizontal left border (back porch)
parameter H_FRONT = 16; // horizontal right border (front porch)
parameter H_SYNC = 96; // horizontal sync width
// vertical constants
parameter V_DISPLAY = 480; // vertical display height
parameter V_TOP = 33; // vertical top border
parameter V_BOTTOM = 10; // vertical bottom border
parameter V_SYNC = 2; // vertical sync # lines
// derived constants
parameter H_SYNC_START = H_DISPLAY + H_FRONT;
parameter H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1;
parameter H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1;
parameter V_SYNC_START = V_DISPLAY + V_BOTTOM;
parameter V_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1;
parameter V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1;
wire hmaxxed = (hpos == H_MAX) || reset; // set when hpos is maximum
wire vmaxxed = (vpos == V_MAX) || reset; // set when vpos is maximum
// horizontal position counter
always @(posedge clk)
begin
hsync <= (hpos>=H_SYNC_START && hpos<=H_SYNC_END);
if(hmaxxed)
hpos <= 0;
else
hpos <= hpos + 1;
end
// vertical position counter
always @(posedge clk)
begin
vsync <= (vpos>=V_SYNC_START && vpos<=V_SYNC_END);
if(hmaxxed)
if (vmaxxed)
vpos <= 0;
else
vpos <= vpos + 1;
end
// display_on is set when beam is in "safe" visible frame
assign display_on = (hpos<H_DISPLAY) && (vpos<V_DISPLAY);
endmodule
#!/usr/bin/env python3
# This variable defines all the external programs that this module
# relies on. lxbuildenv reads this variable in order to ensure
# the build will finish without exiting due to missing third-party
# programs.
LX_DEPENDENCIES = ["icestorm", "yosys", "nextpnr-ice40"]
#LX_CONFIG = "skip-git" # This can be useful for workshops
# Import lxbuildenv to integrate the deps/ directory
import os,os.path,shutil,sys,subprocess
sys.path.insert(0, os.path.dirname(__file__))
import lxbuildenv
# Disable pylint's E1101, which breaks completely on migen
#pylint:disable=E1101
from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer
from litex.soc.integration.soc_core import SoCCore
from litex.soc.integration.builder import Builder
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage
from litex_boards.partner.targets.fomu import BaseSoC, add_dfu_suffix
from valentyusb.usbcore import io as usbio
from valentyusb.usbcore.cpu import dummyusb
import argparse
class GPU(Module, AutoCSR):
def __init__(self, pins, clk):
self.x0 = CSRStorage(16, reset=100)
self.x1 = CSRStorage(16, reset=150)
self.y0 = CSRStorage(16, reset=100)
self.y1 = CSRStorage(16, reset=200)
self.comb += [
pins[1].eq(0),
]
self.specials += Instance(
'gpu',
i_clk=clk,
i_x0=self.x0.storage,
i_x1=self.x1.storage,
i_y0=self.y0.storage,
i_y1=self.y1.storage,
o_hsync=pins[2],
o_vsync=pins[3],
o_color=pins[0]
)
def main():
parser = argparse.ArgumentParser(
description="Build Fomu Main Gateware")
parser.add_argument(
"--seed", default=0, help="seed to use in nextpnr"
)
parser.add_argument(
"--placer", default="heap", choices=["sa", "heap"], help="which placer to use in nextpnr"
)
parser.add_argument(
"--board", choices=["evt", "pvt", "hacker"], required=True,
help="build for a particular hardware board"
)
args = parser.parse_args()
soc = BaseSoC(args.board, pnr_seed=args.seed, pnr_placer=args.placer, usb_bridge=True)
# Add the LED driver block. Get the `rgb_led` pins from the definition
# file, then instantiate the module we defined above.
touch_pins = [soc.platform.request('user_touch_n', i) for i in range(0, 4)]
clk = soc.crg.cd_sys.clk
soc.submodules.gpu = GPU(touch_pins, clk)
# Indicate that `fomu_rgb` is a CSR, and should be added to the bus.
# Otherwise we wouldn't be able to access `fomu_rgb` at all.
# Note that the value here must match the value above, so if you did
# `soc.submodules.frgb = FomuRGB(led_pads)` then you would need to
# change this to `soc.add_csr("frgb")`.
soc.add_csr("gpu")
soc.platform.add_source("hvsync_generator.v")
soc.platform.add_source("gpu.v")
builder = Builder(soc,
output_dir="build", csr_csv="build/csr.csv",
compile_software=False)
vns = builder.build()
soc.do_exit(vns)
add_dfu_suffix(os.path.join('build', 'gateware', 'top.bin'))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment