3

我目前正在使用微汇编语言 (MAL) 并使用 Mic1mmv 模拟器对其进行测试。我试图弄清楚如何制作一个将两个数字相乘的程序,但我正在努力弄清楚如何做到这一点。

下面是加减法的 MAL 代码:

iadd1   MAR = SP = SP - 1; rd       // Read in next-to-top word on stack
iadd2   H = TOS                     // H = top of stack
iadd3   MDR = TOS = MDR + H; wr; goto Main1 // Add top two words; write to top of stack

isub1   MAR = SP = SP - 1; rd       // Read in next-to-top word on stack
isub2   H = TOS                    // H = top of stack
isub3   MDR = TOS = MDR - H; wr; goto Main1 // Do subtraction; write to top of stack

例如,假设我想做 3 x 4。我这样做的想法是取 3 并将其与另外 3 相加 4 次(3+3+3+3),但我还没有弄清楚如何我可以制作一个 if/else/loop 或倒计时来跟踪它被添加在一起的次数。

如果有人知道如何解决这个问题或对此有任何提示,我将非常感激,谢谢!

4

1 回答 1

5

我知道这个问题有点老了,但也许我仍然可以帮助其他试图理解这个问题的人。

明显的答案

给定一个乘法a * b。如您所料,首先想到的明显答案就是计算b + b + b + b + [...]。事实上这是一种正确的方法,虽然现在需要的计算周期完全取决于 b,所以 b 越大,这种方法计算所需的时间就越长。

更好的方式

但是,当然,有一个解决方案。鉴于前面a * b两个数字都是无符号和 32 位的乘法,b 可以描述为b(i) * 2^(i)(0 <= i <= 32) 的总和。现在,如果我们将它与 a 相乘,我们得到b(i) * (a * 2^(i))(0 <= i <= 32)。所以用文字来解释它,我们遍历每个位并将它们对应的二进制值相乘。结果现在只是每个计算的总和。这使我们最多可以进行 32 次计算。

在 C 代码中看起来像这样:

unsigned multiply(unsigned a, unsigned b) { 
    unsigned i, product = 0;
    for (i = 0; i < 32; ++i) {
        if ((b & 1) == 1) { 
            product = product + a;
        }
        a = a << 1;
        b = b >> 1;
    } 
    return product;
}

但是这段代码目前还不能翻译成微指令。

  1. for不能if1:1翻译
  2. 我们受到 ALU 能力的限制,即移位操作
  3. ALU 只能产生数字 0、1 和 -1

在接下来的第二个方法中,我们将 for 循环替换为 while 循环。这是可能的,因为我们每次通过移位使 b 减半,所以 b 在某一点必须等于 0。明确在 32 个班次之后。

unsigned multiply(unsigned a, unsigned b) { 
    unsigned product = 0;
    while (b != 0) {
        if ((b & 1) == 1) { 
            product = product + a;
        }
        a = a << 1;
        b = b >> 1;
    }
    return product;
}

现在我们可以替换更高的控制结构,比如while循环:

unsigned multiply(unsigned a, unsigned b) { 
    unsigned product = 0;
loop:
    if (b == 0) goto finish;
    if ((b & 1) == 0) goto next; 
    product = product + a;
next:
    a = a << 1;
    b = b >> 1;
    goto loop;
finish:
    return product; 
}

现在我们可以开始将它投射到 mic-1 上。

  1. 变量 a 在堆栈上的变量 b 下。因此,我们首先必须启动一个读取指令。这意味着 a 将在 MDR 寄存器中。
  2. 变量 b 在栈顶。这意味着它的值已经在寄存器 TOS 中。
  3. 为了保存和更新最终结果,我将其命名为“产品”,我们留下了寄存器 OPC,因为它是唯一没有限制的其他寄存器

我们还必须将所有操作投射到 mic-1 上。

  1. 可以通过查看 Z 标志立即检查 b == 0(零标志,如果 ALU 的输出为 0,则为 1)
  2. 测试 ifb & 1 == 0必须分两步完成,所以我们使用寄存器 H 来存储 1
  3. ALU 无法直接将 a 向左移动 1 位,但a = a << 1仅此而已a = a + a,因为我们是二进制的
  4. 将 b 向右位移 1 可以直接由 ALU 完成

有了所有这些,让我们看看我们在哪里:

unsigned multiply(unsigned mdr, unsigned tos) { 
    unsigned z, h, opc = 0;
loop:
    z = tos;
    if (z == 0) goto finish; h = 1;
    z = tos & h;
    if (z == 0) goto next;
    h = mdr;
    opc = opc + h; 
next:
    h = mdr;
    mdr = mdr + h; tos = tos >> 1; goto loop;
finish:
    return opc;
}

现在我们可以直接把它翻译成一个微汇编程序:

imul1  | MAR = SP = SP - 1; rd
imul2  | OPC = 0
loop   | Z = TOS; if (Z) goto finish; else goto imul4 
imul4  | H=1
imul5  | Z = TOS AND H; if (Z) goto next; else goto imul6 
imul6  | H = MDR
imul7  | OPC = OPC + H
next   | H = MDR
imul9  | MDR = MDR + H
imul10 | TOS = TOS >> 1; goto loop
finish | MDR = TOS = OPC; wr; goto Main1
于 2021-06-12T17:17:25.693 回答