std_logic_vector 与浮点数的乘法

Multliplication of std_logic_vector with Floating Point

我有 32 位 std_logic_vector 信号并想将其乘以浮点数。

例如

     signal Input : std_logic_vector (31 downto 0 );
     signal number = 0.2 ;
     signal Output: std_logic_vector (31 downto 0 ); 
     Output <= 0.2 * Input ;

做这种乘法的最佳解决方案是什么?我在某处读到浮点算术运算不可综合,因此最好使用定点数。怎么做?

如果有人能告诉我进行这种操作的正确想法,我将不胜感激。

谢谢

"best" 解决方案取决于您需要的精度和您可以负担的资源(逻辑与 DSP)。使用浮点数需要将 input 转换为浮点数,在此过程中最多丢失 8 位,进行乘法并转换回来。花了很多钱,你问我也太贵了。

使用定点非常简单。将 number 乘以 2^N,四舍五入,用它乘以 input,然后将结果除以 2^N。以N=8为例:

number = 0.2
number_fixed = round(0.2*2^8) = 51
output = floor(51*input/2^8) -- If you add 2^N-1 before floor, you reduce your error

That last comment is because floor(m + 0.5) = round(m),这样做通常很便宜,尤其是在 Xilinx 中,因为它们的乘法器也有嵌入式 adder/accumulator.

不动点的问题是错误。我们乘以 51/256 而不是 0.2,产生 0.00078125 的差异。如果 input1000000,那么提交的错误是 781。这可以通过使用更大的 N 来修复,这会花费更多的硬件。此外,0.2 没有二进制的封闭形式:0.2 = 0.0011001100110011...。同样的问题顺便影响浮点

第三种解决方案是使用除以 5 的除法器。这将花费大约 32 个 3 位加法器,具体取决于算法,这确实不是那么糟糕。它还为您提供了完整的精度,即仅在 lsb 上出现错误。 Xilinx 有可用的除法内核。

更新

如果我的定点解释不清楚,我很抱歉,我承认我不确定最好的解释方式。

首先,不要按 10 或任何其他非 2 的幂进行缩放。虽然没有错,但您通常必须 multiply/divide 比例因子,这对于 2 的幂是微不足道的,但对于其他数字则不然。

首先考虑理论。假设您有实数 ab,您应该看到:

a * b = c
a*2^N * b*2^M = d = c * 2^(N+M)

因此,如果您在乘法之前缩放 2 个数字,它只会通过另一个缩放因子更改结果。这是定点运算的基础,缩放操作数并跟踪输出的缩放。但是,我们只对整数进行运算,因此我们不使用 abcd,而是使用这些值的截断、四舍五入或近似版本:

round(a*2^N) * round(b*2^N) = e approx d approx round(c*2^(N+M))

在后续的计算中,你保持e。当您需要取回实数时,通常在解释数据时在 FPGA 外部,您会将 e 除以 2^(N+M)。当然,你通过使用定点(或浮点)犯了一个错误,它等于 c - e/2^(N+M),使用更大的 NM 会减少错误。

回到您的示例,使用 2^8 的缩放比例。无论你在哪里乘以 0.2,你都会乘以 51 (round(0.2*2^8))。你的结果将按 2^8 缩放,如果你想保持这种方式或缩放到另一个缩放因子(如 2^0),这取决于你。