通过动态值调用子程序
Call subroutine by dynamic value
我是 68k 的新手,我想知道是否可以通过内存中保存的值调用特定的子例程。
伪代码示例:
X: dc.w 0
routine1:
code
rts
routine2:
more code
rts
代码中的某处类似:
move.w #2,X
JSR routine(X)
执行 routine2,在 routine1
之前 move.w #1,X
我不知道也找不到任何示例,我的猜测是制作一个包含例程的标签,然后使用地址寄存器跳转到特定的偏移量,但不知道如何实现。
欢迎任何帮助!
您正在寻找一个 indirect JSR,它在从地址数组加载寄存器后在寄存器中获取目标地址。 (自从我做任何 m68k 以来已经有很长时间了,但这些是您在指令集参考中寻找的关键字和概念。)更新:请参阅@chtz 的评论。
查找不会按名称进行,您必须在某处使用 dc.l routine1, routine2
来制作 table 的 32 位 函数指针 .
(除非 both/all 例程长度相同,并且您在寄存器中计算跳转目标,如 routine1 + <constant> * index
,使用一些 ALU 指令而不是索引到内存中的数组。寻址模式对于 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
(即尾调用) .
第三种选择,如果您在 d0
中有一个值范围并且您想根据该值跳转到特定方法,那将是一个跳转-table,它可以是像这样实现(假设所有例程都在 16 位地址范围内——您还需要验证 d0
不包含超出跳转大小的值 table):
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 的幂——可能在一些填充之后,或者必要时使用一些 trampoline),您也可以直接跳转到类似 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“TIMELINE”来控制在任何给定点执行的内容。
我是 68k 的新手,我想知道是否可以通过内存中保存的值调用特定的子例程。
伪代码示例:
X: dc.w 0
routine1:
code
rts
routine2:
more code
rts
代码中的某处类似:
move.w #2,X
JSR routine(X)
执行 routine2,在 routine1
之前move.w #1,X
我不知道也找不到任何示例,我的猜测是制作一个包含例程的标签,然后使用地址寄存器跳转到特定的偏移量,但不知道如何实现。
欢迎任何帮助!
您正在寻找一个 indirect JSR,它在从地址数组加载寄存器后在寄存器中获取目标地址。 (自从我做任何 m68k 以来已经有很长时间了,但这些是您在指令集参考中寻找的关键字和概念。)更新:请参阅@chtz 的评论。
查找不会按名称进行,您必须在某处使用 dc.l routine1, routine2
来制作 table 的 32 位 函数指针 .
(除非 both/all 例程长度相同,并且您在寄存器中计算跳转目标,如 routine1 + <constant> * index
,使用一些 ALU 指令而不是索引到内存中的数组。寻址模式对于 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
(即尾调用) .
第三种选择,如果您在 d0
中有一个值范围并且您想根据该值跳转到特定方法,那将是一个跳转-table,它可以是像这样实现(假设所有例程都在 16 位地址范围内——您还需要验证 d0
不包含超出跳转大小的值 table):
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 的幂——可能在一些填充之后,或者必要时使用一些 trampoline),您也可以直接跳转到类似 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“TIMELINE”来控制在任何给定点执行的内容。