名称:俄罗斯方块 FPGA 游戏 Verilog Vivado
软件:Vivado
语言:Verilog
功能介绍
本设计实现了一个 FPGA 俄罗斯方块游戏,采用 Verilog 编写,工程环境为 Vivado。系统包含游戏运行控制、方块移动与旋转、地图存储、下一个方块提示、分数控制、按键消抖、时间节拍以及 VGA/HDMI 显示输出等功能模块,可在开发板上实现可交互的俄罗斯方块显示与操作。
玩家可通过按键控制方块左移、右移和旋转,通过开关进行暂停和速度档位选择。游戏逻辑会根据地图边界、墙体区域和已固定方块位置判断移动是否合法,并在方块下落、堆叠、消行和分数更新等环节提供完整的硬件逻辑支撑。
显示部分面向像素坐标生成彩色画面,能够输出游戏地图、墙体、当前活动方块和下一个方块提示等内容。工程还包含 VGA 转 HDMI 相关模块,适合用于学习 FPGA 游戏逻辑设计、视频时序显示、按键控制和多模块协同设计。
运行环境
开发语言:Verilog
开发软件:Vivado
工程类型:FPGA 俄罗斯方块游戏设计
显示相关:VGA 显示驱动,配套 VGA 转 HDMI 输出模块
验证条件:包含仿真测试文件 TetrisTop_tb.v,包含 Urbana 开发板相关约束与开发板图片
设计思路
设计以俄罗斯方块的状态更新和像素级显示输出为主线,将游戏逻辑、地图存储、方块移动变换、当前方块显示、下一个方块提示和外设输入分开实现。按键输入经过消抖处理后送入游戏控制模块,控制当前方块左右移动和形态旋转;速度开关用于改变下落节奏,暂停开关用于控制游戏运行状态。
地图部分负责保存已落定方块的位置,并根据当前活动方块叠加生成显示画面。方块变换模块处理不同形状在不同旋转状态下的坐标关系,移动控制模块根据边界、墙体和地图占用情况判断操作是否有效,避免方块越界或与已有方块冲突。
显示链路按照坐标扫描方式工作,VGA/HDMI 相关模块根据 x_addr、y_addr 等像素坐标输出 RGB 数据。游戏区域、墙体、当前方块、下一个方块提示以及分数相关显示由不同显示模块协同生成,最终合成为视频输出数据,适合学习 FPGA 图形显示类小游戏的完整实现流程。
模块结构
主要模块包括:
main:工程顶层连接模块,完成时钟、按键、开关、显示输出等外设信号组织。
TetrisTop:俄罗斯方块核心顶层,连接游戏状态、地图、当前方块、下一个方块和显示数据输出。
TerisGaming:游戏运行状态控制模块,负责运行、暂停等状态管理。
TerisMoveChange:方块移动与旋转控制模块,处理左移、右移、变形和边界判断。
TerisMapStorage:地图存储模块,保存已固定方块并配合消行、得分逻辑。
TerisMapDisplay、TerisCurrChartDisplay、TerisNextCharDisplay、TerisDisplay:显示生成相关模块,用于输出地图、当前方块、下一个方块和综合显示内容。
TerisNextIndex、TerisNextChart:下一个方块序列与图形生成模块。
TerisWall:游戏边界墙体显示与判断模块。
btn_dis_shake:按键消抖模块。
TIME、score_ctrl、hex_driver、nibble_to_hex:时间、分数和数码管显示相关模块。
VGA_Driver、hdmi_tx_v1_0、encode、serdes_10_to_1、srldelay:视频时序与 HDMI 输出相关模块。
开发板验证
工程包含面向 Urbana 开发板的管脚约束文件,并配套开发板实物图片,可用于将俄罗斯方块显示与按键控制逻辑下载到板级环境中验证。约束内容覆盖板卡外设连接,适合在 Vivado 中完成综合、实现与管脚分配后进行实际显示输出测试。
板级验证重点包括按键输入、暂停控制、速度档位切换以及视频显示输出等功能。通过开发板按键可触发方块左移、右移和旋转,开关可用于暂停与速度选择,显示端用于观察当前方块、下一个方块、地图区域和游戏状态。
仿真图/仿真说明/设计文档图片
工程包含 TetrisTop_tb 仿真测试模块,用于对 TetrisTop 核心逻辑进行行为级验证。测试激励包含时钟与复位产生、像素坐标扫描、左移按键、右移按键、旋转按键、暂停开关和速度档位切换等输入过程,可观察 score_add 与 odata 等输出信号随游戏控制变化的响应。
部分代码
以下展示顶层模块 TetrisTop_tb 的部分代码,完整源码请下载压缩包查看。
module TetrisTop_tb;
reg clk;
reg rst;
reg stop_sw;
reg [1:0] speed_sw;
reg KeyLeft;
reg KeyRight;
reg KeyChange;
reg [8:0] x_addr;
reg [8:0] y_addr;
wire score_add;
wire [23:0] odata;
TetrisTop dut (
.clk(clk),
.rst(rst),
.stop_sw(stop_sw),
.speed_sw(speed_sw),
.KeyLeft(KeyLeft),
.KeyRight(KeyRight),
.KeyChange(KeyChange),
.x_addr(x_addr),
.y_addr(y_addr),
.score_add(score_add),
.odata(odata)
);
initial clk = 1\'b0;
always #10 clk = ~clk;
initial begin
rst = 1\'b0;
stop_sw = 1\'b0;
speed_sw = 2\'b11;
KeyLeft = 1\'b0;
KeyRight = 1\'b0;
KeyChange= 1\'b0;
x_addr = 9\'d0;
y_addr = 9\'d0;
#200 rst = 1\'b1;
end
always @(posedge clk or negedge rst) begin
if (!rst) begin
x_addr <= 9\'d0;
y_addr <= 9\'d0;
end else begin
if (x_addr == 9\'d319) begin
x_addr <= 9\'d0;
if (y_addr == 9\'d239) y_addr <= 9\'d0;
else y_addr <= y_addr + 1\'b1;
end else begin
x_addr <= x_addr + 1\'b1;
end
end
end
initial begin
@(posedge rst);
repeat (4) begin
KeyLeft = 1\'b1; repeat (3) @(posedge clk); KeyLeft = 1\'b0;
repeat (200) @(posedge clk);
KeyRight = 1\'b1; repeat (3) @(posedge clk); KeyRight = 1\'b0;
repeat (200) @(posedge clk);
KeyChange= 1\'b1; repeat (3) @(posedge clk); KeyChange= 1\'b0;
repeat (400) @(posedge clk);
end
end
initial begin
@(posedge rst);
#2000000 stop_sw = 1\'b1;
#200000 stop_sw = 1\'b0;
end
initial begin
@(posedge rst);
#500000 speed_sw = 2\'b01;
#500000 speed_sw = 2\'b10;
#500000 speed_sw = 2\'b11;
end
initial begin
#5000000 $finish;
end
endmodule
108