VerilogHDL高级数字设计实验报告俄罗斯方块FPGA实现.docx
- 文档编号:24080356
- 上传时间:2023-05-24
- 格式:DOCX
- 页数:81
- 大小:1.33MB
VerilogHDL高级数字设计实验报告俄罗斯方块FPGA实现.docx
《VerilogHDL高级数字设计实验报告俄罗斯方块FPGA实现.docx》由会员分享,可在线阅读,更多相关《VerilogHDL高级数字设计实验报告俄罗斯方块FPGA实现.docx(81页珍藏版)》请在冰豆网上搜索。
VerilogHDL高级数字设计实验报告俄罗斯方块FPGA实现
VerilogHDL高级数字设计
实验报告
题目:
“俄罗斯方块”FPGA实现
实验目的
通过此次项目,完成以下目的:
1)熟悉XilinxFPGA的架构及开发流程
2)设计一个功能完整的系统,掌握FSM+Datapath的设计方法。
实验内容
1.项目介绍
本项目主要在FPGA上实现了一个经典小游戏“俄罗斯方块”。
本项目基本解决方案是,使用XilinxZynq系列开发板ZedBoard作为平台,实现主控模块,通过VGA接口来控制屏幕进行显示。
2.系统框架
整个系统由四部分组成,按键输入处理模块、控制模块、数据路径模块以及VGA显示接口模块。
整个系统的结构如下图所示:
图1:
系统框图
下面分别对四个模块进行介绍:
1)按键输入处理模块
按键处理模块的主要功能是对输入系统的up,down,left,right四个控制信号进行消抖处理,并对其进行上升沿检测。
消抖模块采用上课所提出的结构,采用了一个4位的移位寄存器,先将输入信号延迟4个时钟周期,再对其以一个较低的时钟频率进行采用。
消抖模块的结构如下图所示:
图2:
消抖模块结构示意图
为了简化控制系统,在本系统的设计过程中,不考虑长时间按键产生连按效果。
因而,需要对按键进行上升沿检测。
上升沿检测的基本实现方案是加入一组寄存器,对前一个的按键信号进行暂存,将暂存的值与当前值进行比较,当上一个值为0而当前值为1时,即认为其检测到了一个上升沿。
2)控制模块
控制模块采用FSM的方式进行控制。
在控制模块中,定义了10个状态:
S_idle:
上电复位后进入的空状态,当start信号为1时进入S_new状态
S_new:
用于产生新的俄罗斯方块。
S_hold:
保持状态。
在这个状态中进行计时,当时间到达一定间隔时,转到S_down状态;或者等待输入信号(up,down,left,right)时,转到S_down(按键为down)或者S_move(up,left,right)状态。
S_down:
判断当前俄罗斯块能否下移一格。
如果可以,则转到S_remove_1状态,如果不行,则转到S_shift状态。
S_move:
判断当前俄罗斯块能够按照按键信号指定的指令进行移动,如果可以,则转到S_shift状态,如果不可以,则转到S_remove_1状态。
S_shift:
更新俄罗斯方块的坐标信息。
返回S_hold。
S_remove_1:
更新整个屏幕的矩阵信息。
转移到S_remove_2状态。
S_remove_2:
判断是否可以消除,将可以消除的行消除,并将上面的行下移一行。
重复此过程,直到没有可消除的行为止。
跳转到S_isdie状态
S_isdie:
判断是否游戏结束。
如果结束,则跳转到S_stop状态。
如果没有,则跳转到S_new状态,生成新的俄罗斯方块。
S_stop:
清楚整个屏幕,并跳转到S_idle状态。
整个控制过程的ASMD图如下图所示:
图3:
控制模块ASMD图
3)数据路径
数据路径模块主要功能是,根据控制模块给出的信号,对俄罗斯方块当前的逻辑状态进行判断,更新背景矩阵。
具体如下:
方块:
方块分为非活动方块与活动方块。
非活动方块为:
(1)之前下落的方块;
(2)下落后方块消除之后的结果。
由背景矩阵表示。
活动方块为当前下落中的方块,由活动方块坐标与方块类型表示(后简称方块)。
背景矩阵:
reg[9:
0]R[23:
0];
背景矩阵R是24行10列的寄存器组,负责保存非活动方块坐标,即R中任一位置,如方块存在,则该位置1,否则为0。
活动方块坐标:
outputreg[4:
0]n,
outputreg[3:
0]m,
n,m分别为当前活动方块的行、列指针,指向方块固定点位置。
方块固定点为方块旋转时不变的格点,依据方块种类决定,下文方块模型中详述。
方块类型:
outputreg[6:
0]BLOCK,
BLOCK代表方块类型,由7位编码构成。
数据交换:
Datapath与其余模块的数据交换分为两部分:
(1)与control_unit间的状态指令交互;
(2)控制merge,间接实现对VGA的控制。
方块模型:
俄罗斯方块共有7中形状的方块(O,L,J,I,T,Z,S),每种方块有1-4种不同的旋转变形方式。
为方便起见,将方块定位A-G,旋转编号为1-4,将方块编码成A_1-G_2的19种,如下图:
图中,深色方块是该种方块的固定点。
图4:
方块模型示意图
方块运动:
产生:
方块产生由一个简单的伪随机过程决定。
系统采用一个3位的计数器产生随机数,进入S_new,BLOCK的值被NEW_BLOCK覆盖,方块坐标n<=1;m<=5;同时,根据计数器,NEW_BLOCK的值刷新为A_1,B_1,…,G_1中的一种,作为下一次方块。
移动:
方块移动分为四种:
旋转,下落,向左,向右,由键盘KEYBOARD=[UP,DOWN,LEFT,RIGHT]控制。
移动分两步进行:
(1)判断;
(2)转换。
判断过程包含S_down,S_move。
判断分两步:
首先,判断变换后方块坐标是否合法,即变换后是否会造成方块越界。
然后,判断变换后方块可能占据的新位置是否有背景矩阵方块存在。
两步判断通过后返回成功信号,否则失败。
因判断代码量较多,仅举一例说明:
判断D_1向右运动(MOVE_ABLE初值为0):
if(m<=8)
if(!
((R[n-1][m+1])|(R[n][m+1])|(R[n+1][m+1])|(R[n+2][m+1])))
MOVE_ABLE=1;
elseMOVE_ABLE=0;
转换过程(S_shift)进行方块的移动或变形。
根据KEYBOARD,移动时,改变方块坐标;变形时,方块按类别变换,如:
A_1→A_1;B_1→B_2;B_2→B_3;B_4→B_1;
停止与消除:
方块停止与消除由两个状态完成:
S_remove1,S_remove2。
前一状态中,根据BLOCK,n,m,将活动方块位置覆盖至R,变为非活动方块。
后一状态中,根据行满状态,进行行的消除与平移,具体如下:
显然,俄罗斯方块能影响的最大行数为4,因此,在REMOVE_2中,仅对R[n-1],R[n],R[n+1],R[n+2]四行依次进行处理。
处理过程为:
如果该行(k)满,则由k行开始,至1行结束,逐行向下平移,当前平移位置由计数器REMOVE_2_C控制,当前行消除截止由标志位SIG确认。
每行处理完后,将REMOVE_FINISH[3:
0]中相应位置1,REMOVE_FINISH全1时,REMOVE_2完成。
死亡判定:
R中的0-3行位于屏幕上方,不进行显示,仅有新生成的方块坐标会进入这一区域。
因而,当消除完成后,如R[3]不为空,游戏结束。
4)显示部分
输出结果通过VGA接口接入显示屏显示。
VGA(VideoGraphicsArray)视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。
VGA接口即电脑采用VGA标准输出数据的专用接口。
VGA接口共有15针,分成3排,每排5个孔,显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。
它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号)。
使用VerilogHDL语言对VGA进行控制一般只需控制行扫描信号、列扫描信号和红绿蓝三色信号输出即可。
VGA输出可分为四个模块:
时钟分频模块、数据组织模块、接口控制模块和顶层模块。
以下进行分块描述。
时钟模块分频模块对FPGA系统时钟进行分频。
由于使用的显示屏参数为640*480*60Hz,其真实屏幕大小为800*525,因此所需时钟频率为800*525*60Hz=25.175MHz,可近似处理为25MHz。
FPGA系统时钟为100M,因此将其四分频即可基本满足显示要求。
数据组织模块是将预备输出的数据组织为可以通过VGA接口控制的数据形式,本次设计中因接口已经协调,数据可不经过此模块进行组织,故可忽略该模块。
接口控制模块通过VGA接口对显示屏进行控制。
VGA的扫描顺序是从左到右,从上到下。
例如在640X480的显示模式下,从显示器的左上角开始往右扫描,直到640个像素扫完,再回到最左边,开始第二行的扫描,如此往复,到第480行扫完时即完成一帧图像的显示。
这时又回到左上角,开始下一帧图像的扫描。
如果每秒能完成60帧,则称屏幕刷新频率为60Hz。
宏观上,一帧屏幕由480个行和640个列填充而成,而实际上,一帧屏幕除了显示区,还包含其他未显示部分,作为边框或者用来同步。
具体而言,一个完整的行同步信号包含了左边框、显示区、右边框还有返回区四个部分,总共800个像素,其分配如下:
图5:
VGA行扫描时序
同样的,一个完整的垂直同步信号也分为四个区域,总共525个像素,分配如下:
图6:
VGA场扫描时序
模块通过组织输出行扫描信号、列扫描信号和三原色信号对显示屏实现控制。
实验结果
实验结果图如下:
图7:
实验结果图
实验总结
1)完成情况
本次项目我们完成了既定目标,即完成一个经典小游戏“俄罗斯方块”的核心功能。
在本次实验过程中,我们通过采用分工合作的方式,通过对系统功能的分析,确定解决方案,完成了对一个系统自上而下的设计,并尝试采用控制单元+数据路径这样的方式来处理核心模块。
2)不足与改进之处
由于时间仓促,加之对俄罗斯方块逻辑复杂度估计不足,到最后展示之前我们才完成了对核心模块的调试。
因此,在用户界面上没有做过多的调整。
另外,由于在进行模块划分时,一些接口没有事先定义好,导致在最后系统整合时,不得不进行修改与调整,由此而造成了一部分时间的浪费。
总的来说,通过这个项目,小组成员对于硬件设计“并行”的特点有了比较直接的认识,同时也在调试的过程中掌握了一些硬件调试常用的方法,也认识到了仿真的重要意义所在。
另外就是关于团队协作方面的一个教训,在系统划分时要注意把接口定义好,以免造成不必要的代价。
实验代码
KeyBoard模块
`timescale1ns/1ps
modulekey(
inputclk,
inputrst_n,
inputUP_KEY,
inputLEFT_KEY,
inputRIGHT_KEY,
inputDOWN_KEY,
outputregrotate,
outputregleft,
outputregright,
outputregdown
);
reg[3:
0]shift_up;
reg[3:
0]shift_left;
reg[3:
0]shift_right;
reg[3:
0]shift_down;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
shift_up<=0;
else
shift_up<={shift_up[2:
0],UP_KEY};
end
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
shift_right<=0;
else
shift_right<={shift_right[2:
0],RIGHT_KEY};
end
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
shift_left<=0;
else
shift_left<={shift_left[2:
0],LEFT_KEY};
end
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
shift_down<=0;
else
shift_down<={shift_down[2:
0],DOWN_KEY};
end
regclk_div;
reg[7:
0]clk_cnt;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
clk_cnt<=0;
clk_div<=0;
end
elseif(clk_cnt<=8'd49)
begin
clk_cnt<=clk_cnt+1;
clk_div<=clk_div;
end
else
begin
clk_cnt<=0;
clk_div<=~clk_div;
end
end
always@(posedgeclk_divornegedgerst_n)
begin
if(!
rst_n)
begin
rotate<=0;
left<=0;
right<=0;
down<=0;
end
else
begin
rotate<=shift_up[3];
left<=shift_left[3];
right<=shift_right[3];
down<=shift_down[3];
end
end
endmodule
控制模块程序
modulegame_control_unit(
inputclk,
inputrst_n,
inputrotate,
inputleft,
inputright,
inputdown,
inputstart,
outputreg[3:
0]opcode,
outputreggen_random,
outputreghold,
outputregshift,
outputregmove_down,
outputregremove_1,
outputregremove_2,
outputregstop,
outputregmove,
outputregisdie,
outputregauto_down,
inputshift_finish,
inputremove_2_finish,
inputdown_comp,
inputmove_comp,
inputdie
);
regleft_reg;
regright_reg;
regup_reg;
regdown_reg;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
begin
left_reg<=0;
right_reg<=0;
up_reg<=0;
down_reg<=0;
end
else
begin
left_reg<=left;
right_reg<=right;
up_reg<=rotate;
down_reg<=down;
end
end
regauto_down_reg;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
auto_down_reg<=0;
elseif(time_cnt==time_val)
auto_down_reg<=1;
else
auto_down_reg<=0;
end
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
auto_down<=0;
else
auto_down<=auto_down_reg;
end
parametertime_val=26'd2*******;
reg[25:
0]time_cnt;
localparamS_idle=4'd0,
S_new=4'd1,
S_hold=4'd2,
S_move=4'd3,
S_shift=4'd4,
S_down=4'd5,
S_remove_1=4'd6,
S_remove_2=4'd7,
S_isdie=4'd8,
S_stop=4'd9;
reg[3:
0]state,next_state;
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
state<=S_idle;
else
state<=next_state;
end
always@(posedgeclkornegedgerst_n)
begin
if(!
rst_n)
time_cnt<=0;
elseif(hold==0&&time_cnt time_cnt<=time_cnt+1; elseif(move_down==1) time_cnt<=0; elsebegin time_cnt<=time_cnt; end end always@(posedgeclkornegedgerst_n) begin if(! rst_n)opcode<=0; elseopcode<={right,left,down,rotate}; end always@(*) begin next_state=S_idle; hold=1; gen_random=0; //opcode=4'b0000; shift=0; move_down=0; remove_1=0; remove_2=0; stop=0; move=0; isdie=0; case(state) S_idle: begin if(start) next_state=S_new; else next_state=S_idle; end S_new: begin gen_random=1; next_state=S_hold; end S_hold: begin hold=0; if(time_cnt==time_val) begin next_state=S_down; end elseif((down_reg==0)&&(down==1)) begin next_state=S_down; end elseif((left_reg==0&&left==1)||(right_reg==0&&right==1)||(up_reg==0&&rotate==1)) begin next_state=S_move; end else next_state=S_hold; end S_move: begin move=1; if(move_comp) next_state=S_shift; else next_state=S_hold; end S_shift: begin shift=1; next_state=S_hold; end S_down: begin move_down=1; if(down_comp) next_state=S_shift; else next_state=S_remove_1; end S_remove_1: begin remove_1=1; next_state=S_remove_2; end S_remove_2: begin remove_2=1; if(remove_2_finish) next_state=S_isdie; else next_state=S_remove_2; end S_isdie: begin isdie=1; if(die==1) next_state=S_stop; else next_state=S_new; end S_stop: begin stop=1; next_state=S_idle; end defaultnext_state=S_idle; endcase end endmodule 数据路径 moduleDatapath_Unit#( parameterA_1=7'b0001000, B_1=7'b0011000, B_2=7'b0010100, B_3=7'b0010010, B_4=7'b0010001, C_1=7'b0101000, C_2=7'b0100100, C_3=7'b0100010, C_4=7'b0100001, D_1=7'b0111000, D_2=7'b0110100, E_1=7'b1001000, E_2=7'b1000100, E_3=7'b1000010, E_4=7'b1000001, F_1=7'b1011000, F_2=7'b1010100, G_1=7'b1101000, G_2=7'b1100100 )( outputregMOVE_ABLE,SHIFT_FINISH,DOWN_ABLE,DIE_TRUE, output[239: 0]M_OUT, outputreg[4: 0]n, outputreg[3: 0]m, outputreg[6: 0]BLOCK, //outputregREMOVE_1_FINISH, outputregREMOVE_2_FINISH, //outputregNEW_BLOCK, inputclk,rst_n,MOVE,DOWN,DIE,SHIFT,REMOVE_1,REMOVE_2,NEW,STOP,AUTODOWN, input[3: 0]KEYBOARD ); reg[2: 0]RAN; reg[9: 0]R[23: 0]; reg[6: 0]NEW_BLOCK; reg[6: 0]BLOCK_P; reg[4: 0]remove_cnt; reg[3: 0]REMOVE_2_S; reg[3: 0]
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VerilogHDL 高级 数字 设计 实验 报告 俄罗斯方块 FPGA 实现