Debug系列文章,想起哪个坑就把它埋了~
本文分享一个for循环的坑,见过了就别再踩了
在Verilog中,我们一般使用for语句进行循环操作。
假设场景:
某项目中,前面代码用到了一个二维数组array[3:0][2:0],如果array[i] = 3’b111,就从S0状态跳转S1状态。这时,你想了两秒钟写出了如下代码:
for(i=0;i<4;i=i+1) begin: array_loop
if(array[i] == 3'b111)
state <= S1;
else
state <= S0;
end
然后,你看了眼代码没有问题,将模块代码整合到工程,编译下载程序到板子上,发现没有实现预期的功能。你就不停抓信号,终于定位到是这个状态机的问题,始终在S0,没有跳转到S1。怎么回事呢,你只得单独对这个模块进行仿真:
明明条件满足了呀?(array[1] = 3’b111) 但是状态始终在S0呢?
这时,你请教了小组同事,他说:把else屏蔽掉,放到for前面。
你试了试:
// ...
state <= S0;
for(i=0;i<4;i=i+1) begin: array_loop
if(array[i] == 3'b111)
state <= S1;
//else
//state <= S0;
end
又跑了仿真:
呀,真的可以!
这时候回过头再来想想for循环:for会在一个时钟周期循环完,那么它的最终结果呢?不就是最后一次循环变量时运行的结果。对应到上面代码,当i=1时,arrar[1] = 3’b111,满足条件;但是for会继续循环,最终变量为i=3,array[3] = 3’b110,不满足if条件,执行else语句,所以state = S0。如果,某次状态跳转到S1,那也只是恰好最后一个循环满足条件罢了。
注释掉else语句,将state = S0放至for循环前面,意思就是状态默认为S0,只要当for语句满足条件,即状态跳转至S1。达到预期效果。
这其实是我们初学Verilog的时候,被要求(组合逻辑)写完整if..else所导致的。也从侧面说明要活学活用。读死书,不如无书。
注:上述是典型的错误示范,正确顺序为: 方案设计——代码实现——仿真验证——上板调试。
再假设一种场景:一个二维数组保存了某种一一对应的关系。比如A对应a,B对应b;现知道B,需要得到对应的b;这时候你可能想到了for循环来遍历整个二维数组,如果满足条件就将对应值赋值给某个变量。但如果你跟上面代码一样,后面跟了else语句的话,很可能得到错误的结果,除非恰好是最后一个循环满足条件。
后记
本文只提供一种逻辑上的概念,并非对应实际项目。
Debug系列文章,想起哪个写哪个,咱们下期见。