Je suis assez nouveau dans 68k et je me demandais s'il était possible d'appeler un sous-programme spécifique par des valeurs conservées en mémoire.
exemple de pseudo code:
move.w #2,X JSR routine(X)
et quelque part dans le code quelque chose comme:
X: dc.w 0 routine1: code rts routine2: more code rts
pour exécuter la routine2, ou move.w #1,X
avant pour la routine1
Je n'ai aucune idée et je ne trouve aucun exemple, je suppose que je dois créer une étiquette contenant les routines, puis utiliser un registre d'adresses pour sauter à l'offset spécifique mais je ne sais pas comment.
Toute aide serait la bienvenue!
3 Réponses :
Vous recherchez un JSR indirect qui prend l'adresse cible dans un registre, après avoir chargé le registre à partir d'un tableau d'adresses. (Cela fait longtemps que je n'ai pas fait de m68k, mais ce sont les mots-clés et les concepts que vous recherchez dans la référence du jeu d'instructions.) Mise à jour: voir le commentaire de @ chtz.
La recherche ne se fera pas par nom, vous devrez utiliser dc.l routine1, routine2
quelque part pour créer une table de pointeurs de fonction 32 bits.
(À moins que les deux / toutes les routines routine1 + <constant> * index
la même longueur et que vous routine1 + <constant> * index
une cible de saut dans un registre comme routine1 + <constant> * index
, en utilisant des instructions ALU au lieu d'indexer dans un tableau en mémoire. Un mode d'adressage pour JSR peut faire partie de ce calcul, par exemple jsr 4(a3)
met PC = A3 + 4).
OK donc après avoir chargé l'adresse de la table en ex. A3 Dois-je pouvoir déclencher la routine2 avec jsr 1 (A3)?
@KONEY: N'oubliez pas que dans l'assemblage, tout utilise des décalages d'octets. Vous voudriez donc jsr 4(A3)
, tout comme pour indexer un tableau d'entiers 32 bits. (Parce que les pointeurs sont des entiers 32 bits).
Oui bien sûr, ma faute!
jsr 4(A3)
appellerait la fonction commençant à l'adresse A3+4
. Vous voulez probablement movea.l 4(A3),A3; jsr (A3);
Si votre table de saut est à l'intérieur de votre code et que vous avez l'index en D0
, vous pouvez multiplier D0
par 4 en utilisant des décalages et utiliser l'adressage relatif au PC pour obtenir l'adresse de saut: lsl.w #2,D0; movea.l table(PC,D0.w),A3; jsr (A3);
Si vos routines sont dans le même binaire, vous pouvez même simplement stocker des décalages de 16 bits par rapport à une étiquette.
@chtz: Merci, choix de conception intéressant pour qu'un opérande non-registre pour JSR fasse un saut calculé avec le mode d'adressage au lieu du choix de x86 d'être un saut / appel indirect en mémoire qui charge l'adresse à partir de cet emplacement mémoire. Mis à jour un peu ma réponse, n'hésitez pas à modifier vous-même et à insérer votre suggestion de code réelle. Ou poster une réponse distincte et je la voterais.
Oui, jsr X
est essentiellement comme un lea X, PC
pas un move X, PC
(pour moi cela semble plus naturel, mais j'ai appris l'assembleur 68k bien avant d'apprendre x86, donc je suis un peu partial). L'autre méthode a certainement du sens aussi, mais ne correspondait probablement pas à d'autres décisions de conception - par exemple, les valeurs immédiates ne sont pas une adresse efficace valide (c'est pourquoi de nombreuses autres instructions ont des opcodes supplémentaires, comme andi
, addi
, etc. ) donc un autre opcode jmp
/ jsr
aurait été nécessaire pour coder les sauts vers des adresses absolues.
Je ne sais pas vraiment ce que OP veut ici. Si vous voulez littéralement:
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)
fais juste
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, ...
Si vous voulez décider à une partie du code d'appeler ultérieurement routine1
ou routine2
, je chargerais cette adresse dans un registre d'adresses et l'appellerais chaque fois que vous en avez besoin (dans la plupart des cas, vous ne devriez pas manquer de registres d'adresses - mais vous devez soigneusement garder une trace du registre que vous utilisez dans quelles parties de votre code)
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
Si vous avez une variable (en mémoire ou à l'intérieur d'un registre) et que vous souhaitez appeler l'un des deux sous-programmes en fonction de sa valeur, effectuez un branchement comme:
; under some condition: lea routine1(PC),a4 ; under another condition: lea routine2(PC),a4 ; later: jsr (a4)
Si more code
n'est qu'un rts
, remplacez bne.s \callr2
par bne routine2
et bsr routine1
par bra routine1
(c'est-à-dire un appel de queue).
Troisième alternative, si vous avez une plage de valeurs dans d0
et que vous souhaitez vous d0
à une méthode spécifique en fonction de cette valeur, ce serait une table de saut, qui peut être implémentée comme ceci (en supposant que toutes les routines sont dans une plage d'adresses de 16 bits - vous devez également vérifier que d0
ne contient pas de valeur en dehors de la taille de votre jumptable):
bsr routine2
Si de plus, toutes les routines sont exactement de la même taille (idéalement une puissance de deux - peut-être après un rembourrage, ou en utilisant des trampolines si nécessaire), vous pouvez également passer directement à quelque chose comme PC+offset+d0*size_of_method
:
move #2,X jsr "routine(X)"
C'est ainsi que j'ai fini par faire cela, en combinant la solution Peter Corder avec quelques suggestions externes:
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#
- dans la boucle principale -
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
où P61_LAST_POS étant un index incrémental qui change avec des périodes de temps.
De cette façon, j'ai un contrôle de ce qui est exécuté à un moment donné en éditant simplement la LUT "TIMELINE".
Au lieu de modifier une réponse dans votre question, vous devez soit accepter une réponse donnée, soit fournir votre propre réponse (ce que vous pouvez éventuellement accepter également). Aussi, votre solution permet plusieurs optimisations ...