vhdl - 二进制定点乘法

标签 vhdl fpga multiplication signed fixed-point

我正在实现一个 VHDL 8 位定点乘法模块,它返回一个 8 位截断数,但是当我手动进行乘法以测试它时遇到了问题。当我想将两个负数相乘时,问题就出现了。

我尝试将两个正值相乘 1.67 * 0.625 ~ 1.04(二进制乘法为 0.906)。

001.10101 -> 1.67
000.10100 -> 0.625
------------
000000.1110111010 = 000.11101 (truncated to 8bits = 0.906)

我尝试将负数和正数相乘 (-0.875 * 3 ~2.62)

111.00100 -> -0.875
011.00000 -> 3
----------
010101.0110000000 = 101.01100 (truncated to 8bits = -2.625)

目前一切正常。当我尝试将两个负数相乘时,问题就来了。据我所知(除非我记错了): - 将两个数字相乘将得到两倍分辨率的结果(将两个 8 位数字相乘得到一个 16 位数字) - 固定点也会错位。在此示例中,固定点之前有 3 位,之后有 5 个点。这意味着在结果数中,定点将在点之前有 6 位数字,在点之后有 10 位。

假设上述计算正常进行。但是当我尝试将两个负值相乘时 (-0.875 * -1.91 ~ 1.67)

110.00010 -> -1.91 (1.9375)
111.00100 -> -0.875
------------
101011.0011001000 = 011.00110(truncated to 8 bits = 3.1875)

自然地,我尝试了另一个负乘法(-2.64 * -0.875 = 2.31)

101.01011 -> -2.64
111.00100 -> -0.875
----------
100110.0001001100 = 110.00010 (truncated to 8bits = -1.9375)

很明显我做错了什么,但我就是看不出我做错了什么。

PS:我还没有实现。我想到了我要怎么做,然后我尝试用一​​些简单的例子手工测试它。而且我还尝试了更多的乘法。我想也许他们成功了,因为我很幸运,但显然不是,我又尝试了几次乘法,他们成功了。所以也许我在将两个负数相乘时做错了什么,也许我把它截断了?大概。

编辑: 好的,我找到了一份 Xilinx 文档,其中说明了当两个操作数为负时如何进行乘法运算,here是链接。根据这个文件,为了这个文件,这只能在做扩展乘法时完成。并且乘法的最后部分和必须取反,然后加 1 才能得到正确的数字。

为了进行乘法运算,我在程序员模式下使用了 Windows 的计算器,这意味着为了乘以 8 位,我将数字放入计算器中,然后得到结果并将其截断。如果它们适用于其他情况,则意味着 Windows 计算器正在进行直接乘法(按应有的方式添加所有部分和,而不是反转最后的部分和)。所以,这意味着为了获得真正的结果,我应该从最终结果中减去第一个操作数,然后将第一个操作数倒置 + 1

110.00010 -> -1.91 (1.9375)
111.00100 -> -0.875
------------
101011.0011001000
Which gave me the result: 000010.0111001000 = 010.01110(truncated to 8bits =2.43)

与另一个我得出的结果是 1.875。这些输出不是很好,但至少它们更接近我的预期。有没有其他更简单的方法来做到这一点?

最佳答案

您的中间结果是错误的,因此截断没有按预期进行。此外,如果中间结果的四个最高位在您的格式中相等,则只有在没有溢出的情况下才能截断。 您应该使用带符号的数据类型来进行正确的乘法运算。

即使你的第二个例子也是错误的。中间二进制结果 010101.0110000000 表示十进制数 21.375,它不是 -0.875 和 3 的乘积。因此,让我们手动进行乘法运算:

    a     *     b      = -0.875 * 3 = -2.625
111.00100 * 011.00000
---------------------
          .  00000000  // further lines containing only zeros have been omitted
+         .01100000
+      011.00000
+     0110.0000
+   110100.000         // add -(2^2) * b  !
=   111101.0110000000  = -2.625  (intermediate result)
=      101.01100       = -2.625  after truncation

您必须在最后的部分和中添加 b 的二进制补码,因为 a 最高位中的“1”表示值 -(2 ^2) = -4。此处可以进行无溢出截断,因为中间结果的最高 4 位相等。

现在是第三个例子

    a           b      = -1.9375 * -0.875 = 1.6953125
110.00010 * 111.00100 
--------------------- 
          .  00000000  // further lines containing only zeros have been omitted
+   111111.111100100   // sign-extended partial-sum
+   111110.0100        // sign-extended partial-sum
+   000011.100         // add -4 * b
=   000001.101100100   = 1.6953125 (intermediate result)
~      001.10110       = 1.6875 after truncation

因为 b 是一个有符号数,所以总是将部分和符号扩展到中间结果的宽度。当然,在第二个例子的计算中也这样做了,但没有什么区别。

关于vhdl - 二进制定点乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35021806/

相关文章:

vhdl - Xilinx ISE block ram 推理的稳健性

调试VHDL : How to?

vhdl - 在 VHDL 中,数据类型转换与位数组操作的成本有多高?

VHDL 初学者 - 这个电路中的时序出了什么问题?

c++ - 乘以 float 给出无限值

vhdl - 右移和左移 (SLL/SRL)

vhdl - 中缀表达式 VHDL 中的歧义类型

vhdl - raise_edge() 与进程敏感度列表

algorithm - Lua:如何有效地乘以由数字组成的一维表中的所有元素

c++ - 如何在 x86 程序集中移动两个 float 相乘的结果?