【问题标题】:How to implement MUL using all the other instructions in assembly?如何使用汇编中的所有其他指令实现 MUL?
【发布时间】:2014-08-29 05:24:27
【问题描述】:

假设我已经在汇编机器中实现了所有的 ADD、AND、SHF、JUMP、BR、LDW、LDB(加载字加载字节...)........除了 MUL(多)指令。现在我想编写汇编代码来操作一条 MUL 指令,该指令接收存储在 0x4000(a) 和 0x4001(b)(每个 8 位)中的数据并计算它们的乘积,然后将结果存储在 0x4002(16 位)中。我们希望最小化指令步骤。

我能想到的:

  1. a+a+a+a+.....a(b 次) 最简单但显然最糟糕的一次

  2. Leftshift(a, 7) + leftshift(a, 6)+.....+a(按b移位加)

我想知道这个问题是否有更好的解决方案。 谢谢!

【问题讨论】:

  • 如果您有足够的内存,您可以使用查找表。
  • 总内存大小为0x8000。

标签: assembly


【解决方案1】:

总体思路与您(应该)在学校学习“长乘法”时所学的相同,只是我们使用二进制而不是十进制。考虑以下两个示例:

      1010        1234
    x 1100      x 2121
----------   ---------
      0000        1234
     0000        2468
    1010        1234
 + 1010      + 2468
 ---------   ---------
   1111000     2617314  

右边的例子是base-10(十进制),左边的例子是二进制。请注意,您必须乘以顶部因子的唯一数字是 0 或 1。乘以零很容易,答案始终为零,您甚至不必担心将其相加。乘以 1 也很容易,只需知道“将其转移多远”。但这很容易,只要您检查一下就可以了。

从您的号码的 16 位工作副本开始,并将 16 位累加器设置为零。将上面的数字移过来,只要最右边的数字有一个,您就可以将“工作副本”添加到累加器中。无论是 1 还是 0,您都需要将“工作副本”向左移动一位。当“顶部”变为零时,您就知道您已经完成并且答案在累加器中。

您可以使用一些优化,这样您就不需要那么多 16 位寄存器(或 8 位寄存器对),但我会让您自己解决细节问题。

【讨论】:

    【解决方案2】:

    您似乎正在使用类似于 8080、6502、6800 和类似产品的 8/16 位处理器。是的,8 次迭代循环的移位和添加就足够了,而且几乎是最优的。 OTOH,如果您有 1020 字节的常量表,则使用以下公式的方法可能是最快的方法:

    a*b = square(a+b)/4 - square(a-b)/4
    

    如果参数是无符号的,则 a+b 的最大值为 510。对于任何 x,您只需保留 x**2/4 的整数部分,因为公式中的小数部分会相互补偿;因此,映射为:0 -> 0, 1 -> 0, 2 -> 1, 3 -> 2, 4 -> 4, ..., 510 -> 65025。对于有符号参数,该表要小两倍.

    还有很多其他的快速乘法方法,包括几乎线性的成本;参见例如Donald Knuth 的“计算机编程艺术”传奇系列丛书,第 2 卷。但在 8 位参数的情况下,它们的开销太大了。

    【讨论】:

    • 哇,这是一个非常好的想法。这意味着我只需要构建一个长度为 255 的表。但问题是我不能执行“除 4”....
    • @ToHellWithGeorgi ZX Spectrum ROM Basic 有计算器,包括乘法、除法等等。在Z80 CPU 上实施。如果您找到注释的 ROM 源,或者如果您使用 ZX Spectrum 模拟器,您可以复制/粘贴该想法
    • @ToHellWithGeorgi 除法 4 是向右移动 2 次。因为 4 是 2 的 2 次方,所以可能复制/粘贴一个已经完成的库
    • @ToHellWithGeorgi 您不需要在代码中除以 4 - 它应该已经在表格值中完成。
    猜你喜欢
    • 1970-01-01
    • 2010-10-16
    • 2023-01-08
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    相关资源
    最近更新 更多