使用Kansas Lava对RTL块中的同一寄存器进行多次分配

时间:2012-12-22 10:49:06

标签: haskell vhdl lava

RTL块包含对同一寄存器的多个赋值时,我无法理解Kansas Lava的行为。这是版本号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是根据一个完整的时钟周期定义的,所以我不可能做到不可能合成诸如基于{的分支之类的东西{1}}然后为其重新分配新值。那么为什么第二种形式不起作用呢?

这不仅仅是一个模拟问题:第二个版本生成的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;

但是我不确定在VHDL中它会/应该是什么意思。

1 个答案:

答案 0 :(得分: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';

哪个会转换为:

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

阻止作业

使用阻止分配时,会明确定义值。首先它将设置为'0',然后用'1'覆盖它。在此示例中,对于模拟或合成硬件的第一个阻塞分配应该没有影响。您可以将其视为第一次分配与第二次分配之间有0延迟。这意味着你有一个0宽度的脉冲,实际上什么都没有。它相当于只有最后一个赋值,第一个完全省略。需要注意的是,如果你对作业进行延迟,例如: “1 ns后”,你会注意到第一次分配,然后是模拟中的第二次分配。在硬件中,延迟被忽略,因此添加延迟不会有任何变化。实际上,由于这个原因,强烈建议不要在RTL中插入旨在合成的延迟。非常希望硬件与仿真匹配,并且添加延迟会引入不匹配。

非阻止作业

但是当您使用非阻塞分配时,模拟器会为下一次事件安排两个分配。将信号设置为“1”,同时将其设置为“0”。那么信号需要哪个预定的分配?没有办法知道。它可能是值,因为它被错误地分配。当遇到像这样的多个非阻塞分配时,地球上的每个lint检查器和综合工具都应该抛出错误。可以模拟它,但RTL显然存在问题。