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)。
各位!
拜托,你能给我解释一件奇怪的事吗? 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)。