使用Kansas Lava在RTL块中对同一寄存器进行多次赋值

38

我在理解Kansas Lava当一个RTL模块包含多个对同一寄存器的赋值时,遇到了困难。这是版本1:

foo :: (Clock c) => Signal clk Bool
foo = runRTL $ do
    r <- newReg True
    r := low    
    return $ var r

这个表现和我预期的一样:

*Main> takeS 10 foo :: Seq Bool
low | low | low | low | low | low | low | low | low | low | ? .

生成的 VHDL 为:

architecture str of assignments is
  signal sig_2_o0 : std_logic;
begin
  sig_2_o0 <= '0';
  OUTPUT <= sig_2_o0;
end architecture str;

然而,我希望这个不同版本也能够起作用:

foo = runRTL $ do
    r <- newReg True

    r := low
    r := high
    return $ var r

但实际上并没有,第二个任务也没有被考虑在内:

*Main> takeS 10 foo :: Seq Bool
low | low | low | low | low | low | low | low | low | low | ? .

我感到困惑的原因是regvar的定义基于完整的时钟周期,因此我无法执行无法综合的操作,例如基于r进行分支,然后重新分配一个新值给它。那么为什么这种第二种形式不起作用呢?

这不仅是模拟问题:第二个版本生成的VHDL清楚地显示第二个赋值在生成时被抛弃:

architecture str of assignments2 is
  signal sig_2_o0 : std_logic;
begin
  sig_2_o0 <= '0';
  OUTPUT <= sig_2_o0;
end architecture str;

基本上,我会期望输出结果更像

architecture str of assignments2 is
  signal sig_2_o0 : std_logic;
begin
  sig_2_o0 <= '0';
  sig_2_o0 <= '1';
  OUTPUT <= sig_2_o0;
end architecture str;

但我不确定在VHDL中这意味着什么。


这个问题中的VHDL在哪里? - user1818839
VHDL是由Kansas Lava生成的。我认为我不应该在问题中包含它,因为这就像在编程问题中包含生成的汇编代码一样... - Cactus
好的,VHDL并不等同于汇编语言。如果是VHDL出现了问题或者没有问题,那么值得发帖讨论。对于所展示的例子来说,它可能并不是很大。 - user1818839
在查看了两种情况下生成的VHDL之后,这似乎是一个纯粹的Lava问题。我正在编辑问题以反映这一点。我仍然会保留“vhdl”标签,因为“lava”标签似乎没有得到很多使用,并且我也对VHDL对非SSA块的看法感兴趣。 - Cactus
1个回答

3
问题在于您正在使用多个非阻塞语句来分配信号。
  sig_2_o0 <= '0';
  sig_2_o0 <= '1';

这意味着:

at next event assign '0' to sig_2_o0.
at next event assign '1' to sig_2_o0.

这与使用阻塞赋值不同:

  sig_2_o0 := '0';
  sig_2_o0 := '1';

Which would translate to:

assign '0' to sig_2_o0.
assign '1' to sig_2_o0.

阻塞型赋值

当您使用阻塞型赋值时,值是明确定义的。首先,它将设置为“0”,然后用“1”覆盖它。在这个例子中,第一个阻塞型赋值对于仿真或合成硬件都不应产生影响。您可以将其视为第一个赋值和第二个赋值之间没有延迟。这意味着您有一个0宽度的脉冲,实际上什么也没有。它相当于只有最后一个赋值,第一个完全被省略了。需要注意的是,如果在赋值上放置延迟,例如“after 1 ns”,则您将在仿真中注意到第一个赋值后跟随第二个赋值。在硬件上,忽略延迟,因此添加延迟不会导致任何变化。事实上,在意图进行合成的RTL中插入延迟是不可取的,原因是需要硬件匹配仿真,而添加延迟可能会引入不匹配。

非阻塞型赋值

但是,当您使用非阻塞型赋值时,模拟器会安排两个赋值以供下一个时间事件使用。将信号设置为“1”,同时将其设置为“0”。那么信号将采取哪个预定的赋值呢?没有办法知道。由于它被错误地分配,因此可能是任何一个值。当遇到多个非阻塞型赋值时,行星上的每个Lint检查器和综合工具都应抛出错误。这可能是可模拟的,但RTL中显然存在问题。


所以,关于这个问题有两个后续问题:
  1. 在阻塞示例中,第一个 sig_2_o0 := '0' 有什么影响?在仿真或合成硬件中是否可观察到?
  2. 是否可以将这种阻塞语义嵌入到 Kansas Lava 中?
- Cactus
1
@Cactus,我在答案中添加了我的对1的回复。至于2,恐怕我只是RTL的人,不太了解Kansas Lava,无法给你需要的全面答案。我只能根据我对RTL的理解给出部分答案。依我看,阻塞与非阻塞是RTL最难理解的方面。我花了一段时间才弄明白它。 - travisbartley
感谢您的澄清。基于此,我认为Kansas Lava的代码生成器最好只生成包含最后一个赋值的VHDL代码(因此多个赋值将成为纯粹的代码生成时间事物,就像它们目前所做的那样)。我会联系Kansas Lava的开发人员了解更多信息。 - Cactus
1
是的,如果您在单个代码块中有多个阻塞语句,这并不会造成伤害,但会增加死代码。当它们位于不同的代码块中时,多个阻塞语句可能很有用。例如,您可能会有一个默认赋值,然后稍后在if语句中嵌套另一个赋值。我在RTL编码中经常使用该结构,并且对于简洁,高效的RTL非常好。 - travisbartley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接