概述
小白第一次写博客,还稍微有点紧张激动呢啊哈哈。
由于学习Verilog没有太久而且作为选修课大作业,时间有限,程序可能写得有些简单幼稚,有些功能想到了却没有实现,还请各位大虾批评指正哈。
我对源程序进行了一些整理和修改,但苦于手头没有开发板,没有办法进行验证,所传文件可能会有些错误,希望大家能够给我指正。想要程序却苦于没有积分的或者想要原版程序的可以私信我,我看到第一时间会发给你。
本程序主要功能是实现简单的俄罗斯方块,方块堆积范围为18*10的矩阵,方块每0.25s下落一格,可以通过按键或者开关对方块进行左右移动操作,某一行方块堆满则对应行消失,上方方块下落补齐,方块堆到最高,则游戏结束,可以通过复位键控制游戏重新开始(由于只有一天时间,程序写得有些匆忙,某些想到的功能没有实现,我会在最后写一下思路,程序中的问题我也会说明)。
接下来步入正题...
首先是端口声明,CLK是开发板上的50MHZ时钟,RST作为游戏重新开始的复位信号,DOUT用于输出VGA的RGB信号,VGA_HSYNC, VGA_VSYNC为行列同步信号(控制帧数和分辨率),left和right用于控制方块左右移动。
module VGA( CLK, RST, DIN, DOUT, VGA_HSYNC, VGA_VSYNC, left, right);
变量声明中,除了对端口的声明,还有对18个长度为10的变量进行定义,即通过这些变量组成的矩阵来存储某一位置是否被占据(没错,方块只能在18*10这样的一个区域内移动)。另外,还有变量over用于记录游戏是否结束,变量n用于记录下落的图形(由于本程序比较简单,所以n的长度只有2,共有三种图形)。变量temp记录了方块左右移情况,也便于对矩阵对应位置的判断和改变。变量x,y记录了下落方块的坐标,data_valid用于限制显示的区域,clk_4是4HZ时钟,用来控制方块下落。 h_cnt,v_cnt是用于VGA扫描的变量。
input CLK;
input RST;
input left;
input right;
output [2:0] DOUT;
output VGA_HSYNC;
output VGA_VSYNC;
reg over;
reg [10:1]y1=10'b0000000000;
reg [10:1]y2=10'b0000000000;
reg [10:1]y3=10'b0000000000;
reg [10:1]y4=10'b0000000000;
reg [10:1]y5=10'b0000000000;
reg [10:1]y6=10'b0000000000;
reg [10:1]y7=10'b0000000000;
reg [10:1]y8=10'b0000000000;
reg [10:1]y9=10'b0000000000;
reg [10:1]y10=10'b0000000000;
reg [10:1]y11=10'b0000000000;
reg [10:1]y12=10'b0000000000;
reg [10:1]y13=10'b0000000000;
reg [10:1]y14=10'b0000000000;
reg [10:1]y15=10'b0000000000;
reg [10:1]y16=10'b0000000000;
reg [10:1]y17=10'b0000000000;
reg [10:1]y18=10'b0000000000;
reg [1:0]n;
reg [2:0] RGB;
reg [9:0] h_cnt;
reg [9:0] v_cnt;
reg VGA_CLK;
reg [8:1]temp=6;
wire clk_4;
reg [32:1]x=390;
reg [32:1]y=80;
wire data_valid;
分频部分比较简单,这里不再赘述。
always @ (posedge CLK or posedge RST)
begin
if(RST) VGA_CLK <= 1'b0;
else VGA_CLK <= ~VGA_CLK;
end
fd_4 fd_4(
.clk_50m(CLK),
.clk_4(clk_4)
);
VGA的初始化。这里通过三目运算符将范围外内容全都染成了黑色,并对像素和帧进行了规定。VGA一行一行的扫描,扫描完一行开始下一行的扫描,全都扫描完再从头开始(关于VGA显示部分网上例子和说明有很多,本人也只是理解到这个水平,,如果哪里有错误还请大虾指出。具体的可以参考这位老兄的文章,感觉写得很给力https://www.cnblogs.com/spartan/archive/2011/08/16/2140546.html)。顺便也把RST加在了这里,但个人感觉写在这不是太好。
always @(posedge VGA_CLK or posedge RST)
begin
if(RST)
begin
y1<=10'b0000000000;
y2<=10'b0000000000;
y3<=10'b0000000000;
y4<=10'b0000000000;
y5<=10'b0000000000;
y6<=10'b0000000000;
y7<=10'b0000000000;
y8<=10'b0000000000;
y9<=10'b0000000000;
y10<=10'b0000000000;
y11<=10'b0000000000;
y12<=10'b0000000000;
y13<=10'b0000000000;
y14<=10'b0000000000;
y15<=10'b0000000000;
y16<=10'b0000000000;
y17<=10'b0000000000;
y18<=10'b0000000000;
over<=0;
end
else if (h_cnt == 10'd799) h_cnt <= 10'd0;
else h_cnt <= h_cnt + 1'b1;
end
always @(posedge VGA_CLK or posedge RST)begin
if(RST) v_cnt <= 10'd0;
else if (v_cnt == 10'd520) v_cnt <= 10'd0;
else if(h_cnt == 10'd799) v_cnt <= v_cnt + 1'b1;
else v_cnt <= v_cnt;
end
接下来是比较关键的部分,关于实现方块的下落,图形,左右移动及堆积消去,且听我慢慢道来(这里提前说一下,方块被限制在一个矩形内,矩形横向为300~480,纵向为60~420,每个小方格为20*18大小)...
(1)、方块的下落
方块下落事件由4HZ时钟的上升沿触发。若最高层值为0,即y18==0,则说明游戏还在正常进行,结束变量over值为0,变量y自加20实现下落一个单位;否则,即y18!=0,说明游戏结束,over值为1;
if(y18==0)
begin
over<=0;
y<=y+20;
......
end
else
over<=1;
(2)、方块的左右移动
方块左右移动是通过两个按键(我们学校板子按键抖动太严重,我直接用开关替代的),同样是由4HZ时钟上升沿触发(其实这里可以使用8HZ时钟触发,对8HZ再分频得到4HZ用于下落事件)。右移,对应x+=18,temp+=1;左移,对应x-=18,temp-=1;但还要考虑方块不能移出方框范围之外,同时还得考虑方块形状(由于本程序形状比较少,左右移动时只需额外考虑形状2,及横排的两个方格)。
if(right)
begin
if(x>443&&n==2)
begin
end
else if(x<462)
begin
x<=x+18;
temp<=temp+1;
end
end
else if(left)
begin
if(x>300)
begin
x<=x-18;
temp<=temp-1;
end
end
(3)、方块的堆积
方块堆积主要通过判断当前图形下方格子对应的矩阵值是否为1,若为1说明下方有方块,则方块堆积,上方
方块对应矩阵位置值置1,方块重新从最上方开始下落;否则方块正常下落。当然,还需要考虑方块图形的问题,本程序只有三种图形,分别通
if加以讨论。
if((y<80)&&(y>=60)&&(y17[temp]==1))
begin
y18[temp]<=1;
y<=60;
n<=n+1;
end
(4)、方块的消去
方块消去通过对矩阵判断实现,代码应该比较容易看明白。
if(y1==10'b1111111111)
begin
y1<=y2;
y2<=y3;
y3<=y4;
y4<=y5;
y5<=y6;
y6<=y7;
y7<=y8;
y8<=y9;
y9<=y10;
y10<=y11;
y11<=y12;
y12<=y13;
y13<=y14;
y14<=y15;
y15<=y16;
y16<=y17;
y17<=y18;
y18<=10'b0000000000;
end
(5)、方块的图形
方块图形主要通过n的值来形成。n=0,对应单一方格;n=1,对应竖排两个方格;n=2,对应横排两个方格;
n=3,对应单一方格。不同形状下落主要是在VGA显示中对n进行判断和显示,形状堆积是通过对n进行判断决定
如何堆积。
else if((y<100)&&(y>=80)&&(y16[temp]==1))
begin
y17[temp]<=1;
if(n==1)
begin
y18[temp]<=1;
end
if(n==2)
begin
y17[temp+1]<=1;
end
y<=60;
n<=n+1;
end
else if((v_cnt>y && v_cnt<y+20 && h_cnt>x && h_cnt<x+18) )RGB <= 3'd000;
else if((v_cnt>y-20 && v_cnt<y && h_cnt>x && h_cnt<x+18)&&(n==1) )RGB <= 3'd000;
else if((v_cnt>y && v_cnt<y+20 && h_cnt>(x+18) && h_cnt<x+36)&&(n==2))RGB <= 3'd000;
关于VGA的显示,其实就是算格子,算范围,改RGB。我先绘制出一个方框,后又通过矩阵和方框内方块的对应
关系,将矩阵内的值以方块的形式显示到框内。方块下落是通过对x,y的显示实现的(上面代码),形状是通过对n的判断后显示实
现的(应老师的要求,在右下方显示了自己的学号。右上方显示了结束后的OVER字样。由于自己没有掌握用字库,
OVER是自己用点描的,奇丑无比...请忽略这一点)。
else if(v_cnt>400&&v_cnt<420&&y1[1]&&h_cnt>300 && h_cnt<318) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[2]&&h_cnt>318 && h_cnt<336) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[3]&&h_cnt>336 && h_cnt<354) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[4]&&h_cnt>354 && h_cnt<372) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[5]&&h_cnt>372 && h_cnt<390) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[6]&&h_cnt>390 && h_cnt<408) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[7]&&h_cnt>408 && h_cnt<426) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[8]&&h_cnt>426 && h_cnt<444) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[9]&&h_cnt>444 && h_cnt<462) RGB <= 3'd000;
else if(v_cnt>400&&v_cnt<420&&y1[10]&&h_cnt>462 && h_cnt<480) RGB <= 3'd000;
重复比较多的代码只粘贴了部分,代码我传到了资源上(还未审核通过),可以自行下载。
接下来说一下自己没有实现的思路和自己的一些看法:
(1)、如果要实现更多图形可以将n的长度增大,不同的n对应不同的图形;变形也可以通过对n操作实现变形。
(2)、程序中没有对横排方块右边方块进行判断,导致下落过程中该方块下方有方块但仍会下落,加入判断即可解决。
(3)、程序中可以加入加速下落键。
(4)、方块只加入了对下方方块的判断,导致如果下方无方块,两侧有方块,方块会移动到里面的错误。需要对下落的方块加入对两边的判断。
(5)、如果要求变形或左右移速度快于下落速度,可以用更高频率时钟用于变形和左右移,再分频得到下落时钟。
(6)、右上方的OVER实在太丑了,求大神教一教如何用字符集和VGA搭配使用。
最后,小白的第一篇博文,写得没有什么技术含量,还请大家多多质疑及批评指正(这编辑器可真把我折磨得够够的,为什么注释复制上去就会出现一串html代码...)。
代码免费自取:https://download.csdn.net/download/ad7533/10210552
最后
以上就是仁爱大神为你收集整理的使用Verilog语言编写简单的俄罗斯方块的全部内容,希望文章能够帮你解决使用Verilog语言编写简单的俄罗斯方块所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复