【问题标题】:Delay Loop in 68k Assembly68k 组装中的延迟循环
【发布时间】:2021-06-09 16:35:12
【问题描述】:

我想在汇编中编写一个延迟循环。它会造成N 个周期的延迟。

我的想法是创建一个 for 循环并遍历 NOP 指令。在这种情况下,我是否必须将 N 减少由程序其他部分引起的循环数,例如调用 for 循环?另外,for循环的每次迭代算1个循环还是2个循环?

在最好的情况下 - 有没有人实现这样的延迟周期?

【问题讨论】:

  • 何不试试看?
  • 每条汇编语言指令都需要时间。因此,如果这将是代码中某个其他位置调用的函数,则子程序调用和返回完成的堆栈推送和弹出肯定需要考虑到时间常数。
  • 这取决于微架构的细节,比如 68000 与 68010 的 2 指令循环缓冲区。与带有 I-cache 的 68020 相比。 en.wikipedia.org/wiki/Motorola_68000_series#Improvement_history。与具有 2 宽超标量流水线(每个周期 2 条指令)的 68060 相比。
  • 一种显而易见的调查方法是从较旧的 linux 内核中检查 68k bogomips 循环。 :-)
  • 只需一个dbf d0,$-2 就可以完成这项工作。根据wiki.neogeodev.org/…,每次迭代需要 10 个周期。

标签: assembly delay 68000 easy68k


【解决方案1】:

没有 68k 指令可以在一个周期内执行。即使是一个简单的 NOP 也需要四个周期 - 所以你需要稍微调整一下你的期望。

可以想象的最简单的延迟循环是

       move.w #delay-1,d0
loop:  dbf    d0,loop       ; 10 cycles per loop + 14 cycles for last 
                            ; (branch not taken) 

这将延迟 delay * 10 个周期。请注意,delay 是字大小的,因此该构造仅限于 14 到 655354 个周期之间的延迟。如果您想要更广泛的范围,则需要使用使用长字计数器的不同结构:

       move.l  #delay,d0
       moveq.l #1,d1
 loop: sub.l   d1,d0        ; 6 cycles for Dn.l->Dn.l
       bne.s   loop         ; 10 cycles for branch

每次迭代需要 16 个周期。但是,它确实接受长字循环计数器。

如果您想增加可实现的延迟,您可以考虑嵌套延迟循环或更复杂的指令和循环内的寻址模式。然而,这两个是最短的可能延迟循环。

【讨论】:

  • 我假设这些时序来自 68000 本身,不考虑 68010 上的循环缓冲区或 68020 上的 I-cache。这也提出了 Easy68k 是否是周期精确模拟器的问题。 (如果您正在尝试编写一个以恒定速度运行的游戏,那么客户周期是否对应于实时,或者是否仍然取决于主机速度。也许@spadel 知道使用 Easy68k 的答案。)
  • @PeterCordes 这些示例使用原始的 68k 周期时序,就像 easy68k 一样。 easy68k 并不声称是周期精确的,但它确实会跟踪(计数)真实 CPU 在程序中花费的周期数。
  • 我认为sub.l d1,d0 需要8 个周期(与subq.l #1,d0 相同)
  • @chtz 嗯。我的手册说“6”。 (原版68000程序员参考手册)
  • 这里的表 8-4 nxp.com/docs/en/reference-manual/MC68000UM.pdf 有一个注释 **,上面写着“如果有效地址模式是寄存器直接或立即,则六个时钟周期的基本时间增加到八个”。此处信息相同:wiki.neogeodev.org/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
  • 2014-11-10
  • 2016-08-18
  • 1970-01-01
相关资源
最近更新 更多