使用JK触发器的Mod-6计数器输出始终未知,求代码错误排查
问题描述
尝试改造Mod-8计数器实现Mod-6计数器,但仿真波形不符合预期。以下是设计代码和测试平台代码:
原设计代码
module mod_six_counter(clk,rst,q,qbar); input clk; input wire rst; output wire [2:0]q; output [2:0]qbar; assign rst = ~((~q[0])&q[1]&(q[2])); jkff ff1(1'b1,1'b1,clk,rst,q[0],qbar[0]); jkff ff2(1'b1,1'b1,q[0],rst,q[1],qbar[1]); jkff ff3(1'b1,1'b1,q[1],rst,q[2],qbar[2]); endmodule module jkff(j,k,clk,rst,q,qbar); input j,k,clk,rst; output reg q; output qbar; always@(posedge clk or negedge rst) begin if (!rst) q <= 1'b0; 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 assign qbar = ~q; endmodule
原测试平台代码
module tbmod_sixcounter; reg clk,rst; wire[2:0] q,qbar; mod_six_counter DUT(.clk(clk),.rst(rst),.q(q),.qbar(qbar)); always #10 clk=~clk; initial begin clk<=0; rst<=0; #7 rst<=1; end endmodule
错误分析
- 复位端口双重驱动:
mod_six_counter模块中,rst被定义为输入端口,同时又通过assign语句内部赋值,这会导致信号冲突,属于Verilog语法错误,直接引发仿真或综合异常。 - 复位逻辑混淆:原代码试图复用输入复位端口实现计数清零,未区分外部全局复位和内部计数清零逻辑,导致外部复位信号被覆盖,无法正常发挥作用。
- 毛刺风险:直接用组合逻辑生成复位信号,若计数信号存在毛刺,可能误触发清零,导致计数异常。
修正方案
- 拆分复位信号:将输入的外部全局复位与内部计数清零逻辑分离,避免端口驱动冲突。
- 实现正确的Mod-6计数逻辑:Mod-6计数器需覆盖0~5共6个状态,当计数到6(
3'b110)时,异步清零回到0。 - 保留外部复位功能:确保外部复位可以强制将计数器置0。
修正后的设计代码
module mod_six_counter(clk, ext_rst_n, q, qbar); input clk; input ext_rst_n; // 外部低有效复位 output wire [2:0] q; output [2:0] qbar; // 内部复位信号:外部复位有效 或 计数到6(3'b110)时,触发清零(低有效) wire internal_rst_n = ext_rst_n & ~((~q[0]) & q[1] & q[2]); // JK触发器连接,使用内部复位信号 jkff ff1(1'b1, 1'b1, clk, internal_rst_n, q[0], qbar[0]); jkff ff2(1'b1, 1'b1, q[0], internal_rst_n, q[1], qbar[1]); jkff ff3(1'b1, 1'b1, q[1], internal_rst_n, q[2], qbar[2]); endmodule module jkff(j, k, clk, rst_n, q, qbar); input j, k, clk, rst_n; output reg q; output qbar; always @(posedge clk or negedge rst_n) begin if (!rst_n) 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 assign qbar = ~q; endmodule
修正后的测试平台代码
module tbmod_sixcounter; reg clk, ext_rst_n; wire[2:0] q, qbar; mod_six_counter DUT(.clk(clk), .ext_rst_n(ext_rst_n), .q(q), .qbar(qbar)); // 生成10ns周期时钟 always #10 clk = ~clk; initial begin clk <= 0; ext_rst_n <= 0; // 初始复位 #7 ext_rst_n <= 1; // 释放复位,开始计数 // 仿真足够长时间,观察计数循环 #200 $finish; end endmodule
说明
修正后的代码将外部复位命名为ext_rst_n(低有效),内部生成internal_rst_n结合外部复位和计数到6时的清零逻辑,确保计数器在0~5之间稳定循环。测试平台增加了$finish语句避免仿真无限运行,同时保留初始复位逻辑验证计数器启动行为。
内容的提问来源于stack exchange,提问作者np2810
相关产品推荐
相关产品推荐

