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; 

always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin 
            a_cnt <= 1'b0;
	end
	else begin
            a_q <= a;
	end
end
  
always@(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

always@(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


2024.1.30 更新, -fsdb 在高版本(比如vcs2023)已经弃用, 可以用 -debug_access 替代, +fsdb+delta中间没有空格,有空格的话后面用verdi打开时相应的是灰色的

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

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

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一下,也欢迎把具体的解决方法留在评论区,以供后来者参考

参考

guest
0 评论
内联反馈
查看所有评论