68k汇编语言实现N时钟周期延迟的延迟循环问题咨询
68k汇编精确周期延迟循环实现说明
针对两个核心疑问的明确解答
- 疑问1:是否需要扣减循环控制逻辑、跳转指令的占用周期?
必须扣。68k所有指令、循环结构本身都是实打实占时钟周期的,这部分开销是直接从目标延迟N里扣减的,不算的话最终延迟肯定比你要的N大。好在经典68k没有指令缓存、每条指令的执行周期是完全固定的,不存在随机浮动,完全可以通过精确计算把这部分开销扣干净。 - 疑问2:for循环单次迭代本身占1还是2个时钟周期?
根本没有固定的1或2周期值,开销完全取决于你选的循环指令、寻址方式:- 用最常用的
DBRA配合数据寄存器当计数器时,没到最后一次迭代(计数器非零、跳回循环头),循环控制逻辑本身占2个时钟周期;到最后一次迭代(计数器减到0、退出循环)时,DBRA占3个时钟周期。 - 要是你自己写
CMP+BRA拼循环判断逻辑,单次迭代的控制开销能到4个周期以上,比专用循环指令贵得多。
- 用最常用的
可参考的精确周期延迟实现
下面的实现是基于基础款摩托罗拉68000架构(无缓存、指令周期完全固定)的,所有周期数都是对着官方指令手册核对过的:
- 基础模板代码:
; 固定周期延迟子程序,入口无额外前置操作 delay: move.w #COUNT_VAL, D1 ; 给循环计数器赋初值:4个时钟周期 loop: nop ; 空转指令:1个时钟周期 dbra D1, loop ; 循环控制 rts ; 子程序返回:16个时钟周期
- 总周期计算逻辑:
- 前面COUNT_VAL-1次的正常迭代:每次是
nop(1周期) +DBRA跳转成功(2周期) = 3周期/次 - 最后一次退出循环的迭代:
nop(1周期) +DBRA跳转失败退出(3周期) = 4周期 - 循环外的固定开销:
move.w初始化(4周期) +rts返回(16周期) = 20周期 - 汇总下来总周期 = 20 + 4 + 3*(COUNT_VAL -1) = 21 + 3*COUNT_VAL
- 参数适配方法:
- 要凑总N个时钟周期的延迟,直接套公式算COUNT_VAL = (N - 21)/3就行,前提是N大于最小延迟值——也就是COUNT_VAL取0的时候,总延迟是24周期,比这个小的N就没法用这个循环结构实现。
- 如果算出来有除不尽的余数,直接在循环体里插对应数量的
NOP凑数就行,一个NOP占1个周期,不影响循环结构。
- 避坑提醒:
- 循环计数器必须用片上的数据寄存器,别把计数器存在RAM里,不然内存访问的周期会飘,根本算不准。
- 要是你用的是68010、68020及后续型号,别直接套上面的公式,必须重新查对应型号的指令周期表,不同型号的
DBRA、RTS周期数和基础68000不一样。 - 延迟循环里别插会触发总线等待、中断响应的指令,不然周期会随机飘,达不到精确延迟的要求。
内容的提问来源于stack exchange,提问作者spadel
相关产品推荐
相关产品推荐

