【VCS】(4)Debugging Simulation Mismatches

Mismatches指的是仿真结果和预期结果不一样,当出现该问题之后,首先从代码本身找问题;
例如:

if (data == 3) 写成了 if( data = 3 )

为了最大程度避免这一问题,可以写成 if ( 3 == data ),这样写的话,如果少写了一个=,编译的时候会报错。
(当然也不排除工具本身出现bug)

VCS中也有一些编译选项来帮助寻找 Mismatched问题。(用的不多)

+race:以文件(race.out)的形式报告代码中存在的竞争冒险。例如,同时对一个变量进行读写,倒底是先执行读操作,还是先执行写操作。

$vcdplusdeltacycleon:也可以用于定位竞争冒险对应的代码。(locate race condition code)

vcddiff & vcat:比较两个VCD波形。(这里是以文本的方式比较,用的不多,一般是在波形窗口进行比较。)

SImulation Mismatches 产生的原因

在这里插入图片描述
从RTL描述到门级网表的综合过程,因为代码的看问题,逻辑综合工具可能做出了和预期不一样的判断,从而导致前仿成功,而后仿失败。

Race Conditions

在这里插入图片描述

① Write-Read

Race:using and setting a value at the same time

module race;
	reg a;
	initial begin
		a = 0; #10 a = 1;
	end
	initial begin
		#10 if(a) $display("May not print");
	end
endmodule

这里两个 initial 语句块的执行顺序是不确定的,所以 $display()可能永远不会执行,具体取决于仿真工具如何处理这两个语句块。

改进方法: 将两个语句是时间分开

module race;
	reg a;
	initial begin
		a = 0; #10 a = 1;
	end
	initial begin
		#11 if(a) $display("Will print");
	end
endmodule

② 同时赋值(Write-Write)

在这里插入图片描述

③ Continuous assignment evaluation

在这里插入图片描述

改进:时序电路尽可能用非阻塞赋值语句进行赋值操作

在这里插入图片描述

不定态的说法其实是只存在于仿真过程中,无法确定一个端口的逻辑值是0还是1。在实际的电路中,要么是0,要么是1。

对于改进后的代码,根据仿真事件队列,非阻塞赋值的的赋值操作是要晚于连续赋值语句 assgin 的,所以当第一个时钟上升沿来的时候,p是不定态,if 语句认为不定态是 false,所以不会输出内容。第二个时钟上升沿的时候,p和q都稳定为1,正常输出内容。

在这里插入图片描述

④ Time Zero Races

在这里插入图片描述

在给 reset 赋值为 0 之前,reset 是一个不定态。那么:
① X → 0 的变化,到底算不算是一个下降沿?
② 如果认为是下降沿,那么这个下降沿变化和 always 语句到底谁在前?

改进:

在这里插入图片描述

(x→1的变化肯定不是下降沿。)

⑤ Filp-Flop Race:Read-Write

如下所示,这里在组合电路中使用了非阻塞赋值语句,第一个always语句对应dff1,第二个always语句对应dff2。

在这里插入图片描述

那么这个电路能否得到想要则结果:
① 仿真结果是否符合预期?
② 综合工具得到的电路是否是想要的?(就是下面的RTL代码,综合后能够得到上面的电路吗?)

对上述代码的唯一改进就是使用非阻塞赋值,如下所示。对于如下代码,仿真结果和综合结果是都会是符合预期的。
在这里插入图片描述

一些好的代码规则

在这里插入图片描述
① 组合电路使用阻塞赋值,时序电路使用非阻塞赋值
② 组合电路使用 always @(*)
③ 一个变量同一时间只在一个地方进行赋值。(多驱动一般用于SoC ,接口的双向端口,通过定义wire使用多驱动源)

Lab 两级触发器

这里就使用 Filp-Flop Race 部分给出的示例进行实验,并且回答提出的两个问题。

源代码

dff_exp.v

//-------------------------------
// File Name		: dff_exp.v
// Data				: 2023-07-24
// Designer			: Jyw
//-------------------------------

module dff_exp(
	// Inputs
	input	wire	clk_i,
	input	wire	rst_l_i,
	input	wire	d,
	// Outputs
	output	reg		q
);

//-------------------------------
// ref define area
//-------------------------------
	reg		q1;

//-------------------------------
// Style 1 (YES) non-blocking
//-------------------------------
`ifdef DFF_STYLE1
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q1 <= 1'b0;
	else
		q1 <= d;
end

always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q <= 1'b0;
	else
		q <= q1;
end
`endif

//-------------------------------
// Style 2 blocking
//-------------------------------
`ifdef DFF_STYLE2
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q1 = 1'b0;
	else
		q1 = d;
end

always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q = 1'b0;
	else
		q = q1;
end
`endif

endmodule // dff_exp

dff_tb.v

//------------------------------
// File Name		: dff_exp.v
// Data				: 2023-07-24
// Designer			: Jyw
//------------------------------

