FPGA-VGA显示的贪吃蛇游戏开发记录——(1)蛇头模块

FPGA-VGA显示的贪吃蛇游戏开发记录

      • 蛇头模块
      • 代码
      • Testbench

考试复习期间看到别人用Python写了个贪吃蛇,突然想用FPGA实现一个贪吃蛇游戏机,用VGA接口显示在电脑屏幕上。
无论最后能不能成功做成,都先试试看。记录每一个模块的开发思路和代码。

蛇头模块

需求:
1、生成蛇头的初始坐标
2、蛇头坐标根据蛇运动方向做改变

思路:
1、使用VGA-640
480分辨率显示,以2020个像素为一格,所以xpos为1-32(640/20=32),ypos为1-24(480/24=20)。
2、定义4个方向:LEFT,RIGHT,UP,DOWN。
方向为LEFT时,xpos每个时钟周期减1,ypos不变
方向为RIGHT时,xpos每个时钟周期加1,ypos不变
方向为UP时,ypos每个时钟周期减1,xpos不变
方向为DOWN时,ypos每个时钟周期加1,xpos不变
3、键盘值输入,定义4个方向按键:KEY_UP,KEY_DOWN,KEY_LEFT,KEY_RIGHT
蛇头方向根据按键方向改变,除了运动方向与按键操作方向正好相反的情况

4、分频出一个时钟,作为蛇头位置改变的时钟。这儿用了0.5s的时钟,也就是说蛇运动速度是固定的,实现基本功能后可以加入变速的功能。

代码

