VHDL numeric_std 函数(“+”)

VHDL numeric_std function ("+")

各位!

拜托,你能给我解释一件奇怪的事吗? numeric_std 库包含一个函数“+”,加法。我插入了函数的描述。

-- 编号:A.3 function "+" (L, R: UNSIGNED) return UNSIGNED; -- 结果子类型:UNSIGNED(MAX(L'LENGTH, R'LENGTH)-1 downto 0)。 -- 结果:添加两个长度可能不同的 UNSIGNED 向量。

例如,我们有:

    a      : in  unsigned(2 downto 0);
    b      : in  unsigned(1 downto 0);
    result : out unsigned(2 downto 0);

因此,如果 a 是“111”且 b 是“01”,则结果将为“000”。原因是溢出。 我的问题是为什么库允许它,为什么它不扩展结果长度?为什么编译器不警告我溢出?是否可以在不溢出的情况下添加值?我应该如何防止或发现发生溢出。

谢谢!

你说得对,关于使用此运算符的警告会很有帮助。但是,开发人员需要知道他们是否需要滚动的加法操作,或者其中和溢出会导致不良行为的操作。

当执行加法时,如果不希望发生溢出,则结果需要比最长操作数长 1 位。然后您可以通过查看最高有效位是否设置为“1”来检查溢出。

在硬件中,我们有增量器和减量器——它们作为正常操作的一部分“翻转”,我们有累加器——它们永远不会翻转,我们有数学单元需要保持操作的完全精度.

在 VHDL 中,当我们进行操作时,它必须产生精确大小的结果。递增器、递减器和累加器都需要保持相同大小的结果,而需要保持运算完全精度的数学单元需要增加大小。

因此,“+”只能满足其中一种需求。另一部分需要代码处理。

对于numeric_std,“+”的规则如您所说,结果的大小是最大数组操作数的大小。有意思的是,在ieee.fixed_pkg中,结果的大小是1+最大数组操作数的大小。

让我们来看看这对我们的数学有何影响。

signal Co : std_logic ; -- to throw away carry out

signal Incrementer_unsigned : unsigned(3 downto 0) ; 
signal Incrementer_ufixed   : ufixed(3 downto 0) ; 

signal Accumulator_unsigned : unsigned(3 downto 0) ; 
signal Next_unsigned        : unsigned(3 downto 0) ; 
signal Accumulator_ufixed   : ufixed(3 downto 0) ;
signal Next_ufixed          : ufixed(3 downto 0) ; 

signal Sum_unsigned         : unsigned(8 downto 0) ; 
signal A_unsigned           : unsigned(7 downto 0) ; 
signal B_unsigned           : unsigned(7 downto 0) ; 
signal Sum_ufixed           : ufixed(8 downto 0) ; 
signal A_ufixed             : ufixed(7 downto 0) ; 
signal B_ufixed             : ufixed(7 downto 0) ; 

. . .

process (Clk)
begin
  if rising_edge(Clk) then 
    -- Incrementer / Decrementer with unsigned or ufixed.  Result same size
    Incrementer_unsigned     <= Incrementer_unsigned + 1 ; 
    (Co, Incrementer_ufixed) <= Incrementer_ufixed   + 1 ; 

    -- Accumulator with unsigned or ufixed.  Result same size
    Accumulate_unsigned      <= Accumulate_unsigned + Next_unsigned ; 
    (Co, Accumulate_ufixed)  <= Accumulate_unfixed  + Next_ufixed ; 

    -- math unit with full precision.  Result size increases
    Sum_unsigned  <= ('0' & A_unsigned) + ('0' & B_unsigned) ; 
    Sum_ufixed    <= A_ufixed           +  B_ufixed ; 
  end if ; 
end process ; 

因此对于 numeric_std,如果我们对增量器发出警告,我们将收到大量误报警告并最终忽略所有警告 - 那将是一个错误。

对于numeric_std,大小调整规则非常适用于增量器和累加器。结果的大小是预期的。对于 Sum_unsigned,我们必须放大一个参数(如果它们大小相同),我选择同时放大两个。有一个调整大小的功能,我选择不使用。

对于fixed_pkg,对于增量器和累加器,我们必须通过在左侧使用聚合来删除进位来缩小结果(此代码是 VHDL-2008)。还有一个调整大小可以处理这个问题。对于 Sum_ufixed,结果的大小符合我们的应用程序。

这表明无论您选择哪条规则,编写代码的人都必须做某事。

对于 Sum_ufixed,如果我们有:

,结果会更令人兴奋
signal Sum_ufixed10         : ufixed(9 downto 0) ; 
. . . 

Sum_ufixed10 <= (A_ufixed + B_ufixed) + (C_ufixed + D_ufixed) ; 

因为当你遵循规则时,结合性相同的表达式的大小最终会变大一点。虽然我在下面显示了括号,但它们是一样的。

signal Sum_ufixed11         : ufixed(10 downto 0) ; 
. . . 

Sum_ufixed11 <= ((A_ufixed + B_ufixed) + C_ufixed) + D_ufixed ; 

另请注意,这两个包都支持“+”[unsigned/ufixed,自然] return unsigned/ufixed,但是,自然参数不会影响大小。我对此的看法是 0 和 1 易于使用,但必须仔细检查其他值。如果整数被截断,则会出现警告,但在我看来,它可能应该是失败的(这与数组值发生的情况一致)。这当然可以在 IEEE 工作组中进行讨论(参见 http://www.eda-twiki.org/cgi-bin/view.cgi/P1076/WebHome)。