From 22792c1300843ae4556dcf5cc4e771d97a6c1414 Mon Sep 17 00:00:00 2001 From: Jens True Date: Sun, 11 Nov 2018 10:25:27 +0100 Subject: [PATCH] Original import --- vga640x480.v | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 vga640x480.v diff --git a/vga640x480.v b/vga640x480.v new file mode 100644 index 0000000..42e91f3 --- /dev/null +++ b/vga640x480.v @@ -0,0 +1,78 @@ +// FPGA VGA Graphics Part 1: 640x480 60Hz VGA Driver +// (C)2017-2018 Will Green - Licensed under the MIT License +// Learn more at https://timetoexplore.net/blog/arty-fpga-vga-verilog-01 + +// For 60 Hz VGA i_pix_stb must be 25 MHz or 25.175 MHz +// Details in tutorial: https://timetoexplore.net/blog/arty-fpga-vga-verilog-01 + +`default_nettype none + +module vga640x480( + input wire i_clk, // base clock + input wire i_pix_stb, // pixel clock strobe + input wire i_rst, // reset: restarts frame + output wire o_hs, // horizontal sync + output wire o_vs, // vertical sync + output wire o_blanking, // high during blanking interval + output wire o_active, // high during active pixel drawing + output wire o_screenend, // high for one tick at the end of screen + output wire o_animate, // high for one tick at end of active drawing + output wire [9:0] o_x, // current pixel x position + output wire [8:0] o_y // current pixel y position + ); + + // VGA timings https://timetoexplore.net/blog/video-timings-vga-720p-1080p + localparam HS_STA = 16; // horizontal sync start + localparam HS_END = 16 + 96; // horizontal sync end + localparam HA_STA = 16 + 96 + 48; // horizontal active pixel start + localparam VS_STA = 480 + 11; // vertical sync start + localparam VS_END = 480 + 11 + 2; // vertical sync end + localparam VA_END = 480; // vertical active pixel end + localparam LINE = 800; // complete line (pixels) + localparam SCREEN = 524; // complete screen (lines) + + reg [9:0] h_count; // line position + reg [9:0] v_count; // screen position + + // generate sync signals (active low for 640x480) + assign o_hs = ~((h_count >= HS_STA) & (h_count < HS_END)); + assign o_vs = ~((v_count >= VS_STA) & (v_count < VS_END)); + + // keep x and y bound within the active pixels + assign o_x = (h_count < HA_STA) ? 0 : (h_count - HA_STA); + assign o_y = (v_count >= VA_END) ? (VA_END - 1) : (v_count); + + // blanking: high within the blanking period + assign o_blanking = ((h_count < HA_STA) | (v_count > VA_END - 1)); + + // active: high during active pixel drawing + assign o_active = ~((h_count < HA_STA) | (v_count > VA_END - 1)); + + // screenend: high for one tick at the end of the screen + assign o_screenend = ((v_count == SCREEN - 1) & (h_count == LINE)); + + // animate: high for one tick at the end of the final active pixel line + assign o_animate = ((v_count == VA_END - 1) & (h_count == LINE)); + + always @ (posedge i_clk) + begin + if (i_rst) // reset to start of frame + begin + h_count <= 0; + v_count <= 0; + end + if (i_pix_stb) // once per pixel + begin + if (h_count == LINE) // end of line + begin + h_count <= 0; + v_count <= v_count + 1; + end + else + h_count <= h_count + 1; + + if (v_count == SCREEN) // end of screen + v_count <= 0; + end + end +endmodule