与堪萨斯熔岩RTL块相同的寄存器的多个分配

RTL块包含多个赋值给同一个寄存器时,我无法理解堪萨斯熔岩的行为。 这是版本号1:

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

这performance得如我所料:

 *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这样基于r分支来合成它,然后重新分配一个新的值。 那么为什么这个第二种forms没有工作?

这不仅仅是一个模拟问题:为第二个版本生成的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中会有什么意思。

问题是你正在使用多个非阻塞语句来分配信号。

  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纳秒后”,那么你会注意到第一次分配,然后是第二次分配。 在硬件上,延迟被忽略,所以不会因为延迟而增加。 实际上,由于这个原因,强烈build议在RTL中插入意图合成的延迟。 硬件与模拟相匹配是非常理想的,并且增加延迟会引起不匹配。

非阻塞分配

但是,当您使用非阻塞分配模拟器有两个分配计划下一次事件。 将信号设置为“1”,同时将其设置为“0”。 那么信号将采用哪个预定分配? 没有办法知道。 由于分配不正确,这可能是任何值。 当遇到这样的多个非阻塞任务时,地球上的每一个棉绒检查器和综合工具都应该抛出一个错误。 有可能模拟它,但RTL显然存在问题。