北邮数电实验四-基础部分代码

基于 Verilog 的骰子游戏电路设计与实现(基础版)

一、写在前面

这是骰子游戏的全部代码(除提高)提高部分还暂时没写,后续应该会自己写一个将乐谱转化为verilog的工具并开源(如果顺利的话)。数电实验所有代码均已经开源在我们的GitHub仓库,大家可以免费获取,我们致力于打造自由的作业交流平台,四个实验的代码都是我们小伙伴们自己完成,并自愿开源到GitHub上的(csdn开源的文件还需要强制VIP才能下载,所以我们都托管到了GitHub)如果对你有帮助,希望你可以在我们的仓库为我们点一个star!我们后续会一直维护这个仓库,上传最新的资料!

二、整体架构概述

整个骰子游戏电路主要由以下几个关键模块组成:

  1. debounce 模块:用于对原始按键输入信号进行消抖处理,确保按键信号的稳定性,避免因机械按键的抖动而产生误触发。
  2. randomrandom2 模块:这两个模块分别实现了线性反馈移位寄存器(LFSR)算法,用于生成随机数,模拟骰子的点数输出。
  3. dot_matrix 模块:负责将骰子的点数以点阵的形式显示出来,通过控制行和列信号来点亮相应的 LED 点阵,直观地展示游戏结果。
  4. is_roll 模块:该模块根据时钟信号和外部触发信号,控制骰子的投掷操作,协调随机数生成器的工作,并处理相关的逻辑。
  5. debounce_double 模块:针对特定的按键输入进行消抖处理,确保在游戏过程中的按键操作准确无误。
  6. segment 模块:用于驱动数码管显示,将玩家的得分以数字形式展示出来,方便玩家实时了解游戏进展。
  7. prescaler 模块:对输入时钟进行分频操作,得到满足其他模块工作频率需求的时钟信号,确保整个系统各模块之间的时序协调。
  8. score 模块:实现游戏的计分逻辑,根据骰子的点数比较结果更新玩家的得分,并判断游戏是否结束以及最终的胜负情况。
  9. standby 模块:在游戏过程中控制 RGB 灯光的显示逻辑,根据游戏状态和得分情况呈现不同的灯光效果,增强游戏的可视化体验。
  10. dice模块:顶层模块,定义了主要用于实例化各个函数。

三、模块详细解析

(一)debounce 模块

module debounce (
    input wire clk,             // 时钟信号
    input wire rst_n,           // 异步复位信号,低电平有效
    input wire key_in,          // 原始按键输入信号
    output reg key_pressed,     // 按键按下信号
    output reg key_released     // 按键释放信号
);

    // 参数定义:假设消抖时间为 20ms
    parameter DEBOUNCE_TIME = 20_000; // 假设时钟频率为 1 MHz(即 1us 一个周期)
    reg [19:0] debounce_cnt;         // 消抖计数器
    reg key_state;                   // 按键稳定状态
    reg key_state_last;              // 上一个稳定状态

    // 按键状态同步
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            debounce_cnt <= 20'd0;
            key_state <= 1'b0;       // 默认按键未按下(低电平为未按下)
            key_state_last <= 1'b0;
        end else begin
            if (key_in == key_state) begin
                // 输入信号和稳定状态一致,计数器清零
                debounce_cnt <= 20'd0;
            end else begin
                // 输入信号和稳定状态不一致,计数器累加
                if (debounce_cnt < DEBOUNCE_TIME) begin
                    debounce_cnt <= debounce_cnt + 20'd1;
                end else begin
                    // 当计数器满时,更新稳定状态
                    debounce_cnt <= 20'd0;
                    key_state <= key_in;
                end
            end
            // 保存上一个稳定状态
            key_state_last <= key_state;
        end
    end

    // 按键事件检测
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            key_pressed <= 1'b0;
            key_released <= 1'b0;
        end else begin
            key_pressed <= (key_state_last == 1'b0) && (key_state == 1'b1);  // 按键从未按下到按下
            key_released <= (key_state_last == 1'b1) && (key_state == 1'b0); // 按键从按下到未按下
        end
    end

endmodule

这个模块通过一个计数器来实现消抖功能。当按键输入信号与当前稳定状态不一致时,计数器开始累加。如果在规定的消抖时间内(这里假设为 20ms,对应特定的时钟频率)计数器达到设定值,说明按键状态稳定,此时更新稳定状态并输出相应的按键按下或释放信号。

