程序块中的语句按顺序执行,那么为什么block1,block2或block3中没有任何一个推断出锁存器?
module testing(
input logic a, b, c,
output logic x, y, z, v
);
logic tmp_ref, tmp1, tmp2, tmp3;
//reference
always_comb begin: ref_block
tmp_ref = a & b;
x = tmp_ref ^ c;
end
always_comb begin: block1
y = tmp1 ^ c;
tmp1 = a & b;
end
always @(*) begin: block2
tmp2 <= a & b;
z = tmp2 ^ c;
end
always @(c) begin: block3
tmp3 = a & b;
v = tmp3 ^ c;
end
endmodule: testing
在block1中,y是在tmp1的新值可用之前使用阻塞分配计算的。
在块2中,tmp2使用非阻塞分配计算,该分配应推迟总块完成时的分配。同时,z是使用阻塞分配计算的,并且tmp2的新值尚不可用。
在块3中,有一个不完整的敏感列表,但仍然没有锁存。
以下是Quartus II 14.1的综合结果:
只有在我添加此块时才会推断出锁存器:
//infers a latch
always @(*) begin: block4
if (c == 1'b1) begin
tmp4 = a & b;
w = tmp4 ^ c;
end
end
有人可以解释为什么不完整的敏感度列表或在更新值之前使用变量不会推断出组合块中的锁存器吗?
答案 0 :(得分:2)
组合块中使用的赋值类型不会影响合成。使用非阻塞(<=
)可能会导致RTL(预合成)到门(合成后)模拟器不匹配。
灵敏度列表也是如此,综合将给出自动生成或完整列表的行为。
在时钟进程(@(posedge clk)
)中使用非阻塞(<=
)来获取触发器的模拟行为。也可以使用阻塞(=
)在计时过程中使用组合代码,但混合样式被认为是一种糟糕的编码实践。组合部分代码只是移动到一个单独的组合块(always @*
)。
锁存器是一个基本的存储器元件,如果电路不需要存储器,则不会推断它。
例如:
always @* begin:
v = (a & b) ^ c;
end
v
完全由输入定义,不涉及内存。与之相比:
always @* begin
if (c == 1'b1) begin
w = (a & b) ^ c;
end
end
当c
为0时,w必须保持其值,因此推断出锁存器。
值得注意的是,虽然锁存器并不坏,但必须注意打开和关闭的时间,以确保它们捕获正确的数据。因此,推断锁存器通常被视为坏的并且来自不良编码。
SystemVerilog具有以下语义,用于语义暗示设计意图:
always_latch begin
if (c == 1'b1) begin
w = (a & b) ^ c;
end
end