Vivado中$display未正确显示Verilog变量赋值结果的问题排查
Verilog仿真结果异常排查
问题描述
编写的阶乘计算Verilog代码,预期仿真输出res is 3.000000,但实际输出为res is 0.000000,需排查问题原因。
原Verilog代码
`timescale 1ns / 1ps module factorial( input i_n, output reg res, input i_clk ); integer j; initial begin:a for (j=1;j<=i_n;j=j+1)begin res<=res*j; end res<='d3; $display("res is %f",res);//as res is 'd3,should display 3.0 end endmodule module u_f; reg i_n; wire res; reg i_clk; initial begin i_n<=3; i_clk=1'b0; end always begin #10 i_clk<=~i_clk; end factorial u2( .i_n(i_n), .i_clk(i_clk), .res(res) ); endmodule
实际仿真输出
Time resolution is 1 ps res is 0.000000
问题原因分析
非阻塞赋值的执行时序问题:
代码中res<='d3使用了非阻塞赋值(<=),Verilog里非阻塞赋值的变量更新会被放到当前时间片的NBA(Non-Blocking Assignment)阶段执行,而$display属于Active阶段的语句,会在NBA阶段之前跑。也就是说,执行$display时,res还没被更新成3,依然保持之前的初始状态。reg变量未初始化:
res是output reg类型,代码里没有显式初始化,它的初始值是未知态(x)。虽然之后尝试赋值3,但因为非阻塞赋值的时序问题,$display读取的还是这个未知态x。当用%f格式化输出未知态时,仿真器会把它解析成0.000000。额外的时序隐患:
测试模块里i_n<=3也用了非阻塞赋值,仿真0时刻factorial模块的initial块执行时,i_n还没被赋值成3,依然是初始值x,导致for循环的条件j<=i_n不成立,循环根本不会执行。不过这不是本次输出异常的直接原因,但也是代码里的潜在问题。
修复建议
- 把
res<='d3改成阻塞赋值:res='d3,阻塞赋值会立刻更新变量值,$display就能读取到正确的3。 - 或者在
$display前加#0,让语句延迟到NBA阶段之后执行:res<='d3; #0 $display("res is %f",res); - 同时建议显式初始化
res,比如在output reg res后加=0;,避免未知态带来的问题。
内容的提问来源于stack exchange,提问作者kittygirl
相关产品推荐
相关产品推荐

