问题描述
我对于68k还是很陌生,我想知道是否可以通过内存中的值调用特定的子例程。
伪代码示例:
X: dc.w 0
routine1:
code
rts
routine2:
more code
rts
在代码中的某处类似:
move.w #2,X
JSR routine(X)
要执行例程2,或者将move.w #1,X
用于例程1
我不知道,也找不到任何示例,我的猜测是制作一个包含例程的标签,然后使用地址寄存器跳转到特定偏移量,但是不知道如何。
欢迎任何帮助!
解决方法
您正在寻找一个间接 JSR,该JSR在从地址数组中加载寄存器后将目标地址存储在寄存器中。 (自从我做过m68k以来已经有很长时间了,但是这些是您在指令集参考中寻找的关键字和概念。)更新:请参阅@chtz的注释。
查询将不会按名称进行,您必须在某个地方使用dc.l routine1,routine2
来制作32位函数指针的表。
(除非两个/所有例程的长度都相同,并且您使用某些ALU指令而不是索引到内存中的数组中,而是在诸如routine1 + <constant> * index
之类的寄存器中计算跳转目标。JSR的寻址模式可以是计算的一部分;例如jsr 4(a3)
设置PC = A3 + 4)。
我不太确定OP在这里想要什么。如果您真的想要:
move #2,X
jsr "routine(X)"
只要做
bsr routine2
如果您想确定代码的某个部分是稍后再调用routine1
还是routine2
,我将把该地址加载到地址寄存器中,并在需要时调用它(在大多数情况下) ,您不应缺少地址寄存器-但您必须仔细跟踪在代码的哪个部分中使用哪个寄存器)
; under some condition:
lea routine1(PC),a4
; under another condition:
lea routine2(PC),a4
; later:
jsr (a4)
如果您有一个变量(在内存中或在寄存器中),并且想根据其值调用两个子例程之一,请执行一些分支操作,例如:
tst.w d0 ; lets assume for d0==0 we call routine1,otherwise routine2
bne.s \callr2
bsr routine1
bra.s \continue
\callr2:
bsr routine2
\continue:
; more code
如果more code
只是rts
,则将bne.s \callr2
替换为bne routine2
,将bsr routine1
替换为bra routine1
(即尾注)。 / p>
第三种选择,如果d0
中有一个值范围,并且您想根据该值跳转到一个特定的方法,那将是一个跳转表,可以像这样实现(假设所有例程位于16位地址范围内-您还需要验证d0
所包含的值是否不超出跳转表的大小):
add.w d0,d0 ; multiply d0 by two
move.w jumptable(PC,d0.w),d0 ; d0 contains the offset relative to `jumptable`
jsr jumptable(PC,d0.w) ; do the actual function call
; more code -- if this is just a `rts` use `jmp` instead of `jsr`
; somewhere else:
jumptable:
dc.w routine0-jumptable,routine1-jumptable,routine2-jumptable,...
如果另外,所有例程的大小都完全相同(理想情况下为2的幂-可能是经过一些填充,或者在必要时使用一些蹦床),您也可以直接跳到类似PC+offset+d0*size_of_method
的地方:>
lsl.w #4,d0 ; d0 = 16*d0
jsr routine0(PC,d0.w) ; PC = routine0+d0
; more code
routine0:
; exactly 16 bytes of code
routine1:
; exactly 16 bytes of code
routine2:
; exactly 16 bytes of code
routine3:
; (last method could be arbitrary long)
,
这就是我最终将Peter Corder解决方案与一些外部建议结合起来的方法:
TIMELINE: DC.L __BLOCK_0,__BLOCK_1,__BLOCK_1
DC.L __BLOCK_2,__BLOCK_2
DC.L __BLOCK_2,__BLOCK_3 ... etc
__BLOCK_0:
; SOME CODE
RTS
-在主循环中-
MOVE.W P61_LAST_POS,D5
LEA TIMELINE,A3
MULU.W #4,D5 ; OFFSET IN BYTES
MOVE.L (A3,D5),A4
JSR (A4) ; EXECUTE SUBROUTINE BLOCK#
其中P61_LAST_POS是增量索引,它随时间变化。
通过这种方式,我只需编辑LUT“时间轴”即可控制在任何给定点执行的操作。