【nexys3】【verilog】小设计——拆弹游戏

设计说明书——拆弹游戏   

一.       设计背景

拆弹游戏,现有一个定时炸弹,设有一个计时器,如果不能在限定时间内找出唯一的密码,会发生爆炸,若在规定时间内完成,则相当于炸弹被拆除。

二.使用说明

接通电路,计时器自动开始计时,显示在数码管上。利用八个开关输入二进制数(从左到右依次为高位到低位),led灯v16亮起则表示输入密码偏小,led灯u16亮起则显示输入密码偏大。若输入正确,则炸弹拆除,显示“炫酷“的流水灯。若未能在限定时间内完成,则在数码管上会有相应提示表示”炸弹“已经爆炸。

三.设计说明

1 . 主要部分:分秒计时状态机,数码管显示模块,密码比较器,流水灯控制模块

2 . 分秒计时器:

clk频率50Mhz,及每个时钟周期20ns,考虑1000_000ns即1ms为一个延迟。

设置一个状态机,转换机制如下:计数延迟个数,每经历1000个延迟,状态转换一次每次转换,秒的个位sec_l增加1,当sec_l=9时,其变为0,十位sec_h加一。当sel_l=9且sec_h=5时,分的各位min_l增加一。同理易得min_h的变化规律。当计时器统计了60分钟后,所有位归零从新计时。

3 . 密码比较器:不涉及时序,仅由逻辑电路构成。将输入数据(一个8位无符号数)与内置密码比较,若后者较大,则输出相应信号,表示输入密码变大,反之则输出相应信号,表明输入偏小。如果恰好为密码,则炸弹被拆除,则将rst_n置为0,控制数码管清零,以及显示流水灯表示庆祝。

4 . 数码管显示模块:利用四位从左到右分别显示计时的分十位,分个位,秒十位,秒个位。利用视觉留影原理,动态扫描四个数码管,时间每个显示时间为一个延迟,即1ms,小于人眼暂留时间20ms,经测试显示稳定。

5 . 流水灯,使用了T11,M11,R11,N11四个led作为输出,具体输出样式参见代码。

四.代码

module top(
input clk,
input [7:0] datain,
output big,
output smal,
output [7:0] seg,
output [3:0] sel,
output [3:0] led_out
    );

wire rst_n;


cmp c(datain,big,smal,rst_n);
timera t(rst_n,clk,seg,sel);
Led_Top l(clk,~rst_n,led_out);

endmodule
module cmp(

input [7:0]datain,

output big,

output smal,

output rst_n

    );

 

integer key=8'b10101010;

assign smal=(datain<key);

assign big=(datain>key);

assign rst_n=~(datain==key);

endmodule

`define T1MS 16'd49_999    		
`define FLASH_FREQUENCY 14'd500 

module Led_Top
(
	input clk,rst_n,
	output[3:0] ledOut
);
	
	wire[3:0] isStart;
	wire[55:0] SetMSTimes;
	wire[3:0] isDone;
  
	Led_Control Led_Control 
	(
		.clk(clk),
		.rst_n(rst_n),
		.isDone(isDone),
		.isStart(isStart),
		.SetMSTimes(SetMSTimes)
	);
	Led_Driver Led_Driver[3:0]
	(
		.clk(clk),
		.rst_n(rst_n),
		.StartSig(isStart),
		.setMSTimes(SetMSTimes),
		.DoneSig(isDone),
		.ledOut(ledOut)
	);
endmodule

