HDLBits 12小时时钟代码pm输出较标准答案少1小时,求排查
调试HDLBits 12小时时钟模块的问题
我在做HDLBits的12小时时钟题目时编写了代码,但平台仅提示存在测试用例不匹配,无法定位具体错误点,希望有人帮忙排查一下问题。
测试情况
平台返回的结果显示存在多处不匹配,但未给出具体错误场景,仅能确定代码逻辑存在问题。
我的代码
module top_module( input clk, input reset, input ena, output pm, output [7:0] hh, output [7:0] mm, output [7:0] ss); wire [1:0] ssc, mmc, hhc; assign ssc[0] = ss[3]&ss[0]; counter4buenld cssl(clk, ena, reset, ssc[0], 4'h0, ss[3:0]); assign ssc[1] = ss[4]&ss[6]&ssc[0]; counter4buenld cssh(clk, ena&ssc[0], reset, ssc[1], 4'h0, ss[7:4]); assign mmc[0] = mm[3]&mm[0]&ssc[1]; counter4buenld cmml(clk, ena&ssc[1], reset, mmc[0], 4'h0, mm[3:0]); assign mmc[1] = mm[4]&mm[6]&mmc[0]; counter4buenld cmmh(clk, ena&mmc[0], reset, mmc[1], 4'h0, mm[7:4]); assign hhc[0] = hh[3]&hh[0]&mmc[1]; assign hhc[1] = hh[4]&hh[1]&mmc[1]; counter4buenld chhl(clk, ena&mmc[1], 1'b0, reset|hhc[0]|hhc[1], {2'b00, reset, ~reset}, hh[3:0]); counter4buenld chhh(clk, ena&hhc[0], 1'b0, reset|hhc[1], {3'b000, reset}, hh[7:4]); reg pml; assign pm = pml; always@(posedge clk) begin if(reset) begin pml <= 1'b0; end else begin if(hh[4]&hh[0]&mmc[1]) begin pml <= ~pml; end else begin pml <= pml; end end end endmodule module counter4buenld( input clk, input ena, input reset, input load, input [3:0] d, output reg [3:0] q ); always@(posedge clk) begin if(reset) q <= 4'h0; else if(load) q <= d; else q <= q + ena; end endmodule
问题排查与修改建议
我梳理了代码逻辑,发现几个核心问题,下面给出具体分析和修改方案:
1. 小时计数器的复位与循环逻辑错误
12小时制时钟复位后应回到12:00:00 AM,但你的代码复位时小时会被置为00,不符合需求。同时,小时从12跳转时应该回到1,而不是0,原代码的加载值和进位条件逻辑混乱,导致计数循环错误。
2. PM信号切换条件不准确
原代码的PM切换条件是hh[4]&hh[0]&mmc[1],这个判断逻辑模糊,无法精准对应11:59:59到12:00:00的切换时刻(这才是AM/PM状态切换的正确节点)。
3. 信号可读性与逻辑严谨性不足
原代码用位运算判断计数器满值,容易出错,改成直接比较BCD码值会更清晰可靠。
修改后的完整代码
module top_module( input clk, input reset, input ena, output pm, output [7:0] hh, output [7:0] mm, output [7:0] ss); wire [1:0] ssc, mmc; // 秒计数器逻辑 assign ssc[0] = (ss[3:0] == 4'h9); // 秒低位到9,触发复位 counter4buenld cssl( .clk(clk), .ena(ena), .reset(reset), .load(ssc[0]), .d(4'h0), .q(ss[3:0]) ); assign ssc[1] = (ss[7:4] == 4'h5) && ssc[0]; // 秒到59,触发分钟进位 counter4buenld cssh( .clk(clk), .ena(ena & ssc[0]), .reset(reset), .load(ssc[1]), .d(4'h0), .q(ss[7:4]) ); // 分钟计数器逻辑 assign mmc[0] = (mm[3:0] == 4'h9) && ssc[1]; // 分低位到9且秒满59,触发复位 counter4buenld cmml( .clk(clk), .ena(ena & ssc[1]), .reset(reset), .load(mmc[0]), .d(4'h0), .q(mm[3:0]) ); assign mmc[1] = (mm[7:4] == 4'h5) && mmc[0]; // 分到59,触发小时进位 counter4buenld cmmh( .clk(clk), .ena(ena & mmc[0]), .reset(reset), .load(mmc[1]), .d(4'h0), .q(mm[7:4]) ); // 小时计数器逻辑 wire hour_inc = ena & mmc[1]; wire hour_wrap = (hh[7:4] == 4'h1) && (hh[3:0] == 4'h2) && hour_inc; // 小时到12,循环回1 wire hh_low_carry = (hh[3:0] == 4'h9) && hour_inc; // 小时低位到9,十位加1 counter4buenld chhl( .clk(clk), .ena(hour_inc), .reset(reset), .load(reset || hour_wrap), .d(reset ? 4'h2 : 4'h1), .q(hh[3:0]) ); counter4buenld chhh( .clk(clk), .ena(hh_low_carry), .reset(reset), .load(reset || hour_wrap), .d(reset ? 4'h1 : 4'h0), .q(hh[7:4]) ); // PM信号逻辑 reg pml; assign pm = pml; always@(posedge clk) begin if(reset) begin pml <= 1'b0; // 复位初始为AM end else if(hour_inc && (hh[7:4] == 4'h1) && (hh[3:0] == 4'h1)) begin // 小时从11跳转到12时,切换AM/PM状态 pml <= ~pml; end else begin pml <= pml; end end endmodule module counter4buenld( input clk, input ena, input reset, input load, input [3:0] d, output reg [3:0] q ); always@(posedge clk) begin if(reset) q <= 4'h0; else if(load) q <= d; else q <= q + ena; end endmodule
修改点说明
- 小时逻辑修正:复位时直接加载
12的BCD码(十位1,个位2),当小时到12时自动循环到1,符合12小时制的计数规则。 - PM信号修正:仅在小时从
11跳转到12时切换状态,精准对应AM/PM的切换节点。 - 可读性优化:把位运算判断改成直接比较BCD码值,逻辑更直观,降低出错概率。
你可以把修改后的代码放到HDLBits上测试,应该能解决大部分不匹配问题。如果还有异常,可以进一步检查时钟信号同步性或复位状态的细节。
内容的提问来源于stack exchange,提问作者Lyxikun
相关产品推荐
相关产品推荐

