为什么 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
指令只操作和检查循环计数寄存器的低位字。因此,SUB
和 Bcc
版本将比 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.
我正在学习摩托罗拉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
指令只操作和检查循环计数寄存器的低位字。因此,SUB
和 Bcc
版本将比 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.