You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于JK触发器的BCD计数器复位异常问题求助

BCD计数器复位异常问题:复位至4而非0的排查与修复

问题描述

使用SystemVerilog将JK触发器配置为T型触发器(J=K=1)实现BCD计数器,目标是从0计数到9后复位至0。计划通过JK触发器的clr输入,在计数值达到4'b1010时复位触发器,但实际运行时,计数值到4'b1010后,计数器复位到4'b0100(即4)而非0。排查后怀疑第三个触发器的always_ff块中存在条件同时触发的情况。

代码实现

顶层设计模块(bcdCounter)

module bcdCounter(
    input logic clk,
    input logic rst,
    output logic Q0,
    output logic Q1,
    output logic Q2,
    output logic Q3,
    output [3:0] out
    );
    
    assign out = {Q3,Q2,Q1,Q0};
    
    logic clr;
    assign clr = ~(Q3 & Q1);
    // $monitor("the value of clr is %0d and Q3 is %d and Q1 is %d", clr,Q3,Q1);
    jkFlipFlop flipFlop1(.J(1'b1), .K(1'b1), .rst(rst), .clk(clk), .clr(clr), .Q(Q0));
    jkFlipFlop flipFlop2(.J(1'b1), .K(1'b1), .rst(rst), .clk(Q0), .clr(clr), .Q(Q1));
    jkFlipFlop flipFlop3(.J(1'b1), .K(1'b1), .rst(rst), .clk(Q1), .clr(clr), .Q(Q2));
    jkFlipFlop flipFlop4(.J(1'b1), .K(1'b1), .rst(rst), .clk(Q2), .clr(clr), .Q(Q3));
    
endmodule

JK触发器模块(jkFlipFlop)

module jkFlipFlop(
    input logic J,
    input logic K,
    input logic rst,
    input logic clk,
    input logic clr,
    output logic Q
    );
    
    always_ff @(negedge clk, negedge clr ,posedge rst) begin
        if (rst) begin
            Q <= 1'b0;
        end
        else if(clr == 1'b0) begin
            Q <= 1'b0;
        end
        else if(clr != 1'b0 )begin   
            case ({J,K})
                2'b00: Q <= Q;
                2'b01: Q <= 1'b0;
                2'b10: Q <= 1'b1;
                2'b11: Q <= ~Q; 
             endcase
        end
    end    
endmodule

测试平台模块(bcdTB)

module bcdTB();
    logic clk,rst,Q0,Q1,Q2,Q3;
    logic [3:0] out;
    bcdCounter bcdCount(.clk(clk), .rst(rst), .Q0(Q0), .Q1(Q1), .Q2(Q2), .Q3(Q3),.out(out));
    always #40 clk = ~clk;
    
    initial begin
        clk = 1'b0;
        rst = 1'b0;
        #2 rst = 1'b1;
        #2 rst = 1'b0;
       
        #1000
        $finish;
    end
endmodule

仿真波形

仿真波形图

问题原因

  1. 异步清零与时钟事件的竞争:触发器的always_ff敏感列表同时包含negedge clk和negedge clr,当计数到9(4'b1001)时,下一个系统时钟沿触发Q0翻转,进而触发Q1翻转,此时Q3 & Q1为1,clr从1变为0(negedge clr)。这个异步清零事件与部分触发器的时钟事件(如Q1的跳变)几乎同时发生,导致触发器的行为出现竞争,部分触发器未正确执行清零操作(如第三个触发器Q2未被清零)。
  2. 清零逻辑的覆盖范围问题:当前clr = ~(Q3 & Q1)会在所有Q3和Q1同时为1的状态(如4'b1010、4'b1011等)触发清零,但异步清零的时序不确定性导致部分触发器未响应。

解决方案

方案1:改用同步清零(推荐)

将异步清零改为同步清零,即移除clr从敏感列表,仅在时钟沿判断清零条件,避免异步事件竞争。修改后的JK触发器代码如下:

module jkFlipFlop(
    input logic J,
    input logic K,
    input logic rst,
    input logic clk,
    input logic clr,
    output logic Q
    );
    
    always_ff @(negedge clk, posedge rst) begin
        if (rst) begin
            Q <= 1'b0;
        end
        else if(clr == 1'b0) begin
            Q <= 1'b0;
        end
        else begin   
            case ({J,K})
                2'b00: Q <= Q;
                2'b01: Q <= 1'b0;
                2'b10: Q <= 1'b1;
                2'b11: Q <= ~Q; 
             endcase
        end
    end    
endmodule

同时调整顶层的清零逻辑,确保仅在计数值达到4'b1010时触发同步清零:

// 替换原clr赋值
assign clr = ~(out == 4'b1010);

方案2:优化异步清零的时序逻辑

如果坚持使用异步清零,需确保清零信号的变化不会与触发器的时钟沿竞争。可以通过调整清零条件,在计数值达到9时提前生成清零信号,避免4'b1010状态的出现:

// 顶层模块中替换clr赋值
assign clr = ~(out == 4'b1001);

这样在计数到9时就触发异步清零,跳过4'b1010状态,避免竞争问题。

内容的提问来源于stack exchange,提问作者Asurii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 00:59:49