【问题标题】:Mic1, Micro-assembly language, creating a multiplierMic1,微汇编语言,创建乘法器
【发布时间】:2015-05-04 12:05:10
【问题描述】:

我目前正在使用微汇编语言 (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 或倒计时来跟踪它被添加在一起的次数。

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

【问题讨论】:

  • 您有条件转到负值或零值。您可以通过预加载寄存器并减 1 并检查是否为零来进行倒计时循环。
  • 你无处可藏,试图通过添加 A B 倍来增加 A * B。小数字是可以的,但较大的数字有很大的执行时间。尝试通过移位和加法来掌握二进制乘法。然后循环数将是操作数的位数。但是,如果您难以理解循环,请务必先解决此方法,然后再继续。

标签: assembly cpu cpu-architecture multiplication mic-1


【解决方案1】:

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

显而易见的答案

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

更好的方法

但是,当然,有一个解决方案。给定 a * b 的先前乘法,其中两个数字都是无符号和 32 位,b 可以描述为 b(i) * 2^(i)(0 b(i) * (a * 2^(i))(0

在 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. forif 不能 1: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 标志(零标志,如果 ALU 的输出为 0,则为 1)立即检查 b == 0
  2. 测试b &amp; 1 == 0是否必须分两步完成,所以我们使用寄存器H来存储一个1
  3. ALU 无法直接将 a 向左移动 1,但 a = a &lt;&lt; 1 只不过是 a = a + a,因为我们是二进制的
  4. ALU 可以直接将 b 右移 1 位

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多