# 基于 Ben Eater 原则在 FPGA 上实现 VGA 显卡
熟悉 HDL 的开发者会欣赏从 Turing Complete 仿真转向真实硬件实现的转变。本项目借鉴了 Ben Eater 在其离散逻辑视频课程中的理念,在 FPGA 上构建了一个简单的显卡。它使用 Altera EP4CE15F23C8N 芯片,包含 15,000 个逻辑单元,通过标准的 800x600@60Hz 时序连接到 VGA。50 MHz 系统时钟除以 5 产生 10 MHz,与原项目匹配。
ClockDivider 模块处理时钟分频:
module ClockDivider
(
input wire clk,
output reg clk_out
);
reg [2:0] DATA;
always @(posedge clk)
begin
if(DATA == 3'd4)
begin
DATA <= 3'd0;
clk_out <= 1'd1;
end
else
begin
clk_out <= 1'd0;
DATA <= DATA + 1'd1;
end
end
endmodule
FPGA 开发中的 Verilog 特性
Verilog 与命令式语言不同,其特点是并行执行。变量分为两类:reg(保持状态)和 wire(无存储的简单连线)。赋值运算符会产生不同的硬件电路:
- assign 用于组合逻辑:
wire a,b,c;
assign c = a & b;
- always @(...) =(阻塞式)用于块内顺序执行。
- always @(posedge clk) <=(非阻塞式)用于时钟寄存器:
reg A;
always @(posedge clk)
begin
A <= ~A;
end
模块参数使用 #() 定义,带有默认值,并在实例化时按名称传递。`define 指令因预处理器问题而不推荐使用。
VGA 时序计数器
水平计数器跟踪一行中的像素:
module HorizontalCounter
#(
parameter ENDSTRING = 0
)
(
input wire clk,
output reg [8:0] DATA
);
always @(posedge clk )
begin
if(DATA == ENDSTRING) DATA <= 9'd0;
else DATA <= DATA + 1'd1;
end
endmodule
垂直计数器在每行结束时递增:
module VerticalCounter
#(
parameter ENDFRAME = 0,
parameter ENDSTRING = 0
)
(
input wire clk,
input reg [8:0] Hor_count,
output reg [10:0] DATA
);
always @(posedge clk )
begin
if(DATA == ENDFRAME) DATA <= 11'd0;
else if (Hor_count == ENDSTRING) DATA <= DATA + 1'd1;
end
endmodu
像 Hsync、Vsync、Hblank 和 Vblank 这样的信号根据 tinyvga.com 的时序进行断言(前后廊值在 H_count 和 V_count 的 case 语句中指定)。
生成视频数据
可见区域分辨率为 100x75 像素,颜色深度为 2 位(每个 RGB 通道 4 级,打包成 6 位)。图像在 Photoshop 中准备:调整大小至 100x75,转换为带自定义调色板(0x00/0x55/0xaa/0xff)的索引颜色,并导出为 8 位 BMP。
一个 C++ 工具将 BMP 转换为 Verilog 内存数组 mem[]:
#include <windows.h>
#include <iostream>
// ... (full code parsera BMP with SetPixCollor for mappinga palitry in 6-bitnye values)
SetPixCollor 函数将 RGB 值编码成位(R2R1 G2G1 B2B1)。输出 mem_block.txt 加载到 FPGA ROM 中,使用 Hor_count[6:0] 和 V_count[6:0] 寻址。
- 加载 BMP 并验证头(bfType=0x4D42, biBitCount=8)。
- 读取 RGBQUAD[256] 调色板。
- 解析像素并映射到 6 位值。
- 生成 Verilog 代码以及 ASCII 可视化。
集成与调试
在 Quartus Prime 中进行组装:模块使用如 ENDSTRING=799 和 ENDFRAME=624 等参数实例化。USB Blaster 需要自定义固件以可靠运行。Quartus 仿真器代替传统调试器,显示 clk_out、H_count 和 RGB 等信号的示波图。
关键点:
- Verilog 的并行性要求在使用寄存器时采用非阻塞赋值。
- VGA 时序至关重要:800x600@60Hz 需要 10 MHz 像素时钟。
- 2 位颜色使 ROM 简单(7500x6 位),同时保持渐变。
- FPGA 设置经济:最小化开发板无额外组件 + 标准 VGA 线缆。
- 调试完全在仿真中进行,避免运行时问题。
— Editorial Team
暂无评论。