如何为实例化子模块的Verilog模块编写testbench并观测内部子模块波形
问题解答
核心问题答复
首先明确:完全可以为实例化了子模块的Verilog模块编写testbench,也可以直接查看内部子模块的信号波形,不需要额外修改设计代码。
主流仿真器(Modelsim、VCS、Xcelium等)都支持层次化信号引用,格式为[testbench中dut实例名].[子模块实例名].[内部信号名],你要查看的4个bcd_counter的输出可以直接用以下路径引用:
- 百分位计数器输出:
dut.bcd_counter_hundredths.bcd - 十分位计数器输出:
dut.bcd_counter_tenths.bcd - 秒个位计数器输出:
dut.bcd_counter_ones.bcd - 秒十位计数器输出:
dut.bcd_counter_tens.bcd
仿真时直接将上述路径的信号添加到波形窗口即可查看,也可以在testbench中定义对应wire变量绑定这些内部信号,直接在testbench中操作或打印。
现有代码错误修复
首先修复设计代码的隐含错误
你提供的设计代码本身存在几处语法/逻辑问题,会导致仿真无法正常运行:
- stopwatch模块中未声明
clk信号,ms_clock实例化的输出悬空,需要在stopwatch模块内添加wire clk;声明 - bcd_counter模块的端口声明位宽错误,原代码
output bcd, next;需修改为:
output [3:0] bcd; output next;
- ms_clock模块的
count和ms_clock寄存器无初始值,仿真启动后会处于X态,需要添加initial块初始化:
initial begin count = 0; ms_clock = 0; end
修复后的testbench代码
module stopwatch_tb(); // 声明输入信号 reg CLOCK_50; reg [1:0] BUTTON; // 声明输出信号 wire [0:6] HEX0, HEX1, HEX2, HEX3; wire HEX2_DP; // 可选:绑定内部子模块信号方便直接查看 wire [3:0] hun_bcd = dut.bcd_counter_hundredths.bcd; wire [3:0] tenths_bcd = dut.bcd_counter_tenths.bcd; wire [3:0] ones_bcd = dut.bcd_counter_ones.bcd; wire [3:0] tens_bcd = dut.bcd_counter_tens.bcd; // 正确实例化DUT,端口顺序匹配设计定义 stopwatch dut ( .CLOCK_50(CLOCK_50), .BUTTON(BUTTON), .HEX0(HEX0), .HEX1(HEX1), .HEX2(HEX2), .HEX2_DP(HEX2_DP), .HEX3(HEX3) ); // 生成50MHz时钟,周期20ns initial begin CLOCK_50 = 1'b0; forever #10 CLOCK_50 = ~CLOCK_50; end // 按键激励 initial begin // 初始化:复位按下,启停按键默认高 BUTTON[1] = 1'b1; BUTTON[0] = 1'b1; #20 BUTTON[1] = 1'b0; // 释放复位 #100 BUTTON[0] = 1'b0; // 按下启停按键,开始计时 #10000000 $stop; // 仿真10ms,可根据需要调整时长 end endmodule
补充提示
如果要快速验证计数逻辑,可以临时把ms_clock模块中的计数阈值从250000改成更小的值(比如25),避免仿真等待时间过长。
内容的提问来源于stack exchange,提问作者josed2212
相关产品推荐
相关产品推荐

