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
相关产品推荐
相关产品推荐

