一、组合逻辑和时序逻辑
数字电路可以分成两大类,一类叫组合逻辑电路,另一类叫做时序逻辑电路。
组合逻辑电路:由门电路组成,其某一时刻的输出状态只与该时刻的输入状态有关,而与电路原来的状态无关,并没有记忆功能。
时序逻辑电路:由锁存器、触发器和寄存器等单元组成,其某一时刻的输出状态不仅与该时刻的输入状态有关,而且与电路原来的状态有关,具有记忆功能。
而组合逻辑电路和时序逻辑在FPGA中并行执行这是毋庸置疑的,唯一不同的就是组合逻辑只要信号发生改变就随便改变,时序逻辑则需要随着时钟的上升沿或下降沿的到来而改变。
assign result1 = a & b;
always @(*) begin
if (~reset_n) begin
result2 = 0;
end
else begin
result2 = a & b;
end
end
always @(posedge clk or negedge reset_n) begin
if (~reset_n) begin
result3 <= 0;
end
else begin
result3 <= a & b;
end
end
在第一个clk时reset_n低电平有效,因此result2和result3被置为0,而result1则因为assign语句被置为1;
在第一个clk结束后reset_n变为高电平,因此result2被置为1,result3则因为没有检测到clk上升沿仍被置为0;
在第二个clk结束后a从1变为0,此时组合逻辑的result1和result2随之变化,而时序逻辑result3则在第三个上升沿clk时被置为0。
二、阻塞赋值和非阻塞赋值
阻塞赋值(=):在赋值时,先计算等号右手部分的值,再赋值给左边变量,直到该语句赋值完成,后面的语句才能执行,会阻塞后面的语句。
非阻塞赋值(<=):执行赋值语句右边,然后将begin-end之间的所有赋值语句同时赋值到赋值语句的左边,但是左边的变量的值不会立即更新,直到always块所有语句执行完,才将左边变量的值更新。
always @(posedge clk or negedge reset_n) begin
if (~reset_n) begin
b <= 0;
c <= 0;
end
else begin
b <= a;
c <= b;
end
end
always @(*) begin
e = d;
f = e;
end
可以简单这么理解:阻塞赋值时顺序执行,前一句执行完后才会执行后一句;非阻塞赋值时并行执行。
这样也就很好解释了为什么什么是打拍。如下图仿真所示
非阻塞赋值:
在第一个clk时, reset_n为低电平有效,因此b、c被置为0;
在第二个clk时,执行赋值语句,因为是非阻塞赋值,将b的值置为a、将c的值置为b(注意此时b不等2,b的值仍为0),赋值结束后b=2、c=0
在第三个clk时,执行赋值语句,此时b=2,将c的值置为b,因此赋值结束后c=2
阻塞赋值:
先执行e=d,执行完毕后e=3;
再执行f=e,执行完毕后f=3。
通过RTL图也可以理解,非阻塞赋值被综合成了两个D触发器,因此当一个clk到来时寄存器的值通过Q输出到c中,即b原来的0值,而a的值通过寄存器的D存进b里,;第二个clk到来时才会将b后来更新的值送到c寄存器。而阻塞赋值则被综合成了连线哈哈^_^
针对阻塞赋值和非阻塞赋值的使用:
1、时序逻辑,使用非阻塞赋值;
2、锁存器建模,使用非阻塞赋值;
3、组合逻辑,使用阻塞赋值;