MOD10计数器异常:计数至9后复位至4的原因及解决方案
MOD10计数器复位到4而非0的问题分析与修复
问题原因分析
- 异步复位的时序冲突:原代码采用异步复位(TFF的
always @(posedge clr or negedge clk)),当计数器从9(1001)跳转到10(1010)时,复位信号w立刻拉高,将所有TFF清零为0000。但此时q1刚从0翻转为1,又被复位拉回0,这个q1的下降沿会触发tff3的时钟(tff3的时钟是q1,沿触发为negedge),导致tff3的输出q2翻转,从0变为1,最终计数器状态变成0100(4)。 - 复位检测逻辑错误:原代码检测的是10(二进制1010,
q[3]&q[1]),而MOD10计数器应在计数到9后直接复位到0,不需要进入10这个状态。进入10状态再复位会引入额外的信号翻转,触发后续TFF的误动作。 - 异步计数器的固有风险:采用前级TFF输出作为后级时钟的异步计数器,在复位时容易因信号变化的时序问题产生非预期翻转。
修复后的代码
方案1:同步复位+正确状态检测(推荐)
将TFF改为同步复位,同时调整复位检测逻辑为检测9(1001),在时钟沿统一处理复位和计数:
module MOD10 (clk, clr, q); input clk, clr; output reg [3:0] q; // 检测计数到9(1001),同步复位条件 wire reset_condition = (q == 4'b1001); always @(posedge clk or posedge clr) begin if (clr) begin q <= 4'b0000; end else if (reset_condition) begin q <= 4'b0000; end else begin q <= q + 1'b1; end end endmodule module MOD10_TB(); reg clk, clr; wire [3:0] q; MOD10 uut (clk, clr, q); // 时钟生成(50% duty cycle) initial begin clk = 0; forever #5 clk = ~clk; // Toggle clock every 5 time units end // Reset logic and test sequence initial begin clr = 1; // Reset active #10 clr = 0; // Deactivate reset after 10 time units #110 $finish; // End simulation after 110 time units end endmodule
方案2:修复原异步TFF架构的问题
如果坚持使用TFF搭建异步计数器,需要调整复位检测逻辑,并修改TFF的复位触发方式,避免复位后的误翻转:
module MOD10 (clk, clr, q); input clk, clr; output [3:0] q; wire w; // 检测计数到9(1001),提前触发复位,避免进入10状态 assign w = clr | (q[3] & q[0]); TFF tff1(clk, w, 1'b1, q[0]); TFF tff2(q[0], w, 1'b1, q[1]); TFF tff3(q[1], w, ~(q[3] & q[0]), q[2]); // 当计数到9时,禁止tff3翻转 TFF tff4(q[2], w, (q[1] & q[0]), q[3]); // 仅当q1和q0都为1时,tff4才翻转 endmodule module TFF (clk, clr, t, q); input clk, clr, t; output reg q; // 改为同步复位,避免异步复位的时序冲突 always @(negedge clk) begin if (clr) q <= 0; else begin if (t) q <= ~q; else q <= q; end end endmodule module MOD10_TB(); reg clk, clr; wire [3:0] q; MOD10 uut (clk, clr, q); // 时钟生成(50% duty cycle) initial begin clk = 0; forever #5 clk = ~clk; // Toggle clock every 5 time units end // Reset logic and test sequence initial begin clr = 1; // Reset active #10 clr = 0; // Deactivate reset after 10 time units #110 $finish; // End simulation after 110 time units end endmodule
修复代码解释
方案1解释
- 同步复位:所有操作都在时钟上升沿完成,避免异步复位带来的时序冲突,保证复位和计数的动作同步执行。
- 正确状态检测:直接检测计数器到达9(1001),在下一个时钟沿直接复位到0,跳过10这个状态,从根源上消除额外翻转的可能。
- 简化架构:用组合逻辑+时序逻辑直接实现计数,比TFF级联更简洁,更易维护。
方案2解释
- 调整复位检测条件:改为检测9(
q[3]&q[0]),在到达9时就触发复位,避免进入10状态。 - 同步复位:将TFF的复位改为同步(仅在时钟沿处理复位),避免复位信号变化触发的误翻转。
- TFF使能控制:通过
T端控制后级TFF的翻转,当计数到9时,禁止tff3翻转,确保计数器直接从9回到0,不会产生中间状态。
内容的提问来源于stack exchange,提问作者Hazar H
相关产品推荐
相关产品推荐

