有人可以向我解释为什么会推断出锁存器而不是触发器吗?
always_ff @ (posedge clk, negedge rst)
begin
if (!rst)
a <= '0;
end
始终阻塞对信号边缘敏感的事实不足以推断出触发器。在这种情况下,当触发复位的下降沿时,获得0,否则它保持原值。
此问题来自此stackoverflow问题中选定的最佳答案:
System Verilog always_latch vs. always_ff
=============================================== ============================
我将在此分享我到目前为止所发现的内容。它合成锁存器而不是触发器的原因是因为在赋值的右侧是CONSTANT。 在这种情况下,锁存器和触发器的行为是等效的,因为它是否捕获信号边沿(触发器)上的输入值或启用输入锁存(锁存器)无关紧要因为输入没有改变。因此,综合工具选择占用较少资源的元素,即锁存器。
另一方面,如果在赋值的右侧有一个VARIABLE,则合成必须推断触发器,因为输入是否在边缘上采样是很重要的(翻转 - 翻转)或在输入锁存期间启用(锁存),意味着两个逻辑元素不等同。
这是一个例子。前两个始终块将合成一个锁存器(在Quartus 14中),这是正常的,因为它们是等价的,因为它是常量。但是,3.和4. always块也将被合成为一个锁存器,这不是预期的行为,这些块不等同! 3.块将发出警告,而4.将不会发出警告。
module ff_latch(
input logic clk,
input logic nrst,
input logic a,
output logic t, x, y, z
);
always_ff @(posedge clk, negedge nrst)
begin
if (!nrst)
t <= 0;
end
always_latch
begin
if (!nrst)
x <= 0;
end
always_ff @(posedge clk, negedge nrst)
begin
if (!nrst)
y <= a;
end
always_latch
begin
if (!nrst)
z <= a;
end
endmodule: ff_latch
对我来说这种行为是不正确的,因为我特意说我想要一个触发器(带边缘触发)。这甚至不是编码模糊,总是第3和第4块明显不同,从上面的模拟中可以看出:
块3.(tb_y)表现得像异步触发器和块4.(tb_z)表现得像 latch 。 但是合成工具在两种情况下都会推断出锁存。
如果有人可以对此进行阐述或评论代码或波形,我们将不胜感激。
答案 0 :(得分:4)
合成器将推断锁存器,因为此代码的行为类似于锁存器。它的行为不像触发器。它就这么简单。
考虑一下此代码的行为:最初a
的值为'x
。如果rst
声明为低,则a
将变为'0
。 a
将永远保留在'0
。因此,a
的状态不仅取决于输入的当前状态,还取决于过去的状态。因此,我们有顺序逻辑,而不是组合逻辑。触发器在时钟边沿改变状态; a
没有。始终块对信号边缘敏感的事实是无关紧要的。这只意味着内部代码在该信号边缘上执行 - clk
的上升沿。但是当发生这种情况时,没有任何事情发生,所以这段代码就像一个锁存器。
答案 1 :(得分:1)
因为你还没有明确指出时钟发生了什么。就好像a
完全不依赖于clk
或它的构成。您的所有说明都是a
在0
时设置为rst=0
。此外,它(隐含地)说a
在所有其他情况下保持其先前的值。这可以通过锁存器实现。
请注意,仅仅因为你拥有clk
的@posed,并不意味着该块中的每个变量都将被合成为一个翻牌。当在clk的posedge处激活块时,您还需要对a
进行非阻塞分配。请参阅here。
如果你坚持使用翻牌来实现相同的功能,你可以试试这个:
always_ff @ (posedge clk or negedge rst)
begin
if (!rst)
a <= '0;
else
a <= a; //Here, we are specifying what happens @posedge of clk
end