(二)randomrandom2 模块

module random(
	 input clk,
    input wire rst,          // 复位信号
    input wire roll,         // 掷骰子触发信号
    output reg [3:0] dice,    // 输出随机数(0-9)
	 input finish
);

    reg [3:0] lfsr;          // 4 位线性反馈移位寄存器 (LFSR)

initial begin
	lfsr <= 4'b1001;  // 初始化 LFSR,不为 0
   dice <= 4'b1001;
end

    always @(posedge roll or negedge rst or posedge finish) begin
        if (!rst) begin
            lfsr <= 4'b1001;  // 初始化 LFSR,不为 0
            dice <= 4'b1001;  // 初始骰子值为 0
        end else if (finish) begin
				dice<=4'b1001;
        end
		  else begin
				if(roll)begin
            // 更新 LFSR 值
            lfsr <= {lfsr[2:0], lfsr[3] ^ lfsr[2]};
            dice <= (lfsr % 9)+1;  // 映射到 0-9
				end
		  end
    end
endmodule


module random2(
	 input clk,
    input wire rst,          // 复位信号
    input wire roll,         // 掷骰子触发信号
    output reg [3:0] dice,    // 输出随机数(0-9)
	 input finish
);

    reg [3:0] lfsr;          // 4 位线性反馈移位寄存器 (LFSR)

initial begin
	lfsr <= 4'b0001;  // 初始化 LFSR,不为 0
   dice <= 4'b1001;
end	 

    always @(posedge roll or negedge rst or posedge finish) begin
        if (!rst) begin
            lfsr <= 4'b0001;  // 初始化 LFSR,不为 0
            dice <= 4'b1001;  // 初始骰子值为 0
        end else if (finish) begin
				dice<=4'b1001;
        end
		  else begin
				if(roll)begin
            // 更新 LFSR 值
            lfsr <= {lfsr[2:0], lfsr[3] ^ lfsr[2]};
            dice <= (lfsr % 9)+1;  // 映射到 0-9
				end
		  end
    end
endmodule

这两个模块都基于线性反馈移位寄存器(LFSR)来生成随机数。当 roll 信号有效且系统未处于 finish 状态时,LFSR 的值会根据特定的反馈逻辑进行更新,然后将更新后的 LFSR 值映射到 1 - 9 的范围作为骰子的点数输出。

(三)dot_matrix 模块

module dot_matrix (
    input wire clk,           // 时钟信号
    input wire rst,           // 复位信号
	 input stop,
    input wire [3:0] dice1,    // 输入骰子数字(1-9)
	 input wire [3:0] dice2,       //第二个骰子
    output reg [7:0] row,     // 行信号(ROW7 - ROW0)
    output reg [7:0] r_col,    // 红色列信号(R_COL7 - R_COL0)
	 output reg [7:0] g_col     // 绿色列信号
);


    reg [7:0] row_patterns;  // 行信号
    reg [2:0] red_patterns[2:0];  // 红色列信号
	 reg [2:0] green_patterns[2:0];  //绿色信号 
    reg [2:0] scan_index;         // 当前扫描行索引(0~7)
	 reg [1:0] sel;   //这是来选择列信号的,每一个时钟周期变化一次

	initial //参数初始化
	begin
		r_col <= 8'b0000_0000;
		g_col <= 8'b0000_0000;
	end
	 
	 
