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

8位可重载递减计数器设计问题求助

8位递减计数器问题排查与修复

问题描述

设计目标是实现一款8位递减计数器,接收初始值后开始递减,计数值到8'b0000_0000时自动重载初始值。但实际运行时出现以下问题:

  • 当初始输入为8'b11111111时工作正常,输入如8'b10010011时,仅LSB的高几位(如011)递减,遇到0后高位变为X。
  • ld信号功能异常:ld=0时未重置为初始值,反而停止计数。

问题根源分析

  • 异步计数器触发缺陷:当前计数器采用异步级联结构,每一级触发器的时钟是上一级的输出q。当初始值中存在0位时,高位触发器的时钟始终为0,没有上升沿触发,导致高位输出保持未知状态(X)。比如输入8'b10010011时,q[2]初始为0,m_dff3的时钟无跳变,q[3]及更高位无法更新,最终呈现X。
  • ld信号逻辑混淆:原触发器逻辑是ld=1时加载初始值d2,ld=0时加载d1实现翻转,但测试代码中手动控制ld的逻辑与预期相反,且缺少自动检测计数值为0并触发重载的逻辑,完全依赖手动输入ld信号,导致功能异常。
  • 递减逻辑错误:每级触发器的d1接q_bar,这种方式仅在全1初始值时能实现递减,初始值有0位时,高位无法触发翻转,不符合递减计数器逻辑。

修正后的代码实现

方案:同步递减计数器(自动重载)

改用同步时钟设计,所有触发器共享同一时钟,同时添加自动检测计数值为0的逻辑,触发重载初始值。

1. 同步递减计数器模块

module down_counter(
    input [7:0] init_val,  // 初始输入值
    input clk,
    input rst_n,           // 复位信号(低有效)
    output reg [7:0] q
);

always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        q <= init_val;  // 复位时加载初始值
    end else begin
        if(q == 8'b0000_0000) begin
            q <= init_val;  // 计数值为0时重载初始值
        end else begin
            q <= q - 1'b1;  // 正常递减
        end
    end
end

endmodule

2. 测试平台代码

module down_counter_tb;

reg [7:0] init_val;
reg clk;
reg rst_n;

wire [7:0] q;

down_counter uut (
    .init_val(init_val),
    .clk(clk),
    .rst_n(rst_n),
    .q(q)
);

// 生成时钟
always #5 clk = ~clk;

initial begin
    // 初始化信号
    clk = 1'b1;
    rst_n = 1'b0;
    init_val = 8'b10010011;
    
    #10 rst_n = 1'b1;  // 释放复位
    
    // 运行足够时间观察计数循环
    #500 $finish;
end

// 打印输出
initial begin
    $monitor("Time: %0t, q = %b", $time, q);
end

endmodule

原设计局部修正(若坚持触发器级联)

如果必须基于原有modified_d_flip_flop实现,需要:

  • 所有触发器使用同一主时钟clk。
  • 设计同步递减逻辑,每一位的翻转条件是所有低位都为0。
  • 添加自动生成ld信号的逻辑:当q==8'b0时,ld=1,否则ld=0。

修正后的down_counter模块示例:

module down_counter(
    input [7:0] d,
    input clk,
    output [7:0] q,
    output [7:0] q_bar
);

wire ld;
assign ld = (q == 8'b00000000);  // 自动检测计数值为0,触发重载

// 第0位:每次时钟沿翻转(递减时最低位每周期变)
modified_d_flip_flop m_dff1 (
    .q(q[0]), .q_bar(q_bar[0]),
    .d1(q_bar[0]), .d2(d[0]),
    .clk(clk), .ld(ld)
);

// 第1位:仅当第0位为0时翻转(递减进位逻辑)
modified_d_flip_flop m_dff2 (
    .q(q[1]), .q_bar(q_bar[1]),
    .d1(q[1] ^ q_bar[0]), .d2(d[1]),
    .clk(clk), .ld(ld)
);

// 第2位:仅当第0、1位都为0时翻转
modified_d_flip_flop m_dff3 (
    .q(q[2]), .q_bar(q_bar[2]),
    .d1(q[2] ^ (q_bar[0] & q_bar[1])), .d2(d[2]),
    .clk(clk), .ld(ld)
);

// 其余位逻辑以此类推,直到第7位
modified_d_flip_flop m_dff4 (.q(q[3]), .q_bar(q_bar[3]), .d1(q[3] ^ (q_bar[0]&q_bar[1]&q_bar[2])), .d2(d[3]), .clk(clk), .ld(ld));
modified_d_flip_flop m_dff5 (.q(q[4]), .q_bar(q_bar[4]), .d1(q[4] ^ (q_bar[0]&q_bar[1]&q_bar[2]&q_bar[3])), .d2(d[4]), .clk(clk), .ld(ld));
modified_d_flip_flop m_dff6 (.q(q[5]), .q_bar(q_bar[5]), .d1(q[5] ^ (q_bar[0]&q_bar[1]&q_bar[2]&q_bar[3]&q_bar[4])), .d2(d[5]), .clk(clk), .ld(ld));
modified_d_flip_flop m_dff7 (.q(q[6]), .q_bar(q_bar[6]), .d1(q[6] ^ (q_bar[0]&q_bar[1]&q_bar[2]&q_bar[3]&q_bar[4]&q_bar[5])), .d2(d[6]), .clk(clk), .ld(ld));
modified_d_flip_flop m_dff8 (.q(q[7]), .q_bar(q_bar[7]), .d1(q[7] ^ (q_bar[0]&q_bar[1]&q_bar[2]&q_bar[3]&q_bar[4]&q_bar[5]&q_bar[6])), .d2(d[7]), .clk(clk), .ld(ld));

endmodule

总结

同步计数器设计更稳定,逻辑清晰,避免了异步级联带来的触发问题,同时自动重载逻辑无需手动控制ld信号,更符合设计需求。

内容的提问来源于stack exchange,提问作者Sunil.B

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 10:15:34