• 【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等设备实现了计时器,流水灯,显示等,从而完成了一个具有一定可玩性的小游戏。

  • 相关阅读:
    Micorosoft 2013年笔试题
    Dropbox推荐使用
    swift_枚举 | 可为空类型 | 枚举关联值 | 枚举递归 | 树的概念
    swift_简单值 | 元祖 | 流程控制 | 字符串 | 集合
    Swift函数的定义
    swift_Dictionary 字典
    Xcode创建Object-C程序
    Spring事务管理者与Spring事务注解--声明式事务
    JDK注解替代Hibernate的Entity映射
    关于JAVA EE项目在WEB-INF目录下的jsp页面如何访问WebRoot中的CSS和JS文件
  • 原文地址:https://www.cnblogs.com/JK-Z/p/12262077.html
Copyright © 2020-2023  润新知