`define SIM
module snake_dri (
	input					clk						,
	input					rst_n					,
	//====================snake_dri_interface===================
	input			[3:0]	key_val					,
	input					key_trig				,
	output			[5:0]	x_pos					,
	output			[5:0]	y_pos					,
	output			[1:0]	direction				,
	input					flag_go						
);
    //==============Time_Parameter define====================
    `ifndef SIM
    localparam				CNT_DIV_05S = 12500000	;
    `else
    localparam				CNT_DIV_05S = 5			;
   	`endif
    //==============directiton Parameter define====================
    localparam				DIR_LEFT    = 2'd0		;
    localparam				DIR_RIGHT   = 2'd1		;
    localparam				DIR_UP		= 2'd2		;
    localparam				DIR_DOWN	= 2'd3		;
    //==============key_val Parameter define====================
    localparam				KEY_UP		= 2'd0		;
    localparam				KEY_DOWN	= 2'd1		;
    localparam				KEY_LEFT	= 2'd2		;
    localparam				KEY_RIGHT	= 2'd3		;
    //=================System Reg define===================
    reg 			[23:0]		cnt_div_clk			;
    reg 						div_clk				;
    reg 			[5:0]		x_pos_reg			;
    reg 			[5:0]		y_pos_reg			;
    reg 			[1:0]		directiton_reg		;
    reg 			[3:0]		key_val_reg			;
    //key_trig_reg
    reg 						key_trig_t0			;
    reg 						key_trig_t1			;
    reg 						key_trig_t2			;
    //====================System Wire define=====================
    wire						key_trig_pedge0		;
    wire						key_trig_pedge1		;
    //====================inteface Wire =====================
    assign x_pos = x_pos_reg						;
    assign y_pos = y_pos_reg						;
    assign direction = directiton_reg				;
    //=============================================================================
    //****************************     Main Code    *******************************
    //=============================================================================
    //cnt_div_clk logic
    always @ (posedge clk or negedge rst_n) begin
    	if(rst_n == 1'b0)
    		cnt_div_clk <= 24'd0;
    	else if(cnt_div_clk==CNT_DIV_05S)
    		cnt_div_clk <= 24'd0;
    	else
    		cnt_div_clk <= cnt_div_clk + 1'b1;
    end
    //div_clk logic
    always @ (posedge clk or negedge rst_n) begin
    	if(rst_n == 1'b0)
    		div_clk <= 1'b0;
    	else if(cnt_div_clk==CNT_DIV_05S)
    		div_clk <= ~div_clk;
    end
    //x_pos_reg logic
    always @ (posedge div_clk or negedge rst_n) begin
    	if(rst_n == 1'b0)
    		x_pos_reg <= 6'd4;
    	else if(flag_go==1'b1)
    		case (directiton_reg) 
    			DIR_DOWN:begin
    				x_pos_reg <= x_pos_reg;
    			end
    			DIR_UP:begin
    				x_pos_reg <= x_pos_reg;
    			end
    			DIR_LEFT:begin
    				if(x_pos_reg==6'd1)
    					x_pos_reg <= 6'd1;
    				else
    					x_pos_reg <= x_pos_reg - 1'b1;
    			end
    			DIR_RIGHT:begin
    				if(x_pos_reg==6'd32)
    					x_pos_reg <= 6'd32;
    				else  					
    					x_pos_reg <= x_pos_reg + 1'b1;
    			end
    		    default:x_pos_reg <= x_pos_reg;
    		endcase
    	else
    		x_pos_reg <= 6'd4;
    end
    //y_pos_reg logic
    always @ (posedge div_clk or negedge rst_n) begin
    	if(rst_n == 1'b0)
    		y_pos_reg <= 6'd4;
    	else if(flag_go==1'b1)
    		case (directiton_reg) 
    			DIR_DOWN:begin
    				if(y_pos_reg==6'd24)
    					y_pos_reg <= 6'd24;
    				else
    					y_pos_reg <= y_pos_reg + 1'b1;
    			end
    			DIR_UP:begin
    				if(y_pos_reg==6'd1)
    					y_pos_reg <= 6'd1;
    				else
    					y_pos_reg <= y_pos_reg - 1'b1;
    			end
    			DIR_LEFT:begin
    				y_pos_reg <= y_pos_reg;
    			end
    			DIR_RIGHT:begin
    				y_pos_reg <= y_pos_reg;
    			end
    		    default:y_pos_reg <= y_pos_reg;
    		endcase
    	else
    		y_pos_reg <= 6'd4;
    end 
    //key_trig_temp_logic
    always @ (posedge clk) begin
    	key_trig_t0 <= key_trig;
    	key_trig_t1 <= key_trig_t0;
    	key_trig_t2 <= key_trig_t1;
    end
    //key_trig_pedge logic
    assign key_trig_pedge0 = key_trig_t0&~key_trig_t1;
    assign key_trig_pedge1 = key_trig_t1&~key_trig_t2;

    //direction reg logic
    always @ (posedge clk or negedge rst_n) begin
    	if(rst_n == 1'b0)
    		directiton_reg <= DIR_RIGHT;
		else if(key_trig_pedge1==1'b1)
			case (key_val_reg) 
				KEY_RIGHT:begin
					case (directiton_reg) 
						DIR_LEFT:directiton_reg <= DIR_LEFT;
					    default:directiton_reg <= DIR_RIGHT;
					endcase
				end
				KEY_LEFT:begin
					case (directiton_reg) 
						DIR_RIGHT:directiton_reg <= DIR_RIGHT;
					    default:directiton_reg <= DIR_LEFT;
					endcase
				end
				KEY_UP:begin
					case (directiton_reg) 
						DIR_DOWN:directiton_reg <= DIR_DOWN;
					    default:directiton_reg <= DIR_UP;
					endcase
				end
				KEY_DOWN:begin
					case (directiton_reg) 
						DIR_UP:directiton_reg <= DIR_UP;
					    default:directiton_reg <= DIR_DOWN;
					endcase
				end
			    default:directiton_reg <= directiton_reg;
			endcase
		else
			directiton_reg <= directiton_reg;
    end
    //key_val_reg logic
    always @ (posedge clk or negedge rst_n) begin
    	if(rst_n == 1'b0)
    		key_val_reg <= KEY_RIGHT;
    	else if(key_trig_pedge0==1'b1)
    		key_val_reg <= key_val;
    end    
endmodule

Testbench

`define	clock_period	20
`timescale	1ns/1ns
module	tb_food_gene_dri;
//=================System Signals===================
	reg 			clk;
	reg				rst_n;
//=================module_signals===================
	reg						flag_go				;
	wire			[5:0]	food_xpos			;
	wire			[5:0]	food_ypos			;
	reg						flag_food_get		;
	//==============internal signal===================
	integer 				i = 0				;
food_gene_dri food_gene_dri(
	.clk					(clk)				,
	.rst_n					(rst_n)				,
	//====================food_gene_dri_interface===================
	.flag_go				(flag_go)			,
	.food_xpos				(food_xpos)			,
	.food_ypos				(food_ypos)			,
	.flag_food_get			(flag_food_get)		
);
//=================System clock logic===============
initial begin
	clk = 1;
end
always	#(`clock_period/2)clk = ~clk;
//=================System Rst_n logic===============
initial begin
	rst_n = 0;
	#(`clock_period*20);
	rst_n = 1;
end
//=================Test Signal logic================
initial begin
	flag_go = 0;
	flag_food_get = 0;
	#(`clock_period*20);
	flag_go = 1;
	#(`clock_period*500);
	for (i = 0;i <= 20; i = i + 1)begin
		flag_food_get = 1;
		#(`clock_period)flag_food_get = 0;
		#(`clock_period*500);        
    end
end

endmodule

FPGA-VGA显示的贪吃蛇游戏开发记录——(1)蛇头模块_第1张图片

你可能感兴趣的:(FPGA基础)