Verilog阻塞赋值与非阻塞赋值实战体验

1.前言

Verilog与C语言在运算符,变量定义,代码结构等有很多相似,那么其与C语言的差异正式学习Verilog正真要收获的东西。其中阻塞赋值与非阻塞赋值正是其中里程碑式的收获。

2.理论

阻塞赋值,即需要按照顺序一条一条得执行,该中情况与C语言的程序运行结果相同。代码与对应的信号波形图如下:

 

对照波形图和代码可知在复位信号(rst_n)为高电平后即开始赋值操作,虽然没有真的如同C语言按序a,b,c一个个变成零但其运行完最后一句" c = b; "后的结果与C语言代码的运行结果相同。

非阻塞赋值,即所有的赋值语句的等号右侧值仅考虑开始执行时的值,不考虑执行过程中的变化,具体代码和波形图如下:

 

这段代码乍一看和阻塞赋值那段代码一摸一样,仔细看会发现,这段代码把非阻塞赋值代码中所有的"="都替换成了"<=" ,这样就变成了非阻塞赋值,所有的赋值语句在执行时等号右侧的值只考虑开始时的值。例如,第一个时钟到来时a,b,c此时分别为1,2,3经过带入代码中的赋值语句后,实际情况代码如下:

a<=0;
b<=1;//a值在第一个时钟刚到来时为1
c<=2;//b值在第一个时钟刚到来时为2

3.实战

理论就是这么个理论,但是实际使用的时候还是难免犯傻,今天也是静下心来想了许久才想明白,代码如下:

 注意红色框出的这两行。

这段代码中总共有两个always第一个是切换状态标志,第二个根据状态标志做对应的事情。第一个always的if判断语句决定了状态标志"color_counter"能取的值总共有0,1,2,且一定是0,1,2,0,1,2......这样轮换下去,这三个值分别对应了第二个always中的case的三种可能,表面上看起来没有问题,但是实际运行的时候发现"outline_color <= BLUE"这个工作重复了两次。

显然color_counter不可能连续两次取值0,那么说明实际上color_counter的值取到了3,真的吗?为什么?

这里就不上波形图了,因为仔细分析就可以发现问题所在——阻塞和非阻塞的概念不应该仅仅局限在赋值语句上的理解!应该从细节过程上理解。

如果将赋值语句如 a <= b;或a = b;功能都是将b的值写入a,但是阻塞赋值时必须执行完那句赋值才可以接着做后续的工作;非阻塞赋值与其他工作是一起执行的,数据变化是旁路的。

实际上if(color_counter < 2)这个判断语句可以理解为读color_counter的值,并与2做对比。而上述代码中由于使用了非阻塞赋值,导致color_counter <= color_counter + 1;这句在执行时color_counter的数据与if(color_counter < 2)语句读到的color_counter是旁路的关系。即时钟来临时color_counter的值是2,此时if(color_counter < 2)语句读到的color_counter也是2,并且不符合if的判断条件。就在判断的过程中color_counter <= color_counter + 1;也在一旁执行,就这样color_counter糊弄过了if条件判断并最终+1变成了3,于是就出现了问题。

针对这个问题,直接将color_counter <= color_counter + 1;改为color_counter = color_counter + 1;即可,即将这句非阻塞赋值改为阻塞赋值,强制让赋值进行完毕后再开始if(color_counter < 2)判断,问题解决。

猜你喜欢

转载自blog.csdn.net/Fairchild_1947/article/details/123947790