module top(
input clk_50M, // 50MHz 输入时钟
input clr, // 清除/复位按钮 (高电平有效) - 用作全局复位
input Main_Switch, // 主开关:向上 (游戏进行中), 向下 (设置模式)
input key_A, // A键:A棋手落子 / 切换到B棋手回合
input key_B, // B键:B棋手落子 / 切换到A棋手回合
input key_C, // C键:调整初始时间 +2.0秒
input key_D, // D键:调整初始时间 -1.0秒
output [7:0]seg, // 7段数码管段选 (a-g, dp)
output [5:0]dig, // 7段数码管位选
output [4:0]LED_O, // 5个LED指示灯输出
output Buzzer, // 蜂鸣器输出
output [3:0] row // 键盘行输出 (固定为0001,与约束文件对应)
);
// 为键盘扫描的 'row' 信号赋固定值。
assign row[3:0] = 4'b0001;
wire carry_out_A;
wire carry_out_B;
// 不同频率时钟信号的内部连线
wire clk_10; // 10 Hz 时钟,用于倒计时
wire clk_50; // 50 Hz 时钟,用于按钮去抖
wire clk_1k; // 1 kHz 时钟,用于7段数码管动态扫描
// 实例化时钟分频模块
divclk#(.N(2499999)) u1_divclk_10Hz (.clk_in(clk_50M), .clk_out(clk_10));
divclk#(.N(499999)) u2_divclk_50Hz (.clk_in(clk_50M), .clk_out(clk_50));
divclk#(.N(24999)) u3_divclk_1kHz (.clk_in(clk_50M), .clk_out(clk_1k));
// 去抖后的按键信号线
wire key_A_xd, key_B_xd, key_C_xd, key_D_xd;
// 实例化按钮去抖模块
ajxd u4_btnA (.btn_in(key_A), .btn_clk(clk_50), .btn_out(key_A_xd));
ajxd u5_btnB (.btn_in(key_B), .btn_clk(clk_50), .btn_out(key_B_xd));
ajxd u6_btnC (.btn_in(key_C), .btn_clk(clk_50), .btn_out(key_C_xd));
ajxd u7_btnD (.btn_in(key_D), .btn_clk(clk_50), .btn_out(key_D_xd));
// 游戏状态定义
parameter STATE_IDLE = 3'b000, // Main_Switch 下:调整初始时间
STATE_A_TURN = 3'b001, // Main_Switch 上:A棋手回合
STATE_B_TURN = 3'b011,// Main_Switch 上:B棋手回合
STATE_A_TIMEOUT = 3'b010, // A棋手超时 (A负,B胜)
STATE_B_TIMEOUT = 3'b110; // B棋手超时 (B负,A胜)
reg [2:0] current_state = STATE_IDLE; // 初态
reg [2:0] next_state; // 下一个状态
// --- 初始倒计时值 (可调) ---
// 存储以0.1秒为单位的初始时间 (5.0秒到20.0秒,即50到200)
reg [9:0] initial_set_time_tenths = 10'd100; // 默认10.0秒 (100个0.1秒)
// 用于按键上升沿检测的寄存器
reg key_C_prev = 1'b0;
reg key_D_prev = 1'b0;
reg key_A_prev = 1'b0;
reg key_B_prev = 1'b0;
// 按键上升沿检测(用于时间调整和切换回合)
always @(posedge clk_50M or posedge clr) begin
if (clr) begin
key_C_prev <= 1'b0;
key_D_prev <= 1'b0;
key_A_prev <= 1'b0;
key_B_prev <= 1'b0;
end else begin
key_C_prev <= key_C_xd;
key_D_prev <= key_D_xd;
key_A_prev <= key_A_xd;
key_B_prev <= key_B_xd;
end
end
// 组合逻辑用于状态转换
always @(*) begin
next_state = current_state; // 默认为保持当前状态
if (clr) begin
next_state = STATE_IDLE; // 全局复位
end else begin
case(current_state)
STATE_IDLE: begin
if (Main_Switch) begin // K开关拨到上方,开始游戏
next_state = STATE_A_TURN; // A棋手开始
end
end
STATE_A_TURN: begin
if (!Main_Switch) next_state = STATE_IDLE; // K开关拨到下方,复位
else if (key_A_xd && !key_A_prev) next_state = STATE_B_TURN; // A棋手按下按键,切换到B
else if (carry_out_A) next_state = STATE_A_TIMEOUT; // A棋手时间用完
end
STATE_B_TURN: begin
if (!Main_Switch) next_state = STATE_IDLE; // K开关拨到下方,复位
else if (key_B_xd && !key_B_prev) next_state = STATE_A_TURN; // B棋手按下按键,切换到A
else if (carry_out_B) next_state = STATE_B_TIMEOUT; // B棋手时间用完
end
STATE_A_TIMEOUT: begin
if (!Main_Switch) next_state = STATE_IDLE; // K开关拨到下方,复位
end
STATE_B_TIMEOUT: begin
if (!Main_Switch) next_state = STATE_IDLE; // K开关拨到下方,复位
end
default: next_state = STATE_IDLE; // 不应发生
endcase
end
end
// 同步状态寄存器
always @(posedge clk_50M or posedge clr) begin
if (clr) begin
current_state <= STATE_IDLE;
end else begin
current_state <= next_state;
end
end
// --- 初始时间调整逻辑 (在IDLE状态下) ---
always @(posedge clk_50M or posedge clr) begin // 使用clk_50M捕获按键上升沿
if (clr) begin
initial_set_time_tenths <= 10'd100; // 复位到10.0秒
end else if (current_state == STATE_IDLE) begin
if (key_C_xd && !key_C_prev) begin // C键上升沿
if (initial_set_time_tenths + 20 <= 10'd200) // 最大20.0秒 (200个0.1秒)
initial_set_time_tenths <= initial_set_time_tenths + 20;
else
initial_set_time_tenths <= 10'd200; // 上限20.0秒
end else if (key_D_xd && !key_D_prev) begin // D键上升沿
if (initial_set_time_tenths - 10 >= 10'd50) // 最小5.0秒 (50个0.1秒)
initial_set_time_tenths <= initial_set_time_tenths - 10;
else
initial_set_time_tenths <= 10'd50; // 下限5.0秒
end
end
end
// --- A棋手时钟 ---
wire [9:0] counter_A_current_value; // 当前倒计时值 (以0.1秒为单位)
// 控制A棋手计数器的信号
reg reset_A_counter; // 复位A到初始设置时间
reg enable_A_counter; // 启用A倒计时
// 实例化A棋手计数器
counter u8_counter_A(
.clk(clk_10),
.rst(reset_A_counter), // 复位输入
.en(enable_A_counter), // 启用倒计时
.load_value(initial_set_time_tenths), // 复位时加载的值
.current_value(counter_A_current_value), // 输出当前值
.carry_out(carry_out_A) // 当计数器达到0时输出
);
// --- B棋手时钟 ---
wire [9:0] counter_B_current_value; // 当前倒计时值 (以0.1秒为单位)
// 控制B棋手计数器的信号
reg reset_B_counter; // 复位B到初始设置时间
reg enable_B_counter; // 启用B倒计时
// 实例化B棋手计数器
counter u9_counter_B(
.clk(clk_10),
.rst(reset_B_counter),
.en(enable_B_counter),
.load_value(initial_set_time_tenths),
.current_value(counter_B_current_value),
.carry_out(carry_out_B)
);
// --- 根据状态机控制计数器 ---
always @(*) begin
// 默认值
reset_A_counter = 1'b0;
enable_A_counter = 1'b0;
reset_B_counter = 1'b0;
enable_B_counter = 1'b0;
case(current_state)
STATE_IDLE: begin
reset_A_counter = 1'b1; // 两者都复位到初始设置时间
reset_B_counter = 1'b1;
// IDLE状态下不计数
end
STATE_A_TURN: begin
// A棋手回合,A计时。如果按A键,则A复位,停止计时;B计时。
enable_A_counter = 1'b1; // 默认A计时
reset_A_counter = 1'b0; // 默认不复位
if (key_A_xd && !key_A_prev) begin // 只有A棋手按下A键才有效
reset_A_counter = 1'b1; // A时间复位到初始值
enable_A_counter = 1'b0; // A时间停止计时
enable_B_counter = 1'b1; // B时间开始计时
reset_B_counter = 1'b0; // B时间不复位
end else begin
enable_B_counter = 1'b0; // 否则B停止计时
end
end
STATE_B_TURN: begin
// B棋手回合,B计时。如果按B键,则B复位,停止计时;A计时。
enable_B_counter = 1'b1; // 默认B计时
reset_B_counter = 1'b0; // 默认不复位
if (key_B_xd && !key_B_prev) begin // 只有B棋手按下B键才有效
reset_B_counter = 1'b1; // B时间复位到初始值
enable_B_counter = 1'b0; // B时间停止计时
enable_A_counter = 1'b1; // A时间开始计时
reset_A_counter = 1'b0; // A时间不复位
end else begin
enable_A_counter = 1'b0; // 否则A停止计时
end
end
STATE_A_TIMEOUT: begin
// 两个计数器都停止在0.0或上次的值,不计时也不复位
end
STATE_B_TIMEOUT: begin
// 两个计数器都停止在0.0或上次的值,不计时也不复位
end
endcase
end
// --- 显示逻辑 ---
// disp_data_right5 to disp_data_right0 对应dig[5] to dig[0]
// dig[5] dig[4] dig[3] dig[2] dig[1] dig[0]
// 左侧十位 左侧个位 左侧十分位 右侧十位 右侧个位 右侧十分位
reg [3:0] disp_data_tens_L, disp_data_ones_L, disp_data_tenths_L; // 左侧显示
reg [3:0] disp_data_tens_R, disp_data_ones_R, disp_data_tenths_R; // 右侧显示
reg display_game_over_message = 1'b0; // 标志位,告诉动态显示模块显示字符"A B L U"
// 将总的0.1秒倒计时值转换为BCD数字以便显示
function automatic [11:0] to_bcd_digits (input [9:0] value);//需递归调用,选择automatic型
reg [3:0] tens, ones, tenths;
begin
tenths = value % 10;
ones = (value / 10) % 10;
tens = value / 100;
to_bcd_digits = {tens, ones, tenths}; // 打包的3位BCD
end
endfunction
wire [11:0] bcd_A_current, bcd_B_current;
wire [11:0] bcd_initial_set_time;
assign bcd_A_current = to_bcd_digits(counter_A_current_value);//A的十进制计时时间转换为12位二进制数
assign bcd_B_current = to_bcd_digits(counter_B_current_value);//B的十进制计时时间转换为12位二进制数
assign bcd_initial_set_time = to_bcd_digits(initial_set_time_tenths);//十进制计时总时间转换为12位二进制数
always @(*) begin
display_game_over_message = 1'b0; // 默认不显示字母
case(current_state)
STATE_IDLE: begin
// 两个时钟都显示 initial_set_time
disp_data_tenths_R = bcd_initial_set_time[3:0]; // 右侧0.1秒位
disp_data_ones_R = bcd_initial_set_time[7:4]; // 右侧个位
disp_data_tens_R = bcd_initial_set_time[11:8]; // 右侧十位
disp_data_tenths_L = bcd_initial_set_time[3:0]; // 左侧0.1秒位
disp_data_ones_L = bcd_initial_set_time[7:4]; // 左侧个位
disp_data_tens_L = bcd_initial_set_time[11:8]; // 左侧十位
end
STATE_A_TURN: begin
// 左侧显示A时钟 (当前值),右侧显示B时钟 (初始值)
disp_data_tenths_L = bcd_A_current[3:0];
disp_data_ones_L = bcd_A_current[7:4];
disp_data_tens_L = bcd_A_current[11:8];
disp_data_tenths_R = bcd_initial_set_time[3:0];
disp_data_ones_R = bcd_initial_set_time[7:4];
disp_data_tens_R = bcd_initial_set_time[11:8];
end
STATE_B_TURN: begin
// 右侧显示B时钟 (当前值),左侧显示A时钟 (初始值)
disp_data_tenths_R = bcd_B_current[3:0];
disp_data_ones_R = bcd_B_current[7:4];
disp_data_tens_R = bcd_B_current[11:8];
disp_data_tenths_L = bcd_initial_set_time[3:0];
disp_data_ones_L = bcd_initial_set_time[7:4];
disp_data_tens_L = bcd_initial_set_time[11:8];
end
STATE_A_TIMEOUT: begin
// A超时,显示 A L , B U
display_game_over_message = 1'b1;
disp_data_tenths_L = 4'hd;
disp_data_ones_L = 4'ha;
disp_data_tens_L = 4'h0;
disp_data_tenths_R = 4'hc;
disp_data_ones_R = 4'hb;
disp_data_tens_R = 4'h0;
end
STATE_B_TIMEOUT: begin
// B超时,显示 A U , B L
display_game_over_message = 1'b1;
disp_data_tenths_R = 4'hd;
disp_data_ones_R = 4'hb;
disp_data_tens_R = 4'h0;
disp_data_tenths_L = 4'hc;
disp_data_ones_L = 4'ha;
disp_data_tens_L = 4'h0;
end
default: begin // 安全默认值
disp_data_tenths_R = 4'd0; disp_data_ones_R = 4'd0; disp_data_tens_R = 4'd0;
disp_data_tenths_L = 4'd0; disp_data_ones_L = 4'd0; disp_data_tens_L = 4'd0;
end
endcase
end
// 实例化动态7段数码管驱动器
dynamic u10_display(
.disp_data_right0(disp_data_tenths_R), // 最右边,0.1秒位
.disp_data_right1(disp_data_ones_R), // 个位
.disp_data_right2(disp_data_tens_R), // 十位
.disp_data_left0(disp_data_tenths_L), // 左边组的0.1秒位
.disp_data_left1(disp_data_ones_L), // 左边组的个位
.disp_data_left2(disp_data_tens_L), // 左边组的十位
.clk(clk_1k),
.game_over_mode(display_game_over_message), // 新增标志,用于特殊显示
.seg(seg),
.dig(dig)
);
// --- LED控制逻辑 ---
wire LED_EN_A; // 启用A棋手侧的LED
wire LED_EN_B; // 启用B棋手侧的LED
// 当计时器在1.0秒和5.0秒之间时 (即10到50个0.1秒) LED亮起,在0.0时不亮
assign LED_EN_A = (current_state == STATE_A_TURN && counter_A_current_value <= 10'd50 && counter_A_current_value > 10'd0) ? 1'b1 : 1'b0;
assign LED_EN_B = (current_state == STATE_B_TURN && counter_B_current_value <= 10'd50 && counter_B_current_value > 10'd0) ? 1'b1 : 1'b0;
// 实例化LED控制模块
LED u11_led(
.EN_A(LED_EN_A),
.EN_B(LED_EN_B),
.counter_A(counter_A_current_value), // 动画方向
.counter_B(counter_B_current_value),
.led_o(LED_O)
);
// --- 蜂鸣器控制逻辑 ---
// 当A或B超时时,蜂鸣器响2秒
wire trigger_buzzer;
reg buzzer_latch = 1'b0; // 蜂鸣器单次触发的锁存器
always @(posedge clk_10 or posedge clr) begin
if (clr) begin
buzzer_latch <= 1'b0;
end else begin
// 只有当进入超时状态时才置位,并在离开超时状态时清除
if (( current_state == STATE_A_TIMEOUT) ||
( current_state == STATE_B_TIMEOUT))
buzzer_latch <= 1'b1; // 从非超时状态进入超时状态时拉高
else
buzzer_latch <= 1'b0;
end
end
// 使用 buzzer_latch 作为蜂鸣器模块的使能
assign trigger_buzzer = buzzer_latch;
// 实例化蜂鸣器模块
buzzer u12_buzzer(
.clk(clk_50M),
.reset(current_state==STATE_IDLE),
.buzzer_trigger(trigger_buzzer), // 在进入超时状态时触发
.buz(Buzzer)
);
endmodule保证原有结构与功能不变的情况下优化这个代码,删除其中冗余的代码注释,仅仅保留最精简的代码注释