为什么 ARM7 上 MUL 表达式的前两个参数不能相同?

Gar*_*ary 4 assembly arm multiplication arm7

我一直在帮助实验室进行 ARM7 汇编语言课程,今天遇到一个问题,学生输入了以下表达式:

MUL R0, R0, R1
Run Code Online (Sandbox Code Playgroud)

该代码未编译。解决方案是将表达式更改为:

MUL R0, R1, R0
Run Code Online (Sandbox Code Playgroud)

即MUL的前两个参数不能是同一个寄存器。我已经知道这一点,因为它是 ARM 文档的一部分: http ://infocenter.arm.com/help/topic/com.arm.doc.dui0489i/DUI0489I_arm_assembler_reference.pdf

学生很高兴他们的问题得到了解决,但我很沮丧,因为我不知道为什么ARM7 要求这样传递参数。我认为这可能与乘法器移位和加法时用于存储中间值的寄存器之一有关,但我什至不确定乘法在 ARM 上是否是这样工作的(事实上,我相当清楚)当然不是)。为什么参数的顺序在这里如此重要?

Ros*_*dge 5

“在 ARMv6 之前的架构中, Rn必须与Rd不同”这一事实表明,这是原始三级 ARM 管道中如何实现乘法的设计限制。ARMv6 之前是指采用 ARM7 或更早设计的 CPU,这些 CPU 都使用简单的三级管道。与大多数指令不同,乘法需要多个周期来执行,并且根据指令集限制,您的怀疑似乎是正确的,目标寄存器Rd在每个周期都会被修改以计算结果。

Anthony Fox 的论文《验证 ARM6 乘法》通过图 4(下面重新格式化以适应 Stack Exchange 标记的限制)显示了在ARM6 内核执行乘法指令期间如何修改Rd来支持这一点:

  • t 3

    • 获取指令
    • 增加程序计数器
    • 设置mul1reg[Rs]
    • 设置borrow为假
    • 设置count1为零


    • 如果累加则设置reg[Rd]reg[Rn],否则为零

    • 设置mulmul1[1:0]
    • 设置mul2mul1[31:2]
    • 设置borrow2borrow
    • 设置mshiftMSHIFT2(borrow,mul,count1)
  • tn

    • 设置alubreg[Rm]左移mshift
    • 设置aluareg[Rd]
    • 设置mul1mul2[29:0]
    • 设置borrowmul[1]
    • 设置count1mshift[4:1] + 1


    • 设置reg[Rd]ALU6*(borrow2,mul,alua,alub)

    • 设置mulmul1[1:0]
    • 设置mul2mul1[31:2]
    • 设置borrow2borrow
    • 设置mshiftMSHIFT2(borrow,mul,count1)
    • 更新NZC标志CPSR(如果S设置了标志)
    • 如果是最后一次迭代则解码下一条指令

图 4:乘法指令的 ARM6 实现。每个周期分为两个阶段。重复t n 循环 直到当等于或十五时,MULX(mul2,borrow,mshift)寄存器Rd不更新。RdRm

由于reg[Rd]在初始设置周期t 3和重复的t n周期期间都被修改,因此如果“设置为左移”Rd == Rm步骤期望读取Rm的原始未修改值,而不是当前中间值,则结果将是垃圾存储在Rd中。aluareg[Rm]mshift

某些 ARM7 CPU 有一个“快速乘法器”,每个周期处理 8 位,而不是如上所述的每个周期处理 2 位,但它似乎也会在计算过程中修改寄存器。