我知道这个问题有点老了,但也许我仍然可以帮助其他试图理解这个问题的人。
明显的答案
给定一个乘法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;
}
但是这段代码目前还不能翻译成微指令。
for
不能if
1:1翻译
- 我们受到 ALU 能力的限制,即移位操作
- 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 上。
- 变量 a 在堆栈上的变量 b 下。因此,我们首先必须启动一个读取指令。这意味着 a 将在 MDR 寄存器中。
- 变量 b 在栈顶。这意味着它的值已经在寄存器 TOS 中。
- 为了保存和更新最终结果,我将其命名为“产品”,我们留下了寄存器 OPC,因为它是唯一没有限制的其他寄存器
我们还必须将所有操作投射到 mic-1 上。
- 可以通过查看 Z 标志立即检查 b == 0(零标志,如果 ALU 的输出为 0,则为 1)
- 测试 if
b & 1 == 0
必须分两步完成,所以我们使用寄存器 H 来存储 1
- ALU 无法直接将 a 向左移动 1 位,但
a = a << 1
仅此而已a = a + a
,因为我们是二进制的
- 将 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