verilog设计行为仿真和时序仿真不一致, 原来是敏感信号的问题

发布时间 2023-12-12 11:54:42作者: 天若手提滑铲

描述

最近在vivado中设计一个计算器: 28bit有符号加减法,结果出现行为仿真和时序仿真不一致情况

代码

r_a, r_b : 对计算数据a, b的寄存器存储, 也是计算器的数据输入
s_bit : 符号位
cout : 28bit计算器的进位输出 cout[27] : 最高位进位, 用来判断符号以及加法进位

always@(a, b) begin // 1
// always@(r_a, r_b) begin // 2
	case({a[27], b[27]}		// 1
	case({r_a[27], r_b[27]}) // 2
			2'b00: s_bit = 1'b0;
			2'b01: s_bit = cout[27] ? 1'b0 : 1'b1;
			2'b10: s_bit = cout[27] ? 1'b0 : 1'b1;
			2'b11: s_bit = 1'b1;
			default:s_bit = s_bit;
		endcase
	end

输出结果代码

always@(posedge clk or negedge rstn) begin
		if(!rstn)
			result <= 'd0;
		else
			result <= {s_bit, sum};
	end

当条件为1时行为仿真错误,时序仿真正确, 如下
image

当条件为2时行为仿真和时序仿真均正确 , 如下
image

说明

此处的敏感信号列表只有当为r_a, r_b时结果才正确,其他情况均错误

分析

image

t0 : a0, b0 变化,cout0 = 0, case0 = 2'b00, s_bit0 = 0
t1 : r_a0, r_b0 变化并且开始进行计算,cout1 = 0, case1 = 2'b00, s_bit1 = 0
t2 : a1, b1 变化, cout1 = 0, case = 2'b01, s_bit = 1
t3 : r_a1, r_b1 变化开始进行计算, cout3 = 1, case = 2'b01, s_bit = 1

为什么会发生错误呢?

t0 : a, b变化, 但是此时的cout = 0, 并不是因为计算等于0 ,因为此时并未开始计算,所以s_bit也会错误
t1 : r_a, r_b 变化,开始计算,现在的cout是正确的,但是此时并不更新s_bit,因为敏感信号没有变化
t2 : a, b发生变化, 但是此时的cout却是上一个r_a, r_b计算的结果,但是我们在此时对s_bit进行赋值,还是会发生错误
t3 : 终于输出计算结果, 但是此时的s_bit是错误的, 因为cout与case并不同步, case超前于cout一个上升沿(而非一个clk)

所以,在设计的时候一定要分析好时序, 尽管s_bit使用的是组合逻辑, 但是,在仿真过程中出现了case选项和条件值不同步的情况

另外

代码块A

always@(a, b) begin
	case({a[27], b[27]})
		2'b00: s_bit = 1'b0;
		2'b01: s_bit = cout[27] ? 1'b0 : 1'b1;
		2'b10: s_bit = cout[27] ? 1'b0 : 1'b1;
		2'b11: s_bit = 1'b1;
		default:s_bit = 1'b0;
	endcase
end

代码块B

always@(*) begin
	case({a[27], b[27]})
		2'b00: s_bit = 1'b0;
		2'b01: s_bit = cout[27] ? 1'b0 : 1'b1;
		2'b10: s_bit = cout[27] ? 1'b0 : 1'b1;
		2'b11: s_bit = 1'b1;
		default:s_bit = 1'b0;
	endcase
end

代码块B 等价于 代码块A, 废话,肯定等价
我的意思是,always@(*) 会自动将case(a,b)变成敏感信号,从而变化为always@(a, b), 其他信号变化无用
如果你的控制变量是别的, 综合工具(此处是vivado)会将控制信号变为敏感信号.

本篇结束,大家设计代码一定要注意时序匹配