关于FPGA设计仿真和硬件实测不一致问题的讨论
1.
寄存器未给初值;
一个良好的习惯就是每个寄存器变量都要在reset里面预先定义初值. 看下面一个例子:
reg [1:0] unini;
always@(posedge clk or negedge rst)
begin
if(~rst)
;//未给定初值
else
begin
unini<=2'd1;
if(unini<2'd1)
a<=b;
end
end
这个例子是笔者在做项目的时候真实经历的一个bug的一个简化描述,实际代码比这个要复杂得多,当时也是找了半天最后才发现是寄存器未给初值这个低级错误.
对于上段代码,仿真的时候,在rst之后的第一个clk上升沿,unini是未定态(即modelsim中的红线), 这个未定态是不满足下面unini<2'd1这个条件的,所以这个上升沿后a不会被赋值b; 而在第二个时钟上升沿之后才会满足条件而进行a<=b赋值;
但是在硬件实测的时候,寄存器里面的值一定是要么是1要么是0(一般默认的初值都是0),所以在第一个时钟上升沿就会进行a<=b的赋值,这样就造成了一个仿真结果和实测不符合的bug.
2.阻塞和非阻塞赋值混用.
阻塞和非阻塞赋值在always里面混用是RTL设计的大忌,即便你很了解阻塞和非阻塞的原理,还是可能因为疏忽造成难以发现的bug.看下面一段代码:
always@(posedge clk or negedge rst)
begin
if(~rst)
...
else
begin
if(a)
c<=1'b1;//很早就将c赋值为1了
else if(b)
c=1'b0; //注释1
end
end
reg state;
always@(posedge clk or negedge rst)
begin
if(~rst)
state<=1'b0;
else
begin
case(state)
1'b0:
begin
b<=1'b0;
if(c)
state<=1'b1;
...
end
1'b1:
begin
....
if(...)
begin
state<=1'b0;
b<=1'b1;
a<=1'b0;
end
end
endcase
end
以上这段代码也是笔者在真实项目中的一个血的教训,在注释1处错误的使用了阻塞赋值,使得一个bug仿真的时候没有仿出来,实测的时候一个信号一个信号地查才最后定为到这个点.有兴趣的可以仿真一下,如果b在state=1状态时,clk的一个上升沿置1,state会立刻回到0状态.此时在state=0状态时如果a不为1,b为1,那么应该在下一个时钟上升沿之前c保持为1,所以state应该立刻转回1状态. 但是由于之前c=0用了阻塞赋值,在仿真的时候就state就不会转回1.而在实测的时候,虽然用了c=0阻塞赋值,但是仍然按照<=综合(综合软件在这种情况下会把=当做<=处理),
这样就导致了一个本该在仿真阶段暴露的bug未被及时发现.
3.时序收敛问题;
随着FPGA功能越来越强大,时序问题将变得越来越重要. 值得注意的是,以往时序问题往往因为setup time不满足,而随着fpga能跑的越来越快,hold time violation也会越来越多地出现.而hold violation主要解决方法有两种, 首先让信号跑在全局网络上,这样虽然慢,但是信号的skew也小. 其次可以通过插入LCELL等FPGA内延时原件来解决. 虽然时序是个大问题,不过一定要首先在确定功能正确后再着手动时序这快,你会发现绝大部分仿真通过但是实测不过的原因还是代码的功能有问题,而由于一些原因没有仿真到.
4.Multi-cornor Simulation
多种情况下仿真. 现在高端FPGA能做的事情已经很接近大规模的ASIC电路,而ASIC级别的复杂度的FPGA设计要求的是实测前要进行完备的功能验证.比如码流的长度\样式的多种变化,数据的不同输入速率等多种情况都要进行仿真.笔者极力推荐大家仿真时候尽量用system verilog这种高级仿真语言,其有条件随机激励和assertion等功能可以极大增强代码覆盖率,十分有助于发现那种普通定点看波形仿真发现不到的问题.记住一句话,复杂设计的仿真绝对不能局限在一点一点看波形,绝大多数的bug是要编程靠程序自动发现的!
这个经验很有价值啊,小编真是个热心人
小编真是个热心人
呵呵,仔细想一想

你好,我仿真了一下,你说的第二个问题,c应该是能够在下一个时钟沿前保持1的吧?
不知道我弄的对不对?
还是以软件的思路来考虑硬件的实现。
学习中,谢谢小编、、、
最近遇到一个问题,板子热的时候结果就不对,加上风扇吹一会儿就正确了,这问题比较郁闷啊!
set up 时间余量太小
sdwsh说的很多。搂主的代码风格非常糟糕,不严格遵守RTL代码规范,仿真的结果根本不可信!
楼上的说我代码风格糟糕,请举例说明,不要凭空放话.
其次,此文目的本就在于献丑,把代码中容易出错的地方展示出来,何谈仿真不可信一说?
国标北师版)听力
一次,5元,什么时候下完了
设计任何东西,细节都很重要
嵌套太多
else里嵌套if
case里嵌套if
这不是软件思想吗
这风格好吗
请分清楚RTL设计的层次, 本身就是介于高级结构和底层描述之间的寄存器行为级, if else嵌套在不影响时序的前提下是完全没问题的...
何况我这个if else还叫多?怀疑你是否做过复杂的设计...
最后点明一句:组合逻辑的延迟大小和if else嵌套是没有直接联系的,要具体分析你的关键时序路径,而不是说盲目地避免if else
还有 谁规定else里面不能嵌套if了... case里面不能用if了...
楼上的说法真的很奇怪....自己去看网上的标准代码,全都是这样用的.
新手,学习了,谢谢小编!
学习中,谢谢小编、、、
小编有些激动。回复指出问题的人其实没有切中要害。我觉得代码风格没啥问题,其它有问题,我抱砖引玉,只说两点:1.不必要,也最好不要把每个寄存器都赋初值,尤其在datapath中。2. Multi-cornor Simulation是STA中的概念,和SV没关系。
热敏电阻?
学习了
分享自己的问题让每个人受教,热心啊
看看,学习中,
学习了,小编很主动思考啊。
大多数的bug是要编程靠程序自动发现的!这个不错
嗯 经验之谈 赞一个
只能慢慢吸收了
看了小编的经验,学习到了很多。
有一个问题没有搞懂,小编说的第三点,在解决hold time violation的时候尽量让信号跑全局网络是什么意思?
