D触发器仿真没有打一拍

vcs:2016.06_Full64
verdi: verdi3_L-2016.06-1

具体代码如下

`timescale 1ns/1ps
module exp1(
input        clk   ,
input        rst_n ,
input        a     ,
output [3:0] a_cnt
);
wire a_risedge ;
reg a_risedge_q;
reg a_q        ;
reg [3:0] a_cnt;
assign a_risedge = ( a_q ^ a) & a; 
[email protected](posedge clk or negedge rst_n) begin
if(!rst_n) begin 
a_cnt <= 1'b0;
end
else begin
a_q <= a;
end
end
[email protected](posedge clk or negedge rst_n) begin
if(!rst_n) begin
a_cnt <= 1'b0;
end
else begin
a_risedge_q <= a_risedge;
end
end
[email protected](posedge clk or negedge rst_n) begin
if(!rst_n) begin
a_cnt <= 1'b0;
end
else if(a_risedge_q == 1'b1)  begin
a_cnt = a_cnt + 1'b1;
end
else begin
a_cnt <= a_cnt;
end
end
endmodule
module test;
wire clk  ;
wire rst_n;
wire a    ;
reg [3:0] a_cnt;
parameter cycle = 2;
exp1 u_exp1(
.clk   (clk  ),
.rst_n (rst_n),
.a     (a    ),
.a_cnt (a_cnt)
);
initial begin
clk = 0;
forever #(cycle/2) clk <= ~clk;
end
initial begin
$fsdbDumpfile("dut.fsdb");
$fsdbDumpvars(0,u_exp1);
$fsdbDumpon();
rst_n = 1'b0;
a 		= 4'b0;
#1;
rst_n = 1'b1;
#1;
a = 1'b1;
#7;
a = 1'b0;
#2;
a = 1'b1;
#4;
a = 1'b0;
#4;
a = 1'b1;
#2;
a = 1'b0;
$fsdbDumpoff();
$finish();
end
endmodule

用 vcs 编译并仿真,在仿真时需要加上 -fsdb 和 -region,在仿真时需要加上 +fsdb+delta 才能从verdi上看到Delta cycle

vcs -full64 -cpp g++-4.4 -cc gcc-4.4 -sverilog -fsdb -region exp1.v && ./simv +fsdb+delta

用 verdi 打开 dut.fsdb 文件,将波形全部加载进来

verdi -ssf dut.fsdb & 

鼠标左键单击时钟上升沿,在按键盘小写的 w ( nWave–>View –> Expand Delta –> Expand/Collapse Time at Cursor )即可显示出Delta cycle。可以看到在时钟上升沿,采到的值为0,这是因为verilog中存在仿真调度的问题,虽然都是在同一时刻,但是毕竟是用来软件来模拟硬件的行为,软件执行始终是有先后顺序的,具体的顺序可以参考这里,active 区是要在 NBA区之前执行的,在 active 区域会执行阻塞赋值的内容,在 NBA 区域会执行非阻塞赋值的东西。因此,在 9ns 的时候,a 的值是先变为0,然后时钟上升沿才到来,因此在时钟上升沿采样到的就是0,也就不会有打一拍。

当我们把 tb 中的阻塞赋值改为非阻塞赋值后,把时钟的非阻塞改为阻塞后,该现象就没了,下图是改为非阻塞后的结果。

如果在这个过程中遇到了其它问题,欢迎在评论区留言,或者Google一下,也欢迎把具体的解决方法留在评论区,以供后来者参考

欢迎转载,不需注明出处,就说是你写的

参考

发表评论

您的电子邮箱地址不会被公开。

*

code