Last active
September 20, 2024 20:41
-
-
Save hinzundcode/129d0f81fe24257240d55401f04cdb5a to your computer and use it in GitHub Desktop.
fomu litex vga
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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