基于FPGA的俄罗斯方块设计
- 前 言
《俄罗斯方块》的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。该项目基于Xilinx公司的EGO1平台,利用现场可编程门阵列FPGA设计了俄罗斯方块小游戏,并且通过VGA接口来实现对屏幕的控制。整个系统由六个模块组成,分别是键盘输入模块、按键输入处理模块、控制模块、数据路径模块、VGA显示模块以及数码管计分模块。玩家通过键盘上的WASD实现对方块的移动和旋转,并且每消除一行就会进行加分。基本原理是将整个显示屏分为10*20的矩阵,不断对矩阵进行更新和判断是否能消除。俄罗斯方块是一个休闲游戏,它面对的是那些没有精力或兴趣玩大型游戏的玩家,这些人需要一类简单好玩的游戏,拿起来就能进入状态,在忙碌的生活中寻求片刻放松。
- 系统设计
- 俄罗斯方块的总体设计
- 系统结构
- 俄罗斯方块的总体设计
整个系统采用自上向下的层次化设计方法,顶层模块调用键盘控制模块、按键处理模块、控制模块、数据路径模块、VGA显示模块以及玩家计分模块。系统的总体结构如图图 2‑1 RTL顶层逻辑图所示,其中最左侧的为键盘输入模块,将键盘上面的WASD和空格键数据导入。第二级和第三级为按键输入处理模块,对于输入的信号进行消抖和输出上升沿处理。第四级为信号控制模块也就是最主要的状态机模块,即将输入进来的信号进行区分,并且输出状态的控制信号到下一级。第五级为数据控制信号,接受来自状态机的各种状态输出的信号,对背景矩阵进行不断地判断和更新。第六极第一层为数据输出模块,所要输出的数据为背景矩阵要显示的数据。后面几级分别是数码管显示模块和计分模块。
图 2‑1 RTL顶层逻辑图
- 功能设计
基于基本的俄罗斯方块设计方法,设计的俄罗斯方块小游戏可以实现方块的下落、旋转、方块行的消除以及玩家得分的显示。用户通过键盘上面的空格键进行游戏的开始。并通过键盘上面的WASD控制键来实现方块的移动和旋转。当玩家完整的消除一行俄罗斯方块后,数码管上会显示出玩家当前的分数,以供玩家进行参考。如图 2‑2 功能设计展示所示。
图 2‑2 功能设计展示
模块的划分,分别是键盘输入模块、按键输入处理模块、控制模块、数据路径模块、VGA显示模块以及数码管计分模块,展示如图 2‑1 RTL顶层逻辑图所示。
- 系统RTL顶层逻辑和子模块设计思路
- 键盘控制模块
接收键盘传来的数据相对简单,如图 2‑3 键盘信号所示。当时钟Clock的下降沿时,侦测到数据Data也拉低,代表一个数据包传送出来,之后的10个时钟下降沿,分别收到从最低位LSB到MSB的八位数据,1位的奇偶校验(1表示八位数据中1的位数为偶数,0是奇数),最后1位高电平表示数据包结束。时钟信号由K5检测输入,数据Data由L4检测输入。
图 2‑3 键盘信号
对键盘来说,它用的是扫描码,每个按键对应一个代码,当一个按键被按下,每100ms会重复发送一次;当这个按键被松开,一个0xF0被发出,跟着是那个被松开的按键。那些可以被shift的按键,比如大小写字母和可以代表符号的数字键,它的扫描码后面会跟着shift码,FPGA需要根据这个来决定用哪个ASCII字符。有些按键,比如Ctrl和Alt被按下时,会在扫描码前先发一个E0,当它们被松开时,会发E0F0,并跟随着相应按键的扫描码。
键盘按键主要分为三类,图 2‑4 键盘按键码中展示了它们的通码和断码。
图 2‑4 键盘按键码
俄罗斯方块采用的按键均为第一类按键,通码为1字节,断码为0xF0+通码形式。如A键,其通码为 0x1C,断码为0xF0或0x1C。通过寄存输入的通码或者断码来达到输出W/A/S/D/Space的信号目的。
模块在识别到断码时,保持低电平输出,在检测到通码后进行对应的按键高电平输出。
- 按键处理模块
按键处理模块的主要功能是对输入系统的up,down,left,right四个控制信号进行消抖处理,并对其进行上升沿检测。为了简化控制系统,在本系统的设计过程中,不考虑长时间按键产生连按效果。因而,需要对按键进行上升沿检测。上升沿检测的基本实现方案是加入一组寄存器,对前一个的按键信号进行暂存,将暂存的值与当前值进行比较,当上一个值为0而当前值为1时,即认为其检测到了一个上升沿。
图 2‑5 按键处理模块
- 控制模块
控制模块采用有限状态机的方式进行控制,在控制模块中定义了10个状态:
S_idle:空状态,即屏幕显示为空白
S_new:用于产生新的俄罗斯方块。
S_hold:保持状态。在这个状态中进行计时,当时间到达一定间隔时,转到下落状态(S_down);或者等待输入信号(up,down,left,right)时,转到下落状态(S_down)或者(up,left,right)状态。
S_down:判断当前俄罗斯块能否下移一格。如果可以,则转到更新状态,如果不行,则转到更新状态状态。
S_move:判断当前俄罗斯块能够按照按键信号指定的指令进行移动,如果可以,则转到更新状态(S_shift),如果不可以,则转到消除状态1状态(S_remove_1)。
S_shift:更新俄罗斯方块的坐标信息。返回保持状态(S_hold)。
S_remove_1:更新整个屏幕的矩阵信息。转移到消除状态2状态(S_remove_2)。
S_remove_2:判断是否可以消除,将可以消除的行消除,并将上面的行下移一行。重复此过程,直到没有可消除的行为止。跳转判定状态(S_isdie)
S_isdie:判断是否游戏结束。如果结束,则跳转到停止状态(S_stop)。如果没有,则跳转到产生俄罗斯方块状态,生成新的俄罗斯方块。
S_stop:清楚整个屏幕,并跳转到判断状态(S_isdie)。
图 2‑6 状态机总模块
- 数据路径模块
- 方块:
方块分为非活动方块与活动方块。非活动方块为:(1)之前下落的方块;(2)下落后方块消除之后的结果。由背景矩阵表示。活动方块为当前下落中的方块,由活动方块坐标与方块类型表示。
- 背景矩阵
reg [9:0] Background [23:0];
背景矩阵Background是20行10列的reg型数组,负责保存非活动方块坐标,生成20*10的背景矩阵,当背景矩阵某一位置为1时,屏幕显示为白色,否则为黑色。
- 活动方块坐标
output reg [4:0] n,
output reg [3:0] m,
n, m分别为当前活动方块的行、列指针,指向方块固定点位置。因为我们要通过W键对方块实现旋转。所以方块固定点为方块旋转时不变的格点,依据方块种类决定。不同的种类有着不同的旋转点。
- 方块模型
俄罗斯方块共有7中形状的方块,每种方块有至少一种,至多四种不同的旋转变形方式。为方便起见,将方块和旋转类型分别编号,可以得到一共十九种方块。方块类型如图 2‑3 方块展示列表所示。
图 2‑7 方块展示列表
- 方块运动
系统使用计数器产生随机数进入新状态,这里的随机数是一种伪随机,旧状态的值被新状态覆盖。同时,根据计数器,状态值的值刷新为未旋转的俄罗斯方块中的一种中的一种,作为下一次方块。
- 移动
方块的移动分为四种:分别是旋转,下落,左移,右移。由键盘来控制,方块的移动主要分为两部分:(1)判断;(2)转换
判断分两步:首先,判断变换后方块坐标是否合法,即变换后是否会造成方块越界。然后,判断变换后方块可能占据的新位置是否有背景矩阵方块存在。两步判断通过后返回成功信号,否则失败。
转换过程进行方块的移动或变形。根据KEYBOARD,移动时,改变方块坐标;变形时,方块按类别变换。
- 方块的消除
方块消除由两个状态来实现,分别是remove1和remove2.
在remove1状态中,将活动方块位置覆盖至R,变为非活动方块。
在remove2状态中,根据满行状态,进行行的消除与平移。
- 死亡判定
R中的0-3行位于屏幕上方,不进行显示,仅有新生成的方块坐标会进入这一区域。因而,当消除完成后,如R[3]不为空,游戏结束。
- VGA显示模块
VGA 的英文全称是Video Graphic Array,即显示绘图阵列。VGA 支持在
640X480 的较高分辨率下同时显示16种色彩或256 种灰度,同时在320X240 分辨率下可以同时显示256 种颜色。肉眼对颜色的敏感远大于分辨率,所以即使分辨率较低图像依然生动鲜明。计算机内部以数字方式生成的显示图像信息,被显卡中的数字/模拟转换器转变为R、 G、B三原色信号和行、场同步信号,信号通过电缆传输到显示设备中。
这里我们首先对系统自带时钟100MHz进行分频,由于显示屏的参数为640*480*60Hz,所以我们近似处理为25MHz。为了实现发送端与接受端图像各点一一正确对应,发送端与接收端的扫描必须同步。同步脉冲是周期稳定,边沿陡峭的脉冲。按我国电视标准,行同步脉冲的频率等于行频为15.625KHZ,行周期为64us。在电视技术中常以64us 作为时间单位,并以H 表示,即1H=64us。场同步脉冲频率等于场频为50HZ,场周期为 20ms,即312.5H。行同步脉冲宽度为4.7us 左右,场同步脉冲宽度为2.5~3H。
图 2‑8 VGA显示模块
- 玩家计分模块
我们利用数码管来显示玩家的得分情况。当判定到某一行信号全部为1可以消除的时候,玩家的分数可以提高并且在数码管上显示出来,数码管前五位显示SCORE,后面三位显示得分,所以得分上限为999分。由于内部原理的设置,每次玩家消除奇数行加23分,偶数行加22分。
图 2‑9 玩家计分模块
- 状态机模块设计
- 状态转移图
- 状态转移表
现态 |
触发条件 |
次态 |
空状态(S_idle) |
Start=1 |
新俄罗斯方块(S_new) |
新俄罗斯方块(S_new) |
无 |
保持状态(S_hold) |
time_cnt = time_val |
下降状态(S_down) |
|
保持状态(S_hold) |
(down_reg = 0) (down =1) |
下降状态(S_down) |
控制信号为1 |
移动状态(S_move) |
|
移动状态(S_move) |
move_comp=1 |
更新状态(S_shift) |
更新状态(S_shift) |
无 |
保持状态(S_hold) |
下降状态(S_down) |
down_comp=1 |
更新状态(S_shift) |
更新矩阵状态(S_remove_1) |
无 |
更新矩阵状态(S_remove_2) |
更新矩阵状态(S_remove_2) |
remove_2_finish=1 |
判断结束状态(S_isdie) |
判断结束状态(S_isdie) |
die = 1 |
清除状态(S_stop) |
清除状态(S_stop) |
无 |
空状态(S_idle) |
- 用户使用手册
- 具体功能实现
1)基本俄罗斯方块功能:方块下落、随机方块的产生、方块能否消除的判断。
2)键盘控制游戏的开始和方块的移动。上升键(W)控制方块的旋转。
3)数码管显示玩家当前的得分情况。
- 操作使用说明
用户主要通过键盘上面的按键来进行操控。
当想要开始进行游戏的时候,按下键盘上面的空格键,游戏开始。玩家通过A和D来控制方块的左移和右移,W键来控制方块的旋转。从而进行俄罗斯方块游戏的使用。
系统调试
- 调试过程说明
- 一般流程
系统的模块化设计流程一般分为设计思路确定、代码编写、RTL逻辑图分析、行为仿真、添加设计约束、设计综合、设计实现和比特流文件生成。
- 设计问题和解决方案
在俄罗斯方块设计过程中曾出现过两个问题:
首先,在键盘检测模块输出的信号不能有效进入状态机当中。具体的原因在于键盘发送的信号仅会在通断码变化时有效区别,因此检测模块的信号持续时间很短。具体分析如下:由于在键盘输入处理的模块当中,只会在键盘通码变化为断码时,在一个clk周期内输出一个按键信号到后面的模块当中,因此由于按键的有效信号很短,因此在后面的按键处理模块当中难以采用相同周期的clk信号采样识别到,因此需要适当延长有效信号输出的时间,帮助后续模块正常检测采样。
因此解决的方法分为两种,首先是引入状态机模块,将短暂的有效信号看作状态的触发信号,从而切换状态,通过不同的状态下重新输出有效信号,并在内部采用计数器,在计数时间结束之后切换回初始状态。其次是利用模块将有效信号延长至可识别的范围之内。从繁琐程度上考虑我们采用了第二种方法,在信号检测模块之后输出进一个信号延时模块当中,通过内部计数器工作,将有效信号延长至0.1s长度,即有效信号输入之后开始计数,此时对应的按键信号输出有效高电平,当达到阈值10000000之后停止计数,此时对应的按键信号输出低电平恢复,然后对应的信号传入后续模块当中,便有效地解决了有效信号持续时间很短的问题。
其次,在设计计分模块当中,由于对于每一次消除方块的操作,状态机的清零信号激活的类别不同,激活的次数也不同,因此难以输出有效的记数信号或分数。原因在于对于消除信号的检测产生了重复,并且在计分器模块当中,进位语句未使用标准的编写方式,产生了寄存现象,从而使得整个计分系统产生了错误。解决的方法是,对于消除信号,偶数行的消除是进行22次行消除,奇数行进行23次行消除,从而对于计数器而言,行数的奇偶不同时,采用的计分规则就不同,并且在进位方面使用标准的计数器语句格式,最终解决了计分结果有误的问题。
基于FPGA的俄罗斯方块设计相关推荐
- 基于FPGA的FFT设计
基于FPGA的FFT设计 1.verilog源代码还有实验报告 2.FFT的主要算法 FFT算法并不是一种新的理论算法,它只是用来计算DFT的快速算法,所以它是以DFT为基础的.本课题采用的是基-2 ...
- 基于 FPGA Vivado 信号发生器设计(附源工程)
今天给大侠带来基于 FPGA Vivado 信号发生器设计,开发板实现使用的是Digilent basys 3,如有想要入手 basys 3 开发板的,可以联系牛总:18511371833.话不多说, ...
- 频谱仪设计基于FPGA的频谱仪设计,可以测试分析多种频率的频谱,分辨率100HZ
频谱仪设计基于FPGA的频谱仪设计,可以测试分析多种频率的频谱,分辨率100HZ,配套资料多达100M,东西复杂 ID:982500594354361311卡哇伊2号小宝贝
- java 万年历绪论,基于FPGA的万年历设计
基于FPGA的万年历设计(论文15000字) 摘要:万年历在人们的生活中一直扮演着重要的角色,可随着时代的发展,传统的纸质万年历已经越来越无法满足人们对于时间精确度以及便捷性的要求.随着电子科学的不断 ...
- 基于 FPGA Vivado 示波器设计(附源工程)
今天给大侠带来基于 FPGA Vivado 示波器设计,开发板实现使用的是Digilent basys 3,如有想要入手 basys 3 开发板的,可以联系牛总:18511371833.话不多说,上货 ...
- FPGA项目(12)——基于FPGA的万年历设计
首先称述一下所实现的功能:可以显示年.月.日.时.分.秒,有闹钟设置功能,闹钟时间到时,蜂鸣器响,报警.用6位数码管进行显示,分三个显示页面,第一个页面显示年月日,第二个界面显示时分秒,第三个页面显示 ...
- 基于fpga的数码管动态扫描电路设计_【至简设计案例系列】基于FPGA的密码锁设计(altera版)...
秦红凯 明德扬FPGA科教 一.项目背景概述 随着生活质量的不断提高,加强家庭防盗安全变得非常重要,但传统机械锁的构造过于简单,很容易被打开,从而降低了安全性.数字密码锁因为它的保密性很高,安全系数也 ...
- 【示波器】基于FPGA的数字示波器设计实现
1.软件版本 quartusii 2.本算法理论知识 框图结构: 1.缓存里包含有触发控制和触发存储器: 2.由设计指标需要1GsPs的采样率,最后的数据流要降到到250MbPs: 3.从指标来看从波 ...
- 【至简设计案例系列】基于FPGA的密码锁设计(altera版)
本文为明德扬原创及录用文章,转载请注明出处! 作者:秦红锴 一.项目背景概述 随着生活质量的不断提高,加强家庭防盗安全变得非常重要,但传统机械锁的构造过于简单,很容易被打开,从而降低了安全性.数字密码 ...
最新文章
- 数据类型转换(Java)
- 配置告警系统主脚本main.sh mon.sh load.sh 502.sh disk.sh
- SQLServer中使用Split功能分割字符串
- 使用密钥验证方式登录linux系统
- UITextView中的占位符
- jQuery滚动指定位置
- 一天搞定CSS:盒模型content、padding、border、margin--06
- python 多进程 multiprocessing 进程池pool报错 in join assert self._state in (CLOSE, TERMINATE) AssertionError
- java 不可修改的集合对象_[改善Java代码]asList方法产生的List对象不可更改
- OpenCV文字绘制函数putText()的使用
- python数据分析知识整理_Python基础知识点总结:数据分析从0到大师必Mark的一篇!(上)...
- 数据科学入门的5个技巧
- 一次线上商城系统高并发优化,涨姿势了~
- [07.08]密西绿色精品软件每日更新[西空整理]
- 【Tips小技巧】电脑全屏截图网页滚动截图
- c语言作业汽车加速,C语言求车速
- R语言入门——rep函数
- python中title函数有什么用_Python 基础知识全篇-函数(Functions)
- @程序员:连小学生都开始学编程了,你们怕了吗?
- 有关lua,luci的介绍
热门文章
- 股指期权最新消息 股指期权怎么交易?
- 用过游戏加速器后DNS一直被指定无法自动获取如何解决!!!
- 一台小型发电机与计算机相连,2020春青岛市高考物理二轮45分钟练习:交变电流的产生及描述含答案...
- 逆袭之路——python 数据发展史、MySQL的下载和安装、基本SQL语句【day45】
- 安卓市场和安智市场_91和安卓市场渠道下线 百度曾花19亿美元收购
- 获取xml里的某个属性的值,并把值写入到文件中
- 计算机屏幕上的框的英语,电脑打开steam平台弹出一个英文框的解决方法
- 无车承运人平台线路定价问题
- 云从科技从容大模型:大模型和AI平台什么关系?为什么造行业大模型?
- 灰色个人简历自我介绍PPT模板