使用Verilog语言编写简单的俄罗斯方块

小白第一次写博客,还稍微有点紧张激动呢啊哈哈。

由于学习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

 

 

 

 

 

 

 

  • 20
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 67
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 67
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值