话说大禹治水,因为他老爹治水失败被咔咔了,他不得已去顶缸。
他也琢磨啊,其父也不是等闲之辈,没搞定,说明必须得换个法子,否则自己也得被大哥给嗝屁了。
大禹父子治水,分别用的是阻塞和非阻塞的方法,下面我们就扯一下逻辑电路中的阻塞和非阻塞。
通常所说的阻塞和非阻塞,指的是always块中的语句。
always语句中有时序逻辑,也有组合逻辑。
前者用非阻塞,后者用阻塞。其实“阻塞”这个术语,也是专门给软件出身的电工看的,硬电工才懒得管你阻不阻的呢。
reg[7:0] in1;
reg[7:0] out;
always @ (posedge clk)
begin
in1 <= in1+8'h01;
out <= in1;
endendmodule
先从容易的下刀,我们先看看这个非阻塞的语句,它很简单,就是in1的自身完成一个自加一注意这个“<=”,是不是又想起了C语言里用来搞指针的“->”,不过真的没有一毛钱的关系。
in1拿到的是clk上升沿之前的“in1”值再加1,跟clk上升沿之后的in1没有关系了。
正如,已毕业的小明的时候对还在读大四GF小芳承诺说,哥等你大学毕业就讨你做LP了。时光如箭,日月如梭,时间如白驹过隙,学校7月份小芳走出了象牙塔的大学校门。小明履行承诺,娶小芳为妻。话说,无巧不成书。小芳大学毕业了,但大三的同学也该升级读大四了,正好里面也有个女娃的名字也叫小芳。抢答开始,问:小明,娶的是哪个小芳?答案是,去年读大四今年毕业的那个小芳,而不是去年大三今年大四的那个小芳。您感觉拗口吗,反正我有点绕口令的感觉了。
非阻塞操作也是这个效果,你娶的是毕业(clk上升沿)之前的那个大四的小芳。
我们知道硬件是并行执行的,所以,上面的代码,这么写,效果一样。
in1 <= in1+8'h01; //老小芳毕业,新小芳升级大四
out <= in1; //小明娶老婆
但,如果把非阻塞改为阻塞的,那小明娶的老婆,到底是谁?且看分析。
in1 <= in1+8'h01; //老小芳毕业,新小芳升级大四
out <= in1; //小明娶老婆
所谓阻塞,就是一步一步来,就是写软件的那个思路,小明顺利娶他昔日的恋人为妻。
我们要调整语句顺序了,再看看小明的执行结果咋样
in1 = in1+8'h01; //老小芳毕业,新小芳升级大四
out = in1; //小明娶老婆
要顺序执行的哦,先完成“老小芳毕业,新小芳升级大四”,然后“小明娶老婆”。
小明娶到了刚刚大三升大四的小芳,你完全可以认定,小明是一个喜新厌旧的文艺青年。
而如果,做下语句的调整,就像下面这样
out = in1; //小明娶老婆
in1 = in1+8'h01; //老小芳毕业,新小芳升级大四
小明喜新厌旧的企图,被强大的阻塞语句,给堵回去了。
一般用阻塞语句来实现assign语句描述困难的组合逻辑,一般情况下代码块会比较小。
非阻塞的一般是用于时序逻辑,时序逻辑往往比较复杂,有时候复杂得有些变态。如果月老执行Verilog语句的时候,一不小心,小明就娶错了老婆。
阻塞,有个地方用起来很方便,也许你也猜到了,testbenchtb代码本身,就不被用来综合到电路,所以,可以大胆使用阻塞语句
#10 rst = 1;
#10 clk = 0;
#10 clk = 1;
#10 clk = 0;
#10 clk = 1;
#10 rst = 0;
repeat(100)
begin
#10 clk = 0;
#10 clk = 1;
end
这是一段,模拟单片机复位释放以及振荡器启动的激励。反正是顺序执行的,就拿这写软件的脑袋来理解就够了,估计软电工都喜欢。