1
votes

Appel du sous-programme par valeur dynamique

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!


1 commentaires

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 ...


3 Réponses :


1
votes

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).


6 commentaires

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.



1
votes

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)"


0 commentaires

0
votes

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".


0 commentaires