【问题标题】:How does the algorithm for an 8-by-8-bit multiplier look like?8×8 位乘法器的算法是什么样的?
【发布时间】:2013-11-10 17:18:10
【问题描述】:

老师给我们一个作业,让我们编写一个程序,将 2 个 8 位长度的数字相乘。我们的微控制器仅支持 8 位寄存器,因此必须将结果放入 2 个寄存器中。这就是我卡住的地方。

要将这两个数字相乘,我必须将其中一个向左移动。而且我不知道该怎么做,因为当向左移动时,只剩下进位位,我可以将数字粘贴到其中,但是当我必须移动不止一位时,进位-有点不够。

我也不明白如何添加这些数字。示例:

Number1:    Number2:
0000'0111 * 1111'1111
---------------------
            1111'1111
          1'1111'111<  The 1 number on the left would be outside the register.
         11'1111'11<<  The 2 numbers on the left would be outside the register.
         ------------
        110'1111'1001

这是纸上的方法。但是我该如何实现呢?

【问题讨论】:

  • 如果您将 8b x 8b 乘以结果也是 8 位,则有时会溢出(如您的示例中所示)。对此你无能为力。如果您可以监控架构上的进位位,则只需在这种情况下报告溢出即可。
  • 是的,这是一种方式。但是我们必须让它成为一个乘法器,它实际上能够乘以 8x8,然后得到一个 16 位的结果。这意味着结果必须在两个寄存器中,我不知道如何计算。
  • 你能在 4x4 乘法的多次传递中做到这一点吗?或者以某种方式翻译数字并像二进制编码的十进制一样处理它?即:您似乎与想要在 32 位处理器上做 64 位数学的人有同样的问题。它是可行的,只是速度慢。
  • 我刚刚得到了我们必须这样做的信息,如下所示: Number1:只有 1 个寄存器 Number2:2 个寄存器,Number2_Low 和 Number2_High 现在做起来容易多了。我想我已经有了解决方案。非常感谢,我现在有了。
  • 每个处理器都有一个左移指令,将进位移到第 0 位。即使是低端的 8051,例如 RL 与 RLC。

标签: assembly


【解决方案1】:

步行方式如下。调用两个寄存器 R_h 和 R_l,并初始化为 0。创建一个掩码 M_l := 0x01。调用被乘数寄存器x,乘数寄存器y。您还将使用寄存器 R_t.. 然后,在伪代码中:

(0) 设置 i = 0, j =8 

(1) 迭代 8 次 (i)

(2) 如果 (and x, M_l) == 0,则转到 (8)

(3)(a) sll y, i, 并保存在 R_t 中

(3)(b) 添加R_l,R_t,并保存在R_l中

(4) 如果进位位未设置,则转到(6)

(5) 加 R_h, 1

(6) srl y, j 并存储在 R_t 中。这就是您从调整位置推入 R_h 的内容(保持 y 中的值不变)。

(7) 添加 R_h、R_t 并存储在 R_h 中(您的中间结果现在是正确的)。

(8) i++, j--

(9) sll M_l, 1

(10) 跳转 (1)

我很容易出错;但原则上,这应该有效。可能有一个标准算法,但这就是我想到的。

【讨论】:

  • 这是针对原始问题的,x 和 y 均为 8 位;通过 res_h 和 res_l 得到 16 位。
  • 这对我来说有点难以理解,但我会尝试一下。在(3)中,什么是“sll”?
  • 逻辑左移 i 位数。它以我知道的所有语言实现。只需直观地查看它:您需要添加一些位'好像没有溢出' - 如果有,请在更高的寄存器中再添加一个(“到它的左边”)(并查看要添加哪个轮,你需要sll);并且,在每次迭代中,需要将乘法器的最右边的 i 位添加到更高的寄存器(第一次:0;下一次:最高;然后是最高的两个,等等),并且 srl 会这样做。该算法仅描述您在示例中写下的内容。
  • 您可以阅读更多关于 sll/rll here 的信息。忽略“逻辑”(还有算术移位类型,但大多数时候(例如,称为 sla),您会看到“l”类型。
【解决方案2】:

请注意,当您将 X 添加到 (X

因此,当您需要添加时

  |ABCDEFGH
 A|BCDEFGH0  <-- the value shifted by 1, A doesn't fit in the 8-bit registers
 ----------
 c|xxxxxxxH  <-- you have the last bit 

将其转换为:

      |0ABCDEFG (H) is shifted out, that's one more correct bit of the result
      |ABCDEFGH
     ----------
 (C) + xxxxxxxx  <-- you get 8 bit of result + Carry

重复这 8 次将导致 8 个最低有效位移出,并将结果的 8 个最高有效位存储在累加器中。在每一轮中,进位实际上会替换上一行的“0”:

     Partial sum = (c) | xxxxxxxX

     Shift PS >> 1 -->  Partial sum = cxxxxxxx | C <= X

这当然依赖于正确实现的架构(存在通过进位指令的右循环)。

另一个选项包括将操作数拆分为部分,这些部分可以在本机相乘而不会溢出。给定一个可以容纳任何值 0

    78 * 65 == 7*6 (*10^2) + 7*5 * (10^1) + 8*6 * (10^1) + 8*5

在微控制器中乘以(小)数的选项包括 x^2 表:

a*b = ((a+b)^2 - (a-b)^2) / 4 =
      ((a+b / 2)) ^ 2 - ((a-b)/2)^2 + A,
      where A an adjustment term just too difficult to remember, but possible
      to derive if needed.

【讨论】:

    【解决方案3】:

    我以某种方式解决了它,并且它有效。真的很抱歉,我不能使用你的答案,我还是个新手,你写的很多东西都不懂。

    我的解决方案:

    Main:   
    
    IN      Number1, SWITCH
    IN      Number2_L, SWITCH2
    CLR     Number2_H
    CLR     Product_L
    CLR     Product_H
    Loop:   TST     Number1  ; Number1 > 0 ?
            BREQ    JEnd     ; If not, jump to JEnd
            LSR     Number1  ; Logical Shift Right to Carry
            BRCC    JNoC     ; If Carry not set, then jump to JNoC
            ADD     Product_L, Number2_L
            ADC     Product_H, Number2_H
    JNoC:   LSL     Number2_L   ;Logical Shift Left to Carry
            ROL     Number2_H   ;Rotate Left through/from Carry
            RJMP    Loop        
    JEnd:   OUT     LED, Product_L
            OUT     LED2, Product_H
            RJMP    Main      ; Infinite loop
    

    注意:

    添加是 Rd

    ADC 是 Rd

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多