为什么 dbra 对于摩托罗拉 68k 中非常大的循环计数如此之快?

Why is dbra so fast for a very large loop count in Motorola 68k?

我正在学习摩托罗拉68k汇编,我写了以下浪费时间的循环:

    move.l #0x0fffffff,%d0
    bsr timewaster
    rts

timewaster:
    dbra %d0,timewaster
    rts

这个浪费时间的循环几乎立即结束。我在调试器中逐步检查代码,以确保它确实将 d0 减到 0(确实如此)。然而,另一个浪费时间的循环需要永远完成:

    move.l #0x0fffffff,%d0
    bsr timewaster
    rts

timewaster:
    sub.l #1,%d0
    bne timewaster
    rts

那么为什么使用 dbra 的代码要快得多?

我在 TI-89 模拟器中 运行 这些。

虽然由于在真实处理器上的提取次数较少,会有一些改进,但在时间上存在如此大差异的原因是两种方法使用不同的大小。

来自程序员参考手册,在 DBcc 的页面上:

If the termination condition is not true, the low-order 16 bits of the counter data register decrement by one. If the result is -1, execution continues with the next instruction. If the result is not equal to -1,execution continues at the location indicated by the current value of the program counter plus the sign-extended 16-bit displacement.

所以,DBcc指令只操作和检查循环计数寄存器的低位字。因此,SUBBcc 版本将比 DBcc 版本花费大约 4000 倍的时间。如果您使用 SUB.W 而不是 SUB.L,我希望您得到更多相似的 运行 次。

DBcc指令将执行0x10000次,而BNE指令将执行0xFFFFFFF次。

请注意,如果循环计数器的高位字不受DBcc影响,那么您的循环应该在 D0 中以 0x0FFFFFFF 退出。 SUB.L/BNE 版本应该以 D0 中的 0 退出。


这与问题没有特别的关系,但通读手册,在某些地方似乎对 DBcc 指令的确切行为存在轻微分歧。具体来说,当条件为真时循环计数器为 0 时的行为。两者都导致分支不被采用,但他们不同意循环计数寄存器中的最终结果。

The Programmer's Reference Manual, Revision 1 (M68000PM/AD, REV. 1)表示条件为真优先,循环计数器的递减值不回存,寄存器中留0 .以下内容来自手册:

If Condition False
    Then (Dn - 1 -> Dn; If Dn != -1 Then PC + d_n -> PC)

The M68000 Microprocessors User's Manual, Ninth Edition (MC68000UM), Appendix A (MC68010 Loop Mode Operation), 说减一结果优先,结果为-1导致结果被存储返回,在寄存器中留下 -1。以下是根据手册中的描述构建的:

If Dn - 1 == -1
    Then Dn - 1 -> Dn
Else
    If Condition False
        Then (Dn - 1 -> Dn; PC + d_n -> PC)

通常情况下,由于计数而退出会留下 -1,而条件退出会留下不同的值(假设计数器不是从 0xFFFF 开始)。当两者都为真时,这两个来源不同意寄存器中的值。

我假设 PRM 是正确的,是该行为的权威来源,并且因为它与 UM 之前的描述相匹配,但 UM 可能暗示指令是如何实现的,至少在MC68010.