`timescale 1ns/1ns

module dff_tb;

//------------------------------
// reg & wire define
//------------------------------
	reg clk_i;
	reg rst_l_i;
	reg d;
	reg q;

//------------------------------
// clock & reset & d generate
//------------------------------

initial begin
	clk_i <= 1'b0;
	forever #5 clk_i <= ~clk_i;
end

initial begin
	rst_l_i <= 1'b1;
	repeat (2) @ (posedge clk_i);
	rst_l_i <= 1'b0;
	repeat (2) @ (posedge clk_i);
	rst_l_i <= 1'b1;
	repeat (20) @ (posedge clk_i);
	$finish(2);
end

initial begin
	forever begin
		@ ( posedge clk_i );
		d <= 1'b0;
		@ ( posedge clk_i );
		d <= 1'b1;
	end
end

//--------------------------------
//	Instance of dff_exp
//--------------------------------
	dff_exp u_dff_exp(
		//Inputs
		.clk_i(clk_i),
		.rst_l_i(rst_l_i),
		.d(d),
		//Outputs
		.q(q)
	);

//-------------------------------
//	dump file
//-------------------------------

initial begin
	$vcdpluson();
end

endmodule // dff_tb

Makefile

.PHONY: com cov sim clean

OUTPUT = simv_dff_exp
ALL_DEFINE = +define+DFF_STYLE2

# Code coverage command

# vdp file name
VPD_NAME = +vpdfile+$(OUTPUT).vpd

# Compile command
VCS = vcs -sverilog +v2k -timescale=1ns/1ns	\
	-debug_all				\
	+notimingcheck			\
	+nospecify				\
	+vcs+flush+all			\
	$(ALL_DEFINE)			\
	$(VPD_NAME)				\
	-o $(OUTPUT)			\
	-l compile.log

# Simulation command
SIM = ./$(OUTPUT)		\
	$(VPD_NAME)			\
	-l $(OUTPUT).log

# Start Compile
com:
	$(VCS) -f file_list

# Start simulation
sim:
	$(SIM)
	
debug:
	dve -vpd $(OUTPUT).vpd &

# Start Clean
clean:
	rm -rf ./csrc *.daidir *.log *.vpd *.vdb simv* *.key *tace.out* 

非阻塞赋值实现

先使用宏定义 DFF_STYLE1,对使用非阻塞赋值的实现的方式进行仿真。仿真得到的波形如下:

在这里插入图片描述

q1比d慢一拍,q比q1慢一拍,符合预期,电路正确。

综合的结果:
在这里插入图片描述

阻塞赋值实现

使用宏定义 DFF_STYLE2,对使用阻塞赋值的实现的方式进行仿真。仿真得到的波形如下:

在这里插入图片描述

此时,q 和 q1 同时改变,这并不是我们想要的。(我们想要的是 q 的变化比 q1 慢半拍。)

在这里插入图片描述

虽然仿真结果是错误的,但是综合的结果却是正确的。

其他写法的仿真和综合

两级触发器的实现,除了上述两种写法之外,还有其他几种写法,如下:

//-------------------------------
// Style 3 
//-------------------------------
`ifdef DFF_STYLE3
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q1 <= 1'b0;
		q  <= 1'b0;
	else
		q1 <= d;
		q  <= q1;
end
`endif
//-------------------------------
// Style 4
//-------------------------------
`ifdef DFF_STYLE4
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q1 = 1'b0;
		q  = 1'b0;
	else
		q1 = d;
		q  = q1;
end
`endif

style 3 的仿真结果和综合结果:

在这里插入图片描述

在这里插入图片描述

style 4 的仿真结果和综合结果:

在这里插入图片描述

在这里插入图片描述

//-------------------------------
// Style 5 交换顺序
//-------------------------------
`ifdef DFF_STYLE5
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q  <= 1'b0;
		q1 <= 1'b0;
	else
		q  <= q1;
		q1 <= d;
end
`endif

//-------------------------------
// Style 6
//-------------------------------
`ifdef DFF_STYLE6
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		q  = 1'b0;
		q1 = 1'b0;
	else
		q  = q1;
		q1 = d;
end
`endif

Style 5 和 Style 6 的仿真结果和综合结果都是满足预期的。

//-------------------------------
// Style 7
//-------------------------------
`ifdef DFF_STYLE7
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		{q,q1} <= 2'b0;
	else
		{q,q1} <= {q1,d};
end
`endif
//-------------------------------
// Style 8
//-------------------------------
`ifdef DFF_STYLE8
always @ ( posedge clk_i, negedge rst_l_i) begin
	if (!rst_l_i)
		{q,q1} = 2'b0;
	else
		{q,q1} = {q1,d};
end
`endif

Style 7 的仿真结果和综合结果:

在这里插入图片描述
在这里插入图片描述

Style 8 的仿真结果和综合结果:

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值