Modelsim仿真Quartus生成的JK计数器输出始终未定义求助
计数器仿真输出始终未定义的问题解决
我在Quartus中以原理图形式创建了一个计数器,随后从该原理图生成了Verilog设计文件。能够在Modelsim中配置并运行仿真,但计数器的输出(Q0..Q3)始终处于未定义状态。我是Verilog和FPGA的新手,不过按照原理图逻辑,至少Q0应该在每个时钟周期变化才对。

生成的Verilog设计代码
module jk_counter_full( clk, JKFF0, Q0, Q1, Q2, Q3, next ); input wire clk; input wire JKFF0; output wire Q0; output wire Q1; output wire Q2; output wire Q3; output wire next; reg in1; wire in2; wire in3; wire SYNTHESIZED_WIRE_8; reg JKFF_inst2; reg JKFF_inst4; reg JKFF_inst6; assign Q1 = JKFF_inst2; assign Q2 = JKFF_inst4; assign Q3 = JKFF_inst6; assign SYNTHESIZED_WIRE_8 = 1; always@(posedge clk) begin in1 <= ~in1 & JKFF0 | in1 & ~JKFF0; end assign in2 = in1 & JKFF_inst2; always@(posedge clk) begin JKFF_inst2 <= ~JKFF_inst2 & in1 | JKFF_inst2 & ~in1; end always@(posedge clk) begin JKFF_inst4 <= ~JKFF_inst4 & in2 | JKFF_inst4 & ~in2; end assign in3 = in2 & JKFF_inst4; always@(posedge clk) begin JKFF_inst6 <= ~JKFF_inst6 & in3 | JKFF_inst6 & ~in3; end assign next = in3 & JKFF_inst6; assign Q0 = in1; endmodule
测试文件代码
timescale 1 ps/ 1 ps module jk_counter_full_vlg_tst(); reg JKFF0; reg clk; wire Q0; wire Q1; wire Q2; wire Q3; wire next; jk_counter_full i1 ( .JKFF0(JKFF0), .Q0(Q0), .Q1(Q1), .Q2(Q2), .Q3(Q3), .clk(clk), .next(next) ); initial begin clk = 0; JKFF0 = 1; end always #1000 clk = ! clk; endmodule
问题分析与解决
核心问题
设计中的所有寄存器(in1、JKFF_inst2、JKFF_inst4、JKFF_inst6)都没有设置初始值。在Verilog仿真中,未初始化的寄存器默认值为x(未定义状态),所有基于这些寄存器的运算结果也会是x,最终导致输出始终未定义。
修复方案
方案1:在设计模块中直接初始化寄存器
给每个寄存器添加初始赋值,硬件实现时FPGA会自动处理复位,仿真时则会从初始值开始运行:
module jk_counter_full( clk, JKFF0, Q0, Q1, Q2, Q3, next ); input wire clk; input wire JKFF0; output wire Q0; output wire Q1; output wire Q2; output wire Q3; output wire next; reg in1 = 1'b0; // 初始化in1为0 wire in2; wire in3; wire SYNTHESIZED_WIRE_8; reg JKFF_inst2 = 1'b0; // 初始化JKFF_inst2为0 reg JKFF_inst4 = 1'b0; // 初始化JKFF_inst4为0 reg JKFF_inst6 = 1'b0; // 初始化JKFF_inst6为0 // 其余代码保持不变...
方案2:在测试文件中初始化寄存器(不修改设计代码)
通过测试文件直接对设计内部的寄存器赋值,适合不想改动原设计的场景:
timescale 1 ps/ 1 ps module jk_counter_full_vlg_tst(); reg JKFF0; reg clk; wire Q0; wire Q1; wire Q2; wire Q3; wire next; jk_counter_full i1 ( .JKFF0(JKFF0), .Q0(Q0), .Q1(Q1), .Q2(Q2), .Q3(Q3), .clk(clk), .next(next) ); initial begin clk = 0; JKFF0 = 1; // 初始化设计内部的寄存器 i1.in1 = 1'b0; i1.JKFF_inst2 = 1'b0; i1.JKFF_inst4 = 1'b0; i1.JKFF_inst6 = 1'b0; end always #1000 clk = ! clk; endmodule
可选优化:简化触发器逻辑
原代码中JK触发器的逻辑可以简化,比如第一个触发器的代码可以替换为更直观的异或操作,效果完全一致:
always@(posedge clk) begin in1 <= in1 ^ JKFF0; // 等价于原逻辑,更简洁 end
验证效果
修改后重新运行仿真,Q0会在每个时钟上升沿翻转,Q1会在Q0为1时翻转,以此类推,计数器就能正常工作了。
内容的提问来源于stack exchange,提问作者bibo
相关产品推荐
相关产品推荐

