我对Verilog有点新鲜。我知道在时钟进程中我们应该使用非阻塞分配,而在非时钟进程中,我们使用阻塞分配。
当我阅读其他人的代码时,我遇到了这段代码。
reg iowrb_int,iowrb_met;
reg iordb_int,iordb_met;
always@(*)
begin
iowrb_int <= iowrb_met;
iordb_int <= iordb_met;
iowrb_met <= iowr_bar;
iordb_met <= iord_bar;
end
我真的不确定上面的代码!我不认为它正在进行任何注册,对吗?在always @(*)语句中是否有任何非阻塞的意思?
在always @(*)语句中使用阻塞与非阻塞有什么区别吗?
答案 0 :(得分:2)
主要区别在于:
假设a = 2且b = 3然后是非阻塞分配:
a <= 4;
b <= a;
导致a = 4且b = 2 - 分配前的值
但是
a = 4;
b = a;
在阻塞分配完成后,将导致a = 4和b = 4 - a的值。
合成到寄存器(锁存器或触发器)与组合逻辑的变量取决于始终块的灵敏度列表。它不依赖于使用阻塞或非阻塞分配。
例如:
always @(*) begin
if (enable)
q = d;
end
这将导致D锁存器,因为当enable == 0时没有指定为q赋值,所以它需要记住是最后一次赋值。
虽然
always @(*) begin
if (enable)
q = d;
else
q = f;
end
这将导致多路复用器(组合逻辑),因为为两种情况都指定了q的赋值,因此q不需要记住任何内容。
答案 1 :(得分:1)
阻塞与非阻塞是为了使您的门级(综合)与您的RTL模拟匹配。据我所知,使用不同的方法来改变模拟的行为不会影响合成,因此也不会影响门级的行为。
<=
非阻止有效地获取副本右侧的临时副本,并在时间步结束时进行=
阻止分配。
a <= b;
b <= a;
相当于:
a_temp = b;
b_temp = a;
//
a = a_temp;
b = b_temp;
该示例使用组合逻辑,即它不包含任何状态,因此所有输入必须由所有输出定义。
always@* begin
iowrb_int <= iowrb_met;
iordb_int <= iordb_met;
iowrb_met <= iowr_bar;
iordb_met <= iord_bar;
end
当右侧更新块时,应重新触发。由于iowrb_met是双方的,我不确定这意味着什么是电气连接。
虽然<=
意味着复制到临时位置,但组合逻辑没有此功能,它始终由分配驱动。
我认为在模拟中你实际上有这个:
always@* begin
iowrb_int_temp = iowrb_met;
iordb_int_temp = iordb_met;
iowrb_met = iowr_bar;
iordb_met = iord_bar;
iowrb_int = iowrb_int_temp;
iordb_int = iordb_int_temp;
end
在硬件方面你会有:
always@* begin
iowrb_int = iowrb_met; //= iowr_bar;
iordb_int = iordb_met; //= iord_bar;
iowrb_met = iowr_bar;
iordb_met = iord_bar;
end
iowrb_int
实际上与iowrb_met
使用always @(posedge clk
来暗示触发器
使用always @*
暗示了组合逻辑,但是当输出未完全根据输入定义时,可以隐含锁存器。
答案 2 :(得分:1)
仅 更改为阻止分配的代码,它可能会合成到锁存器和/或根据工具句柄创建逻辑等效检查不匹配。
这是调度程序的外观:
阻止:
*_int
个信号*_met
个信号*_int
保留*_met
非阻塞:
*_int
个信号*_met
个信号*_met
的更改会导致循环回调度程序的 Active 区域*_int
信号*_int
信号*_int
与*_met
正确,逻辑等效和CPU友好的方式是颠倒分配顺序(在*_met
之前分配*_int
):
always@(*)
begin
iowrb_met = iowr_bar;
iordb_met = iord_bar;
iowrb_int = iowrb_met;
iordb_int = iordb_met;
end
*_int
个信号*_met
个信号*_int
与*_met
OR 使用*_bar
作为赋值(即如果a == b和b == c,那么a == b和a == C):
always@(*)
begin
iowrb_int = iowr_bar;
iordb_int = iord_bar;
iowrb_met = iowr_bar;
iordb_met = iord_bar;
end
*_int
和*_met
信号*_int
与*_met
答案 3 :(得分:0)
正如其他人所说,在此处更改为阻止分配实际上是行不通的。在组合始终阻止中使用阻止分配(这是建议),要求您以正确的顺序放置分配。
在组合总是块中使用非阻塞分配似乎很有吸引力,因为这样您就可以按任何顺序进行分配,例如在VHDL中。除了性能,避免这种情况的一个很好的理由是它不适用于always_comb
。该代码不起作用:
always_comb begin
tmp <= in;
out <= tmp;
end
原因是tmp
将不属于敏感度列表。如果您使用always @(*)
,always @(tmp, in)
或替换为阻止分配,它将按预期工作。