module Led_Control
(
	input clk,rst_n,
	input[3:0] isDone,
	output[3:0] isStart,
	output[55:0] SetMSTimes
);

	reg[3:0] i,j,k;
	reg[3:0] regStart;
	reg[13:0] regSetMSTimes[3:0];

	always@(posedge clk,negedge rst_n)
		if(!rst_n)   //³õʼ»¯
			begin 
				i<=4'd0;
				j<=4'd0;
				k<=4'd0;
				regStart<=4'b0000;
				regSetMSTimes[0]<=14'd0;
				regSetMSTimes[1]<=14'd0;
				regSetMSTimes[2]<=14'd0;
				regSetMSTimes[3]<=14'd0;
			end
		else
			case(i)
				0:SerialLight(`FLASH_FREQUENCY,`FLASH_FREQUENCY,`FLASH_FREQUENCY,`FLASH_FREQUENCY);
				1:PipeLineLight(`FLASH_FREQUENCY,`FLASH_FREQUENCY,`FLASH_FREQUENCY,`FLASH_FREQUENCY);
				2:ParallelPipeLineLight(`FLASH_FREQUENCY,`FLASH_FREQUENCY,`FLASH_FREQUENCY,`FLASH_FREQUENCY);
				3:i<=4'd0;    //¿ØÖÆÑ­»·
			endcase
	assign isStart=regStart;
	assign SetMSTimes={regSetMSTimes[3],regSetMSTimes[2],regSetMSTimes[1],regSetMSTimes[0]};
	task SerialLight
	(
		input[13:0] serialSetMSTimes0,serialSetMSTimes1,
						serialSetMSTimes2,serialSetMSTimes3
	);
		case(j)
				0:
					begin
						regSetMSTimes[0]<=serialSetMSTimes0;
						regSetMSTimes[1]<=serialSetMSTimes1;
						regSetMSTimes[2]<=serialSetMSTimes2;
						regSetMSTimes[3]<=serialSetMSTimes3;
						regStart[0]<=1'b1;
						j<=j+1'b1;
					end
				1:
					if(isDone[0])
						begin
							regStart[0]<=1'b0;
							regStart[1]<=regStart[0];
							j<=j+1'b1;
						end
				2:
					if(isDone[1])
						begin
							regStart[1]<=1'b0;
							regStart[2]<=regStart[1];
							j<=j+1'b1;
						end
				3:
					if(isDone[2])
						begin
							regStart[2]<=1'b0;
							regStart[3]<=regStart[2];
							j<=j+1'b1;
						end
				4:
					if(isDone[3])
						begin
							regStart[3]<=1'b0;
							k<=k+1'b1;
							if(k==4'd3)
								begin
									k<=4'd0;
									j<=j+1'b1;
								end
							else
								begin
									regStart[0]<=regStart[3];
									j<=4'd1;   
								end				
						end
				5:
					begin
						j<=4'd0;
						i<=i+1'b1;
					end
			endcase
	endtask
	task PipeLineLight
	(
		input[13:0] PipeLineSetMSTimes0,PipeLineSetMSTimes1,
						PipeLineSetMSTimes2,PipeLineSetMSTimes3
	);
		case(j)
				0:
					begin
						regSetMSTimes[0]<=PipeLineSetMSTimes0;
						regSetMSTimes[1]<=PipeLineSetMSTimes1;
						regSetMSTimes[2]<=PipeLineSetMSTimes2;
						regSetMSTimes[3]<=PipeLineSetMSTimes3;
						regStart[0]<=1'b1;
						j<=j+1'b1;
					end
				1:
					if(isDone[0])
						begin
							regStart[0]<=1'b1;
							regStart[1]<=regStart[0];
							regStart[2]<=regStart[1];
							regStart[3]<=regStart[2];
							
							k<=k+1'b1;
							if(k==4'd2)
								begin
									k<=4'd0;
									j<=j+1'b1;
								end
							else
								j<=j;
						end
				2:
					if(isDone[3])
						begin
							regStart[0]<=1'b0;
							regStart[1]<=regStart[0];
							regStart[2]<=regStart[1];
							regStart[3]<=regStart[2];
							k<=k+1'b1;
							if(k==4'd3)
								begin
									k<=4'd0;
									j<=j+1'b1;
								end
							else
								j<=j;
						end
				3:
					begin
						j<=4'd0;
						i<=i+1'b1;
					end
			endcase
	endtask
	task ParallelPipeLineLight
	(
		input[13:0] PipeLineSetMSTimes0,PipeLineSetMSTimes1,
						PipeLineSetMSTimes2,PipeLineSetMSTimes3
	);
		case(j)
				0:
					begin
						regSetMSTimes[0]<=PipeLineSetMSTimes0;
						regSetMSTimes[1]<=PipeLineSetMSTimes1;
						regSetMSTimes[2]<=PipeLineSetMSTimes2;
						regSetMSTimes[3]<=PipeLineSetMSTimes3;
						regStart[0]<=1'b1;
						regStart[2]<=1'b1;
						j<=j+1'b1;
					end
				1:
					if(isDone[0])
						begin
							regStart[0]<=1'b1;
							regStart[1]<=regStart[0];
							regStart[2]<=1'b1;
							regStart[3]<=regStart[2];
							k<=k+1'b1;
							if(k==4'd0)
								begin
									k<=4'd0;
									j<=j+1'b1;
								end
							else
								j<=j;
						end
				2:
					if(isDone[1])
						begin
							regStart[0]<=1'b0;
							regStart[1]<=regStart[0];
							regStart[2]<=1'b0;
							regStart[3]<=regStart[2];
							k<=k+1'b1;
							if(k==4'd1)
								begin
									k<=4'd0;
									j<=j+1'b1;
								end
							else
								j<=j;
						end
				3:
					begin
						j<=4'd0;
						i<=i+1'b1;
					end
			endcase
	endtask
endmodule

module Led_Driver
(
	input clk,rst_n,
	input StartSig,
	input[55:0] setMSTimes,
	output DoneSig,
	output ledOut
);

	wire[13:0] halrSetMSTimes;
	wire timerOut;
	Led_Driver_Control Led_Driver_Control
	(
		.clk(clk),
		.rst_n(rst_n),
		.StartSig(StartSig),
		.setMSTimes(setMSTimes),
		.timerOut(timerOut),
		.DoneSig(DoneSig),
		.halrSetMSTimes(halrSetMSTimes)
	);

											  //ÏÈÇó³öÖظ´ÊµÀýµÄ×ÜλÊý£¬È»ºó°´Ã¿¸öʵÀý¶ÔӦλ´ÓµÍµ½¸ß½Ø¶Ï£¬Ã»ÓиßλµÄ¾ÍÊÇÖظ´
	Timer Timer							  //ÿ¸ösetMSTimesÓÐ14룬4¸öTimerÓÐ14*4=56λsetMSTimes£¬
	(										  //Ôò¸øsetMSTimes¸³ÖµÎª56룬setMSTimes»á°´¶ÔӦλ½Ø¶Ï£¬
		.clk(clk),						  //setMSTimes[0]¶ÔÓ¦[13:0]룬setMSTimes[1]¶ÔÓ¦[27:14]λ
		.rst_n(rst_n),					  //setMSTimes[2]¶ÔÓ¦[41:28]룬setMSTimes[3]¶ÔÓ¦[55:42]λ
		.StartSig(StartSig),
		.setMSTimes(halrSetMSTimes),  
		.timerOut(timerOut)
	);

	Led_Interface Led_Interface
	(
		.clk(clk),
		.rst_n(rst_n),
		.StartSig(StartSig),
		.timerIn(timerOut),
		.ledOut(ledOut)
	);
	
endmodule


module Led_Driver_Control
(
	input clk,rst_n,
	input StartSig,
	input[13:0] setMSTimes,
	input timerOut,
	output DoneSig,
	output[13:0] halrSetMSTimes
);
	
	
	reg countTimerOut;
	
	always@(posedge clk,negedge rst_n)  //¶ÔʱÖÓ¼ÆÊý£¬ÅжÏÇ°Ò»¸öµÆµÄÁÁÃð
		if(!rst_n)
			countTimerOut<=1'b0;
		else if(StartSig)
			begin
				if(timerOut && (countTimerOut==1'b1) )
					countTimerOut<=1'b0;
				else if(timerOut)
					countTimerOut<=countTimerOut+1'b1;
			end
		else
			countTimerOut<=1'b0;
	
	assign DoneSig=(StartSig && timerOut && (countTimerOut==1'b1) )?1'b1:1'b0;	
	assign halrSetMSTimes=setMSTimes>>1;

endmodule


module Timer
(
	input clk,rst_n,
	input[13:0] setMSTimes,
	input StartSig,
	output timerOut
);

	wire MSOut;

	MSTimer MSTimer
	(
		.clk(clk),
		.rst_n(rst_n),
		.StartSig(StartSig),
		.MSOut(MSOut)
	);

	NMSTimer NMSTimer
	(
		.clk(clk),
		.rst_n(rst_n),
		.setMSTimes(setMSTimes),
		.StartSig(StartSig),
		.MSIn(MSOut),
		.NMSOut(timerOut)
	);
		
endmodule

module MSTimer
(
	input clk,rst_n,
	input StartSig,
	output MSOut
);
	reg[15:0] countMS;
	always@(posedge clk,negedge rst_n)
		if(!rst_n)
			countMS<=16'd0;
		else if(StartSig)
			begin
				if(countMS == `T1MS)
					countMS<=16'd0;
				else
					countMS<=countMS+1'b1;
			end
		else
			countMS<=16'd0;
			
	assign MSOut=(StartSig && (countMS == `T1MS) )?1'b1:1'b0;

endmodule

module NMSTimer
(
	input clk,rst_n,
	input MSIn,
	input StartSig,
	input[13:0] setMSTimes,
	output NMSOut
);

	reg[13:0] countNMS;   	
	always@(posedge clk,negedge rst_n) 
		if(!rst_n)
			countNMS<=14'd0;
		else if(StartSig)
			begin
				if(MSIn && (countNMS==(setMSTimes-1'd1) ) )   
					countNMS<=14'd0;								 	 
				else if(MSIn)
					countNMS<=countNMS+1'b1;
			end
		else
			countNMS<=14'd0;
			
	assign NMSOut=(StartSig && MSIn && (countNMS==(setMSTimes-1'd1) ) )?1'b1:1'b0;

endmodule

module Led_Interface
(
	input clk,rst_n,
	input StartSig,
	input timerIn,
	output ledOut
);

	reg regLedOut;
	
	always@(posedge clk,negedge rst_n)
		if(!rst_n)
			regLedOut<=1'b0;
		else if(StartSig)
			begin
				if(timerIn)
					regLedOut<=~regLedOut;
			end
		else
			regLedOut<=1'b0;
	
	assign ledOut=regLedOut;

endmodule
// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module display(
    rst_n,
    clk,
    min_h,      
    min_l,
    sec_h,      
    sec_l,
    display_flag,
    seg,
    sel
    );
    input                   rst_n;                                     //   全局复位,低电平有效
    input                   clk;                                       //   全局时钟,50MHz
    input       [2:0]       min_h;                                     //   分的十位数
    input       [3:0]       min_l;                                     //   分的个位数
    input       [2:0]       sec_h;                                     //   秒的十位数
    input       [3:0]       sec_l;                                     //   秒的个位数
    input                   display_flag;                              //   数码管动态显示标志位
    output reg  [7:0]       seg;                                       //   编码后的数码管输出
    output reg  [3:0]       sel;                                       //   数码管的位选
  
    function [7:0]  seg_data;
        input   [3:0]       din;                                       //   待编码数据
        input               dp;                                        //   决定数码管点号是否点亮,1为点亮
        
        begin
            case(din)
            4'd0 : seg_data = {dp,7'b1000000};
            4'd1 : seg_data = {dp,7'b1111001};
            4'd2 : seg_data = {dp,7'b0100100};
            4'd3 : seg_data = {dp,7'b0110000};
            4'd4 : seg_data = {dp,7'b0011001};
            4'd5 : seg_data = {dp,7'b0010010};
            4'd6 : seg_data = {dp,7'b0000010};
            4'd7 : seg_data = {dp,7'b1111000};
            4'd8 : seg_data = {dp,7'b0000000};
            4'd9 : seg_data = {dp,7'b0010000};
            endcase
        end
    endfunction
    
   wire flag;
	assign flag=(min_l>=3'b010);
    reg         [1:0]       cnt;                                       //   由于只有四个数码管,故只需两位
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n == 1'b0)
            cnt <= (0);
        else if(display_flag == 1'b1)
            cnt <= cnt + 1'b1;
        else
            cnt <= cnt;
    end
    
  
    always @(posedge clk or negedge rst_n)
    begin
        if(rst_n == 1'b0)
        begin
            seg <= (0);
            sel <= (0);
        end
		  else if(flag==1'b1)
				begin
					case(cnt)
            2'b00 :                                                    //   显示秒个位数
            begin
                seg <= {1'b1,7'b0111111};
                sel <= 4'b0111;
            end
            
            2'b01 :                                                    //   显示秒十位数
            begin
                seg <= {1'b1,7'b1000000};
                sel <= 4'b1011;
            end
            
            2'b10 :                                                    //   显示分个位数
            begin
                seg <= {1'b1,7'b0001000};
                sel <= 4'b1101;
            end
            
            2'b11 :                                                    //   显示分十位数
            begin
                seg <= {1'b1,7'b0000011};
                sel <= 4'b1110;
            end
            endcase
				end
        else
        begin
            case(cnt)
            2'b00 :                                                    //   显示秒个位数
            begin
                seg <= seg_data(sec_l,1'b1);
                sel <= 4'b0111;
            end
            
            2'b01 :                                                    //   显示秒十位数
            begin
                seg <= seg_data({1'b0,sec_h},1'b1);
                sel <= 4'b1011;
            end
            
            2'b10 :                                                    //   显示分个位数
            begin
                seg <= seg_data(min_l,1'b0);
                sel <= 4'b1101;
            end
            
            2'b11 :                                                    //   显示分十位数
            begin
                seg <= seg_data({1'b0,min_h},1'b1);
                sel <= 4'b1110;
            end
            endcase
        end
    end
  

endmodule

// synopsys translate_off
`timescale 1 ns / 1 ps
// synopsys translate_on
module time_counter(
    rst_n,
    clk,        
    min_h,      
    min_l,
    sec_h,      
    sec_l,
    display_flag
    );
    
    parameter   CLK_CYCLE = 20;                                        //   时钟周期,单位ns
    parameter   T0        = 1000_000;                                  //   1ms延时
 
    parameter   T0_VAL    = T0/CLK_CYCLE-1;                            //   1ms延时
  
    input                   rst_n;                                     //   全局复位,低电平有效
    input                   clk;                                       //   全局时钟,50MHz
    output reg  [2:0]       min_h;                                     //   分的十位数
    output reg  [3:0]       min_l;                                     //   分的个位数
    output reg  [2:0]       sec_h;                                     //   秒的十位数
    output reg  [3:0]       sec_l;                                     //   秒的个位数
    output                  display_flag;                              //   数码管动态扫描标志位
 
    reg [15:0]  cnt;
    always@(posedge clk or negedge rst_n)
    begin
        if(rst_n == 1'b0)
            cnt <= (0);
        else if(cnt < T0_VAL)
            cnt <= cnt + 1'b1;
        else
            cnt <= (0);
    end
    assign  delay_1ms = (cnt == T0_VAL);                               //   1ms延时完成标志位
    assign  display_flag = delay_1ms;                                  //   数码管动态扫描标志位
   
    reg         [9:0]       mse;
    always@(posedge clk or  negedge rst_n)
    begin
        if(rst_n == 1'b0)
            mse <= (0);
        else
        begin
            if(delay_1ms == 1'b1)
            begin
                if(mse < 10'd999)
                    mse <= mse + 1'b1;
                else
                    mse <= (0);
            end
        end
    end
    wire    sec_l_flag = ((mse == 10'd999) && (delay_1ms == 1'b1));      //  1s延时完成标志位
   
    //  秒个位数计数
    always@(posedge clk or  negedge rst_n)
    begin
        if(rst_n == 1'b0)
            sec_l <= 0;
        else
        begin
            if(sec_l_flag == 1'b1)
            begin
                if(sec_l < 4'd9)
                    sec_l <= sec_l + 1'b1;
                else
                    sec_l <= 0;
            end
        end
    end
    wire    sec_h_flag = ((sec_l == 4'd9) && (sec_l_flag == 1'b1));    //  秒个位数进位标志位
    
    //  秒十位数计数
    always@(posedge clk or  negedge rst_n)
    begin
        if(rst_n == 1'b0)
            sec_h <= 0;
        else
        begin
            if(sec_h_flag == 1'b1)
            begin
                if(sec_h < 3'd5)
                    sec_h <= sec_h + 1'b1;
                else
                    sec_h <= 0;
                end
        end
    end
    wire    min_l_flag = ((sec_h == 3'd5) && (sec_h_flag == 1'b1));    //  秒十位数进位标志位
    
   
    //  分个位数计数
    always@(posedge clk or  negedge rst_n)
    begin
        if(rst_n == 1'b0)
            min_l <= 0;
        else
        begin
            if(min_l_flag == 1'b1)
            begin
                if(min_l < 4'd9)
                    min_l <= min_l + 1'b1;
                else
                    min_l <= 0;
            end
        end
    end
    wire    min_h_flag = ((min_l == 4'd9) && (min_l_flag == 1'b1));    //  分个位数进位标志位
    
    //  分十位数计数
    always@(posedge clk or  negedge rst_n)
    begin
        if(rst_n == 1'b0)
            min_h <= 0;
        else
        begin
            if(min_h_flag == 1'b1)
            begin
                if(min_h < 3'd5)
                    min_h <= min_h + 1'b1;
                else
                    min_h <= 0;
            end
        end
    end
   

endmodule

五。总结

本设计中主体部分是一个分秒计时器的状态机,运用了分频,数码管的动态扫描等原理。灵活使用了数码管,开关,led等设备实现了计时器,流水灯,显示等,从而完成了一个具有一定可玩性的小游戏。

原文地址:https://www.cnblogs.com/JK-Z/p/12262077.html