always@(*)begin   //给红色信号的低三位赋值
	 case(dice1)
	 4'b0001:begin  //1
		red_patterns[0] = 3'b000;
		red_patterns[1] = 3'b010;
		red_patterns[2] = 3'b000;
		end
	 4'b0010:begin  //2
		red_patterns[0] = 3'b001;
		red_patterns[1] = 3'b000;
		red_patterns[2] = 3'b100;
		end
	 4'b0011:begin  //3
		red_patterns[0] = 3'b100;
		red_patterns[1] = 3'b010;
		red_patterns[2] = 3'b001;
		end
	 4'b0100:begin  //4
		red_patterns[0] = 3'b101;
		red_patterns[1] = 3'b000;
		red_patterns[2] = 3'b101;
		end
	 4'b0101:begin  //5
		red_patterns[0] = 3'b101;
		red_patterns[1] = 3'b010;
		red_patterns[2] = 3'b101;
		end
	 4'b0110:begin  //6
		red_patterns[0] = 3'b111;
		red_patterns[1] = 3'b000;
		red_patterns[2] = 3'b111;
	   end
	 4'b0111:begin   //7
		red_patterns[0] = 3'b111;
		red_patterns[1] = 3'b010;
		red_patterns[2] = 3'b111;
		end
	 4'b1000:begin    //8
		red_patterns[0] = 3'b111;
		red_patterns[1] = 3'b101;
		red_patterns[2] = 3'b111;
		end
	 4'b1001:begin    //9
		red_patterns[0] = 3'b111;
		red_patterns[1] = 3'b111;
		red_patterns[2] = 3'b111;
		end
		default:begin  //默认都不亮
		red_patterns[0] = 3'b000;
		red_patterns[1] = 3'b000;
		red_patterns[2] = 3'b000;
		end
	 endcase
	 
	 case(dice2)   //给绿色信号的高三位赋值
	 4'b0001:begin  //1
		green_patterns[0] = 3'b000;
		green_patterns[1] = 3'b010;
		green_patterns[2] = 3'b000;
		end
	 4'b0010:begin  //2
		green_patterns[0] = 3'b001;
		green_patterns[1] = 3'b000;
		green_patterns[2] = 3'b100;
		end
	 4'b0011:begin  //3
		green_patterns[0] = 3'b100;
		green_patterns[1] = 3'b010;
		green_patterns[2] = 3'b001;
		end
	 4'b0100:begin  //4
		green_patterns[0] = 3'b101;
		green_patterns[1] = 3'b000;
		green_patterns[2] = 3'b101;
		end
	 4'b0101:begin  //5
		green_patterns[0] = 3'b101;
		green_patterns[1] = 3'b010;
		green_patterns[2] = 3'b101;
		end
	 4'b0110:begin  //6
		green_patterns[0] = 3'b111;
		green_patterns[1] = 3'b000;
		green_patterns[2] = 3'b111;
	   end
	 4'b0111:begin   //7
		green_patterns[0] = 3'b111;
		green_patterns[1] = 3'b010;
		green_patterns[2] = 3'b111;
		end
	 4'b1000:begin    //8
		green_patterns[0] = 3'b111;
		green_patterns[1] = 3'b101;
		green_patterns[2] = 3'b111;
		end
	 4'b1001:begin    //9
		green_patterns[0] = 3'b111;
		green_patterns[1] = 3'b111;
		green_patterns[2] = 3'b111;
		end
	 default:begin
		green_patterns[0] = 3'b000;
		green_patterns[1] = 3'b000;
		green_patterns[2] = 3'b000;
		end
	 endcase
end

reg [2:0]flag;//计八个数
reg assist;
initial begin
	flag<=0;
end

    // 显示点阵逻辑
    always @(posedge clk or negedge rst ) begin
		  if (!rst) begin
            row <= 8'b1111_1111;  // 所有行禁用
            r_col <= 8'b0000_0000; // 红色列全灭
				g_col <= 8'b0000_0000;
        end else begin
				if(flag==3'b000)begin
					row <= 8'b01111111; // 使用移位来进行赋值
					r_col[2:0] <= red_patterns[0];//将红色低三位赋值给列
					g_col <= 8'b0000_0000;
					flag <=flag +1 ;
				end
				if(flag==3'b001) begin
					row <= 8'b10111111;
					r_col[2:0] <= red_patterns[1];//将绿色高三位赋值给列信号
					flag <= flag+1;
					end
				if(flag==3'b010)begin
					row <= 8'b1101_1111;
					r_col[2:0] <= red_patterns[2];
					flag <= flag +1;
					end
				if(flag == 3'b011)begin
					row <= 8'b1110_1111;
					flag <= flag +1;
					r_col <= 8'b0000_0000;
				end
				if(flag == 3'b100)begin
					row <= 8'b1111_0111;
					flag <= flag+1;
				end
				if(flag ==3'b101)begin
					row <= 8'b1111_1011;
					g_col[7:5] <= green_patterns[0];
					flag <= flag+1;
				end
				if(flag == 3'b110)begin
					row <= 8'b1111_1101;
					g_col[7:5] <= green_patterns[1];
					flag <= flag+1;
				end
				if(flag == 3'b111)begin
					row <= 8'b1111_1110;
					g_col[7:5] <= green_patterns[2];
					flag <= 3'b000;
				end
			end
    end

endmodule

(四)is_roll 模块

module is_roll(                   //测试模块用于根据时钟信号,每0.2秒进行扔骰子操作
	 input clk, //时钟选择1kHz
    input wire rst,          // 复位信号
    output [3:0] dice1,   // 输出随机数(0-9)
	 output [3:0] dice2,
	 input start1,
	 input start2,
	 input finish
);

reg roll1,roll2;  //设置start信号,由时钟控制
reg [9:0] count1,count2;  //20计数器,即选择5位
reg cnt;


initial begin
	count1 <= 10'b0000_0000;
	count2 <= 10'b0000_0000;
	roll1 <= 1'b0;
	roll2 <= 1'b0;
	cnt <= 1'b0;
end

    // 实例化第二个随机数生成器
    random2 u_random2 (
        .clk(clk),
		  .rst(rst),        // 连接复位信号
        .roll(roll2),      // 连接掷骰子触发信号
        .dice(dice2),      // 连接第二个骰子的随机数输出
		  .finish(finish)
    );
	 
	 	     // 实例化第一个随机数生成器
    random u_random1 (
        .clk(clk),
		  .rst(rst),        // 连接复位信号
        .roll(roll1),      // 连接掷骰子触发信号
        .dice(dice1),      // 连接第一个骰子的随机数输出
		  .finish(finish)
    );
	 

always @(posedge clk or negedge rst) begin
    if (!rst) begin
        roll1 <= 1'b0;
        count1 <= 10'b0;
    end 
	 else 
	 if(start1)begin
		 if (count1 < 10'd100) begin
			  count1 <= count1 + 1;
			  roll1 <= 0;
		 end else begin
			  count1 <= 10'b0;
			  roll1 <= 1;  // 触发掷骰子
		 end
	 end
	 else begin
		count1<=10'd0;
	 end
end


always @(posedge clk or negedge rst) begin
    if (!rst) begin
		  roll2 <= 1'b0;
        count2 <= 10'b0;
    end 
	 else 
	 if(start2)begin
		 if (count2 < 10'd100) begin
			  count2 <= count2 + 1;
			  roll2 <= 0;
		 end else begin
			  count2 <= 10'b0;
			  roll2 <= 1;  // 触发掷骰子
		 end
	 end
	 else begin
		count2<=10'd0;
	 end
end

endmodule		

这个模块主要用于控制骰子的投掷操作时机。它内部包含了计数器 count,在复位后,随着时钟上升沿,计数器开始累加,当计数器未达到设定值(这里根据代码逻辑与相关时间设定有关)时,不会触发掷骰子操作,即 roll1roll2 保持为 0。而当计数器达到设定值后,会根据外部输入的 start1start2 信号来触发对应的随机数生成器(randomrandom2 模块)进行骰子点数的生成,以此模拟玩家投掷骰子的动作。同时,还实例化了 debounce 模块用于对相关按键输入(虽然代码中 key_in 等未明确外部连接,但功能上是用于消抖相关按键操作的)进行消抖处理,确保操作的准确性。

(五)debounce_double 模块

module debounce_double (     
    input stop,               //暂停时候不进行任何逻辑
	 input wire clk,           // 时钟信号
    input wire btn_in,        // 原始按键信号
    output reg btn_out        // 去抖动后的稳定按键信号
);
    reg [16:0] counter = 0;   // 用于计数的20位计数器
    reg btn_sync_0, btn_sync_1;  // 同步化寄存器
    reg btn_state = 0;        // 记录当前稳定的按键状态

	 // 使用两个触发器同步按键输入信号,避免亚稳态
    always @(posedge clk or posedge stop) begin
			  btn_sync_0 <= btn_in;           // 第一层同步
			  btn_sync_1 <= btn_sync_0;       // 第二层同步
    end

    // 计时器和去抖动逻辑
    always @(posedge clk or posedge stop) begin
       if(stop)begin
			btn_out<=0;
		 end
		 else begin
		  if (btn_sync_1 != btn_state) begin
            // 如果检测到按键状态发生变化,开始计时
            counter <= counter + 1;
            if (counter == 16'b0100_1110_0010_0000) begin  // 经过足够长时间(20位计数器达到最大)
                btn_state <= btn_sync_1;    // 更新按键状态
                btn_out <= btn_sync_1;      // 输出去抖动后的按键信号
                counter <= 0;               // 计数器清零
            end
        end else begin
            counter <= 0;  // 如果按键状态没有变化,计数器保持清零
        end
		 end
    end
endmodule

该模块实现了按键的消抖功能,尤其适用于游戏中需要稳定按键输入的场景。首先通过两个触发器 btn_sync_0btn_sync_1 对原始按键输入 btn_in 进行同步处理,避免亚稳态问题。然后设置了一个计数器,当检测到同步后的按键状态与当前稳定的按键状态 btn_state 不一致时,计数器开始累加,当计数器累加到特定值(代表经过了足够的消抖时间),就更新按键状态并输出稳定的去抖动后的按键信号 btn_out。如果按键状态一直没有变化或者系统处于暂停(stop 信号有效)状态,则按照相应逻辑处理计数器和输出信号。

(六)segment 模块

module segment(
    input [3:0] score1,     // 8位 BCD 数字,低四位为玩家1,高四位为玩家二
	 input [3:0] score2,
    input clk,               // 时钟信号
    output reg [7:0] cat,    // 位选信号,用于选择显示的数码管
    output reg [7:0] signal  // 7段显示信号
);

// 初始化 cat 为 2'b01,用于初始选择个位
initial begin
    cat = 8'b0111_1111;
    signal = 8'b00000000;  // 给 seg 一个初始值
end

// 在时钟上升沿切换 cat,并根据 cat 显示对应的数码管
always @(posedge clk) begin
    // 使用移位操作来交替切换 cat
    {cat[7],cat[0]} <= {cat[0], cat[7]}; // 将 cat 的值在 2'b01 和 2'b10 之间切换

    // 根据 cat 来选择不同的数码管并输出相应的 BCD 信号
    if ({cat[7],cat[0]} == 2'b01) begin
        // 显示个位,低四位玩家一
        case (score1)
           4'b0000: signal = 8'b1111_1100; // 显示 "0"
			  4'b0001: signal = 8'b0110_0000; // 显示 "1"
			  4'b0010: signal = 8'b1101_1010; // 显示 "2"
			  4'b0011: signal = 8'b1111_0010; // 显示 "3"
			  4'b0100: signal = 8'b0110_0110; // 显示 "4"
			  4'b0101: signal = 8'b1011_0110; // 显示 "5"
			  4'b0110: signal = 8'b1011_1110; // 显示 "6"
			  4'b0111: signal = 8'b1110_0000; // 显示 "7"
			  4'b1000: signal = 8'b1111_1110; // 显示 "8"
			  4'b1001: signal = 8'b1111_0110; // 显示 "9"
			  default: signal = 8'b0000_0000; // 默认全部熄灭
        endcase
    end else if ({cat[7],cat[0]} == 2'b10) begin
        // 显示十位,玩家2
        case (score2)
           4'b0000: signal = 8'b1111_1100; // 显示 "0"
			  4'b0001: signal = 8'b0110_0000; // 显示 "1"
			  4'b0010: signal = 8'b1101_1010; // 显示 "2"
			  4'b0011: signal = 8'b1111_0010; // 显示 "3"
			  4'b0100: signal = 8'b0110_0110; // 显示 "4"
			  4'b0101: signal = 8'b1011_0110; // 显示 "5"
			  4'b0110: signal = 8'b1011_1110; // 显示 "6"
			  4'b0111: signal = 8'b1110_0000; // 显示 "7"
			  4'b1000: signal = 8'b1111_1110; // 显示 "8"
			  4'b1001: signal = 8'b1111_0110; // 显示 "9"
			  default: signal = 8'b0000_0000; // 默认全部熄灭
        endcase
    end
end

endmodule

segment 模块的主要功能是驱动数码管显示玩家的得分情况。模块初始化时设置了 cat(位选信号)和 signal(7 段显示信号)的初始值。在每个时钟上升沿,通过移位操作切换 cat 的值,使其在 2'b012'b10 之间交替,以此来选择不同的数码管(个位或十位对应的数码管)。然后根据 cat 的值以及输入的玩家得分(score1score2),通过 case 语句来确定 signal 的具体值,从而在数码管上显示出对应的数字,实现了对玩家得分的可视化展示。

(七)prescaler 模块

module prescaler #(
    parameter DIVIDE_BY = 1000      // 分频因子,默认分频为2
)(
    input wire clk_in,           // 输入时钟信号
    input wire rst,              // 复位信号
    output reg clk_out           // 输出分频后的时钟信号
);

    reg [31:0] counter = 0;      // 32位计数器,用于计数输入时钟周期

    always @(posedge clk_in or negedge rst) begin
        if (!rst) begin
            counter <= 0;        // 如果复位信号为高电平,清零计数器
            clk_out <= 0;        // 复位时,将输出时钟清零
        end else begin
            if (counter == DIVIDE_BY- 1 ) begin
                counter <= 0;    // 每到达分频周期时,计数器清零
                clk_out <= ~clk_out; // 翻转输出时钟
            end else begin
                counter <= counter + 1; // 否则,计数器自增
            end
        end
    end

endmodule

此模块是一个简单但实用的时钟分频器。它基于一个 32 位的计数器 counter 来实现对输入时钟 clk_in 的分频功能。根据设定的分频因子 DIVIDE_BY,每当计数器累加到 DIVIDE_BY - 1 时,就将计数器清零,并对输出时钟 clk_out 进行翻转(取反)操作,从而得到一个频率为输入时钟频率除以 DIVIDE_BY 的分频时钟信号,为系统中其他需要不同时钟频率的模块提供合适的时钟源,确保各模块之间的时序配合。

(八)score 模块

module score(
    input clk,rst,
    input start1,
    input start2,
    input [3:0] dice1,
    input [3:0] dice2,
    output reg [3:0] state1,
    output reg [3:0] state2,
    output reg times,
    output reg is_final,
    output reg finish
);

    reg [27:0] cnt;
    reg [3:0] difference,state1_tmp,state2_tmp;
	reg start1_before,start2_before,flag1,flag2,sign,start1_sync,start2_sync,switch;

    // 初始状态
    initial begin
        cnt <= 28'd0;
        is_final <= 0;
        times <= 0;
        state1 <= 0;
        state2 <= 0;
        finish <= 0;
		  flag1<=0;
		  flag2<=0;
		  sign<=0;
		  difference<=0;
		  start1_before <= 0;
		  start2_before <= 0;
		  start1_sync <= 0;
		  start1_sync <= 0;
		  state1_tmp<=0;
		  state2_tmp<=0;
		  switch<=0;
    end
	 
	 always @(posedge clk or negedge rst) begin
    if (!rst) begin
		  start1_before <= 0;
		  start2_before <= 0;
		  start1_sync <= 0;
		  start1_sync <= 0;
    end else begin
        start1_before <= start1_sync;
        start2_before <= start2_sync;
		  start1_sync <= start1;
		  start2_sync <= start2;
		  if((start1_before==1)&&(start1==0))begin
				flag1<=1;
		  end
		  if((start2_before==1)&&(start2==0))begin
				flag2<=1;
		  end
		  if(flag1&&flag2)begin
			sign<=1;
			flag1<=0;
			flag2<=0;
		  end
		  if(sign)begin
		  if (difference < 2) begin
			if(cnt>=28'd3000000)begin
			sign<=0;end
			end
		  else begin
			if(cnt>=28'd5000000)begin
			sign<=0;end
		  end
    end
end
end


    // 计数逻辑:由时钟信号驱动
    always @(negedge rst or posedge clk) begin
      if(!rst)begin
			cnt<=0;
			finish<=0;
			times<=0;
			is_final<=0;
		end
		else begin
			if (sign) begin
            if (difference < 2) begin
                if (cnt >= 28'd3000000) begin // 计时3秒difference < 2
                    cnt <= 28'd0;
                    times <= 0;
						  finish<=0;
						  is_final <= 0;
						  switch <=0;
					end
					 else if(cnt>=28'd2999900)begin
						finish<=1;
						cnt<=cnt+1;
					end
                else begin
                    cnt <= cnt + 1;
                    times <= 1;
                end
            end
				else begin
            if (cnt >= 28'd5000000) begin // 计时5秒
                cnt <= 28'd0;
                times <= 0;
					 finish<=0;
					 switch <= 0;
					 
				end
				else if(cnt>=28'd3000000)begin
					switch<=1;
					cnt<=cnt+1;
				end
				else if(cnt >= 28'd4999900)begin
					finish<=1;
					cnt<=cnt+1;
				end
            else begin
                cnt <= cnt + 1;
                times <= 1;
                is_final <= 1;
					 finish<=0;
            end
        end
		 end
		end
    end

    // 游戏状态更新逻辑:由 times 的上升沿触发 此时更新的为内在逻辑
    always @(negedge rst or posedge finish or posedge times) begin
        if(!rst)begin
		  	   state1_tmp<=4'b0000;
				state2_tmp<=4'b0000;
				difference = 4'b0;
			end
			else begin
			 if (finish) begin
				if(is_final)begin
					state1_tmp<=4'b0000;
					state2_tmp<=4'b0000;
					difference = 4'b0;
					end
			  end
			 else begin
				if(times)begin
					if (dice1 < dice2)begin
						state2_tmp = state2_tmp + 1;
						difference <= (state1_tmp > state2_tmp) ? state1_tmp - state2_tmp : state2_tmp - state1_tmp;
					end
					else if (dice1 > dice2)begin
						state1_tmp = state1_tmp + 1;
						difference <= (state1_tmp > state2_tmp) ? state1_tmp - state2_tmp : state2_tmp - state1_tmp;
					end
				end
			end
		end
    end
	 
	 
	 //更新显示逻辑
	 always@(negedge rst or negedge times or posedge switch)begin
		if(!rst)begin
			state1<=0;
			state2<=0;
		end
		else begin
			if(!times)begin
				state1<=state1_tmp;
				state2<=state2_tmp;
			end
			else if(switch)begin
				if (dice1 < dice2)begin
					state1<=state1+1;
				end
				else begin
					state2<=state2+1;
				end
			end
		end
	 end
	 

endmodule

(九)standby 模块

module standby(clk, times, is_final, rst, score1, score2, rgb_led,is_finish);  
    input clk;
    input times;
    input is_final,is_finish;
    input rst;
    input [3:0] score1, score2;
    output reg [15:0] rgb_led;
    

    reg [19:0] cnt;
    reg [3:0] score1_reg, score2_reg;

    initial begin
        cnt<=20'd0;
    end
    // 同步复位及寄存分数
    always @(posedge clk or negedge rst) begin
        if (!rst) begin
            score1_reg <= 4'b0;
            score2_reg <= 4'b0;
        end else begin
            score1_reg <= score1;
            score2_reg <= score2;
        end
    end

    // 计数器逻辑
    always @(posedge clk or negedge rst) begin
        if (!rst) begin
            cnt <= 20'd0;
        end else if (!is_final && times) begin  //不是最后一把并且times为高电平
            if (cnt >= 20'd100001) begin
                cnt <= 20'd0;
            end else begin
                cnt <= cnt + 1;
            end
        end
    end

    // RGB灯光逻辑
    always @(posedge clk or negedge rst) begin
        if (!rst) begin
            rgb_led <= 16'b0000_0000_0000_0000;
        end 
        else if (!is_final) begin
            if (times) begin
                if (rgb_led == 16'd0) begin
                    rgb_led <= 16'b0000_0000_0000_0001;
                end else if (cnt >= 20'd100000) begin
                    rgb_led <= {rgb_led[0],rgb_led[15:1]};
                end
            end
            else {
                rgb_led<=16'b0000_0000_0000_0000;
            }
        end
        else {
            if(times)begin
                if (score1_reg > score2_reg) begin
                    rgb_led <= 16'b1111_1111_0000_0000;
                end 
                else {
                    rgb_led <= 16'b0000_0000_1111_1111;
                }
            }
            else {
                rgb_led<=16'b0000_0000_0000_0000;
            }
        end
    end
endmodule

(十)dice顶层模块

module dice(row,r_col,g_col,rst,clk,start1,start2,clk_div,dice1,dice2,signal,cat,rgb_led,beep);
	input rst;
	input clk;
	input start1,start2;
	output [7:0] row; //行控制信号
	output [7:0] r_col; //红色列控制信号
	output [7:0] g_col; //绿色列控制信号
	output clk_div;
	output [3:0] dice1,dice2;
	output [7:0] signal;
	output [7:0] cat;
	output [15:0] rgb_led;
	output beep;

	wire [3:0]score1,score2;
	wire btn_out1,btn_out2;
	wire divided_clk;
	wire times;
	wire is_final;
	wire finish;
	
	prescaler #(
  .DIVIDE_BY(1000)
) u_prescaler (
  .clk_in(clk),
  .rst(rst),
  .clk_out(divided_clk)
);

	debounce_double uut_debounce(
		.stop(times),
		.clk(clk),
		.btn_in(start1),
		.btn_out(btn_out1)
	);
	
	
	debounce_double uut_debounce2(
		.stop(times),
		.clk(clk),
		.btn_in(start2),
		.btn_out(btn_out2)
	);
	
	segment u_segment(
		.clk(clk),
		.score1(score1),
		.score2(score2),
		.cat(cat),
		.signal(signal)
	);
	
	is_roll u_roll(
		.clk(divided_clk),
		.rst(rst),
		.dice1(dice1),
		.dice2(dice2),
		.start1(btn_out1),
		.start2(btn_out2),
		.finish(finish)
	);

	 
	 // 实例化 dot_matrix 模块
    dot_matrix u_dot_matrix (
        .clk(clk),        // 连接时钟信号
        .rst(rst),        // 连接复位信号
        .dice1(dice1),    // 连接第一个骰子的输入
        .dice2(dice2),    // 连接第二个骰子的输入
        .row(row),        // 连接行信号输出
        .r_col(r_col),    // 连接红色列信号输出
        .g_col(g_col),     // 连接绿色列信号输出
		  .stop(times)
    );

// 实例化standby模块
standby standby_inst (
  .clk(clk),
  .times(times),
  .is_final(is_final),
  .rst(rst),
  .score1(score1),
  .score2(score2),
  .rgb_led(rgb_led),
  .is_finish(finish)
);
	 
// 实例化socre模块
score socre_inst (
   .clk(clk),
   .start1(btn_out1),
   .start2(btn_out2),
   .dice1(dice1),
   .dice2(dice2),
   .state1(score1),
   .state2(score2),
   .times(times),
   .is_final(is_final),
	.finish(finish),
	.rst(rst)
);

endmodule

standby 模块在整个骰子游戏系统中承担着控制 RGB 灯光显示效果的重要作用,以此来直观反馈游戏的不同状态。

首先,模块中有一个 cnt 计数器,在复位时被初始化为 20'd0。通过 always 块实现了对输入分数 score1score2 的同步复位及寄存功能,在时钟上升沿或者复位信号有效时,会相应地更新 score1_regscore2_reg 的值,确保其能准确反映当前玩家的得分情况。

在计数器逻辑部分,当系统未处于 is_final 状态(即游戏未结束)并且 times 信号为高电平(意味着处于相应的有效游戏阶段)时,计数器 cnt 开始工作。如果 cnt 的值达到 20'd100001,则将其清零;否则,计数器会随每个时钟周期自增,这个计数器主要用于配合后续的灯光显示逻辑来控制灯光切换的时间间隔等。

而 RGB 灯光逻辑是该模块的核心部分。在复位时,rgb_led 被初始化为全 0,即灯光全灭。当游戏未结束(!is_final)时,如果 times 信号为高电平,会先判断 rgb_led 的值,若其为 16'd0,则将其设置为 16'b0000_0000_0000_0001,表示点亮某一盏灯(具体取决于硬件连接对应的灯光效果),并且当 cnt 达到 20'd100000 时,通过移位操作 {rgb_led[0],rgb_led[15:1]} 来改变灯光的显示状态,实现动态的灯光效果,比如流水灯等形式。当 times 为低电平时,直接将 rgb_led 清零,关闭灯光。

当游戏处于结束状态(is_final 为真)时,如果 times 信号为高电平,会根据寄存的玩家得分 score1_regscore2_reg 来决定最终的灯光显示情况,若 score1_reg 大于 score2_reg,则 rgb_led 被设置为 16'b1111_1111_0000_0000(可能表示玩家 1 获胜对应的灯光颜色或样式),反之则设置为 16'b0000_0000_1111_1111(对应玩家 2 获胜或平局等情况的灯光呈现),若 times 为低电平同样将灯光熄灭,以清晰地通过灯光向玩家展示游戏的最终胜负结果或者游戏过程中的不同阶段状态。

综上所述,通过 standby 模块的这些逻辑,使得整个骰子游戏系统在视觉呈现上更加丰富和直观,增强了游戏的趣味性和交互性。

四、总结

扔色子这个代码最难的地方我觉得在于时序的控制和赋值,尤其是存在五秒和三秒的待机时间,所有的标志位你都需要在一个always块内赋值,所以所有逻辑应该考虑清楚!

五、提高部分

提高部分的python工具我已经写在了这篇博客里面,大家可以跳转阅读,另外也已经更新到GitHub仓库,大家可以进入仓库查看!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻柚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值