Section courante

A propos

Section administrative du site

Conversion de code ARM en 68000

Cette page traite de la conversion de programmes écrits en assembleur ARM (architecture ARM7/ARMv4) vers l'assembleur Motorola 68000. L'ARM et le 68000 sont tous deux des microprocesseurs RISC/CISC 32 bits, mais leurs philosophies de conception diffèrent significativement : l'ARM est un microprocesseur RISC a ensemble d'instructions fixe de 32 bits avec exécution conditionnelle intégrée, tandis que le 68000 est un microprocesseur CISC a instructions de longueur variable.

Différences fondamentales entre ARM et 68000

Critère ARM (ARMv4) Motorola 68000
Type d'architecture RISC (load/store) CISC
Taille des instructions 32 bits (fixe) 16-80 bits (variable)
Registres généraux 16 (R0-R15) 8 données + 8 adresses
Registres d'adresse (inclus dans généraux) A0-A7 (séparés)
Taille des registres 32 bits 32 bits
Espace d'adressage 4 Go (32 bits) 16 Mo (24 bits)
Ordre des octets Bi-endian (souvent little-endian) Big-endian
Alignement mémoire Requis (mots sur 4) Mots sur adresses paires
Pile Décroissante (R13) Décroissante (A7)
Exécution conditionnelle Toute instruction Scc + Bcc seulement
Barrel shifter Intégré (opérande 2) Instructions séparées
Drapeaux (flags) N,Z,C,V (optionnel) X,N,Z,V,C (toujours)
Modes de privilège 7 modes (USR,SVC,..) 2 modes (user/super)
Coprocesseur flottant VFP/FPA (optionnel) 68881/68882 (séparé)
Instructions load/store LDR/STR seulement MOVE depuis/vers mémoire

Différences clefs pour la conversion :

Correspondance des registres

Registre ARM Equivalent 68000 Notes
R0 D0 Registre de travail / retour
R1 D1 Registre de travail
R2 D2 Registre de travail
R3 D3 Registre de travail
R4 D4 Variable préservée
R5 D5 Variable préservée
R6 D6 Variable préservée
R7 D7 Variable préservée
R8 A0 Variable préservée / pointeur
R9 A1 Variable préservée / pointeur
R10 A2 Variable préservée / pointeur
R11 (FP) A5 ou A6 Frame pointer
R12 (IP) A3 ou A4 Scratch / pointeur temporaire
R13 (SP) A7 (SP) Pointeur de pile
R14 (LR) (sur la pile) Adresse de retour
R15 (PC) PC Compteur ordinal
CPSR SR/CCR Registre d'état

Notes sur la correspondance :

Conversion des instructions de transfert

L'ARM utilise LDR/STR pour les accès mémoire et MOV pour les transferts entre registres. Le 68000 utilise MOVE pour tout.

ARM 68000
MOV R0, R1 MOVE.L D1, D0
MOV R0, #100 MOVEQ #100, D0 ; si -128..127 ou MOVE.L #100, D0
MOV R0, #0 CLR.L D0
MOV R0, #-1 MOVEQ #-1, D0
MVN R0, R1 MOVE.L D1, D0
NOT.L D0
MVN R0, #0 MOVEQ #-1, D0

Chargement depuis la mémoire :

ARM 68000
LDR R0, [R8] MOVE.L (A0), D0
LDR R0, [R8, #16] MOVE.L 16(A0), D0
LDR R0, [R8, R1] MOVE.L 0(A0,D1.L), D0
LDR R0, [R8, #16]! MOVE.L 16(A0), D0 ; pre-indexe
LEA 16(A0), A0 ; maj base
LDR R0, [R8], #16 MOVE.L (A0)+, D0 ; si offset=4
; sinon :
MOVE.L (A0), D0
LEA 16(A0), A0
LDRB R0, [R8] CLR.L D0
MOVE.B (A0), D0
LDRH R0, [R8] CLR.L D0
MOVE.W (A0), D0
LDRSB R0, [R8] MOVE.B (A0), D0
EXT.W D0
EXT.L D0
LDRSH R0, [R8] MOVE.W (A0), D0
EXT.L D0

Entreposage en mémoire :

ARM 68000
STR R0, [R8] MOVE.L D0, (A0)
STR R0, [R8, #16] MOVE.L D0, 16(A0)
STR R0, [R8, R1] MOVE.L D0, 0(A0,D1.L)
STR R0, [R8, #16]! MOVE.L D0, 16(A0)
LEA 16(A0), A0
STR R0, [R8], #16 MOVE.L D0, (A0)
LEA 16(A0), A0
STRB R0, [R8] MOVE.B D0, (A0)
STRH R0, [R8] MOVE.W D0, (A0)

Transferts multiples (LDM/STM) :

ARM 68000
LDMIA R8!, {R0-R3} MOVEM.L (A0)+, D0-D3
STMDB R13!, {R0-R3} MOVEM.L D0-D3, -(SP)
LDMIA R13!, {R0-R3} MOVEM.L (SP)+, D0-D3
PUSH {R4-R7, LR} MOVEM.L D4-D7, -(SP)
; LR est déjà sur la pile via BSR
POP {R4-R7, PC} MOVEM.L (SP)+, D4-D7
RTS

Note : LDM/STM de l'ARM avec différents modes d'adressage (IA=Increment After, IB=Increment Before, DA=Decrement After, DB=Decrement Before) se convertissent en MOVEM avec les modes(An)+ ou -(An) du 68000. Attention : MOVEM du 68000 ne supporte que (An)+ pour la lecture et -(An) pour l'écriture.

Chargement d'adresses :

ARM 68000
ADR R0, label LEA label, A0 ; ou LEA label(PC), A0
LDR R0, =valeur32 MOVE.L #valeur32, D0 ; (pas de bassin de constantes)

Note : ARM utilise souvent LDR Rn, =constante pour charger des constantes 32 bits depuis un bassin (littéral de bassin). Le 68000 charge directement les constantes 32 bits en mode immédiat.

Conversion des instructions arithmétiques

ARM 68000
ADD R0, R1, R2 MOVE.L D1, D0
ADD.L D2, D0
ADD R0, R1, #100 MOVE.L D1, D0
ADD.L #100, D0 ; ou ADDQ.L #n (1<=n<=8)
ADD R0, R0, R1 ADD.L D1, D0
ADD R0, R0, #1 ADDQ.L #1, D0
ADDS R0, R1, R2 MOVE.L D1, D0
ADD.L D2, D0 ; drapeaux mis a jour automatiquement
ADC R0, R1, R2 MOVE.L D1, D0
ADDX.L D2, D0
SUB R0, R1, R2 MOVE.L D1, D0
SUB.L D2, D0
SUB R0, R0, #1 SUBQ.L #1, D0
SUBS R0, R1, R2 MOVE.L D1, D0
SUB.L D2, D0
SBC R0, R1, R2 MOVE.L D1, D0
SUBX.L D2, D0
RSB R0, R1, #0 MOVE.L D1, D0
NEG.L D0
RSB R0, R1, R2 MOVE.L D2, D0
SUB.L D1, D0
MUL R0, R1, R2 ; 68000 : MULU/MULS 16 bits seul. Pour 32x32 : routine logicielle ou 68020 MULS.L D1,D0
UMULL R0, R1, R2, R3 ; 68000 : routine logicielle
; 68020 : MULU.L D2,D0:D1
MLA R0, R1, R2, R3 ; R0 = R1*R2 + R3
; 68000 : routine logicielle
CMP R0, R1 CMP.L D1, D0
CMP R0, #0 TST.L D0
CMP R0, #100 CMP.L #100, D0
CMN R0, R1 MOVE.L D1, D7 ; copie temp
NEG.L D7
CMP.L D7, D0
; ou ADD.L D1,D0 puis tester drapeaux (mais modifie D0)

Note importante : Sur ARM, les instructions a 3 opérandes (ADD R0, R1, R2) placent le résultat dans un registre différent des sources. Sur le 68000, les opérations sont a 2 opérandes (ADD.L D2,D0 modifie D0). Il faut donc souvent ajouter un MOVE.L préalable pour préserver l'opérande source.

Si R0 = R1 (destination = première source), le MOVE.L est inutile et la conversion est directe :

Conversion des instructions logiques et décalage

ARM 68000
AND R0, R1, R2 MOVE.L D1, D0
AND.L D2, D0
AND R0, R0, #$FF AND.L #$FF, D0
ORR R0, R1, R2 MOVE.L D1, D0
OR.L D2, D0
EOR R0, R1, R2 MOVE.L D1, D0
EOR.L D2, D0
BIC R0, R1, R2 MOVE.L D2, D7 ; copie masque
NOT.L D7 ; inverser
MOVE.L D1, D0
AND.L D7, D0
BIC R0, R0, #$80 AND.L #$FFFFFF7F, D0 ; ou BCLR #7, D0
TST R0, R1 MOVE.L D0, D7
AND.L D1, D7 ; positionner drapeaux
TST R0, #$01 BTST #0, D0
TEQ R0, R1 MOVE.L D0, D7
EOR.L D1, D7 ; positionner drapeaux
MOV R0, R1, LSL #3 MOVE.L D1, D0
LSL.L #3, D0
MOV R0, R1, LSR #3 MOVE.L D1, D0
LSR.L #3, D0
MOV R0, R1, ASR #3 MOVE.L D1, D0
ASR.L #3, D0
MOV R0, R1, ROR #3 MOVE.L D1, D0
ROR.L #3, D0
MOV R0, R1, LSL R2 MOVE.L D1, D0
LSL.L D2, D0
MOV R0, R1, RRX MOVE.L D1, D0
ROXR.L #1, D0

Barrel shifter combine (spécificité ARM) :

ARM 68000
ADD R0, R1, R2, LSL #3 MOVE.L D2, D7
LSL.L #3, D7
MOVE.L D1, D0
ADD.L D7, D0
SUB R0, R1, R2, ASR #2 MOVE.L D2, D7
ASR.L #2, D7
MOVE.L D1, D0
SUB.L D7, D0
AND R0, R1, R2, ROR #8 MOVE.L D2, D7
ROR.L #8, D7
MOVE.L D1, D0
AND.L D7, D0
CMP R0, R1, LSL #2 MOVE.L D1, D7
LSL.L #2, D7
CMP.L D7, D0

Note : Le barrel shifter intégré de l'ARM est l'une des différences les plus significatives. Chaque instruction ARM avec un opérande décalé nécessite un registre temporaire et une instruction de décalage supplémentaire sur le 68000. D7 est souvent utilise comme registre temporaire pour cela.

Conversion des instructions de branchement

ARM 68000
B label BRA label
BL proc BSR proc ; ou JSR proc
BX LR RTS
BX R0 JMP (A0) ; si R0 = A0

Branchements conditionnels :

ARM 68000
BEQ label BEQ label
BNE label BNE label
BCS / BHS label BCC label ; Attention: inverse!
; ARM CS = Carry Set = C=1
; 68000 BCS = Branch if Carry Set
; -> utiliser BCS (meme sens)
BCS label BCS label
BCC / BLO label BCC label
BMI label BMI label
BPL label BPL label
BVS label BVS label
BVC label BVC label
BHI label BHI label
BLS label BLS label
BGE label BGE label
BLT label BLT label
BGT label BGT label
BLE label BLE label

Note sur les conditions : Les conditions ARM et 68000 utilisent les mêmes noms pour les mêmes tests logiques. La correspondance est directe car les deux processeurs utilisent les mêmes drapeaux (N,Z,C,V) avec la même sémantique pour les branchements.

Boucles :

ARM 68000
  1. ; Boucle ARM comptant de n a 0
  2.   MOV  R2, #100                 
  3. .boucle:                       
  4.   ; ... corps ...              
  5.   SUBS R2, R2, #1              
  6.   BNE  .boucle
  7.  
  8. ; Boucle ARM comptant de 0 a n
  9.   MOV  R2, #0                  
  10.   MOV  R3, #100                
  11. .boucle:                       
  12.   ; ... corps ...              
  13.   ADD  R2, R2, #1              
  14.   CMP  R2, R3                  
  15.   BLT  .boucle
  1.   MOVEQ   #100-1, D2
  2. .boucle:
  3.   ; ... corps ...
  4.   DBRA    D2, .boucle
  5.  
  6.  
  7.  
  8.   CLR.L   D2
  9.   MOVE.L  #100, D3
  10. .boucle:
  11.   ; ... corps ...
  12.   ADDQ.L  #1, D2
  13.   CMP.L   D3, D2
  14.   BLT     .boucle

Note : DBRA du 68000 décrémenté un compteur 16 bits et boucle si le résultat n'est pas -1. Pour des compteurs 32 bits, utiliser SUBQ.L #1,Dn / BNE .boucle.

Conversion des modes d'adressage

L'ARM a un nombre limite de modes d'adressage pour LDR/STR. Le 68000 a 14 modes d'adressage utilisables avec la plupart des instructions.

ARM 68000
  1. ; --- Immediat ---
  2. MOV R0, #42                     
  3.  
  4. ; --- Registre ---
  5. MOV R0, R1                      
  6.  
  7. ; --- Indirect registre ---
  8. LDR R0, [R8]                    
  9.  
  10. ; --- Indirect avec offset ---
  11. LDR R0, [R8, #100]              
  12.  
  13. ; --- Indirect avec registre index ---
  14. LDR R0, [R8, R1]                
  15.  
  16. ; --- Indirect avec index decale ---
  17. LDR R0, [R8, R1, LSL #2]        
  18.                                 
  19.                                 
  20.                                 
  21.  
  22. ; --- Pre-indexe avec ecriture ---
  23. LDR R0, [R8, #4]!               
  24.                                 
  25.  
  26. ; --- Post-indexe ---
  27. LDR R0, [R8], #4                
  28.  
  29. ; --- Relatif PC ---
  30. LDR R0, [PC, #offset]           
  31. LDR R0, label
  1.  
  2. MOVEQ   #42, D0
  3.  
  4.  
  5. MOVE.L  D1, D0
  6.  
  7.  
  8. MOVE.L  (A0), D0
  9.  
  10.  
  11. MOVE.L  100(A0), D0
  12.  
  13.  
  14. MOVE.L  0(A0,D1.L), D0
  15.  
  16.  
  17. MOVE.L  D1, D7
  18.  LSL.L   #2, D7
  19.  MOVE.L  0(A0,D7.L), D0
  20.  ; 68020 : MOVE.L (A0,D1.L*4),D0
  21.  
  22.  
  23. ADDQ.L  #4, A0
  24.  MOVE.L  (A0), D0
  25.  
  26.  
  27. MOVE.L  (A0)+, D0
  28.  
  29.  
  30. MOVE.L  offset(PC), D0
  31. MOVE.L  label(PC), D0

Accès aux tableaux :

  1. ; ARM : acces a tab[i] (tableau de long mots)
  2.   LDR R0, [R8, R1, LSL #2]
  3.  
  4. ; 68000 : equivalent
  5.   MOVE.L  D1, D7          ; copie index
  6.   LSL.L   #2, D7          ; * 4
  7.   MOVE.L  0(A0,D7.L), D0
  8.  
  9. ; 68020+ : equivalent direct
  10.   MOVE.L  (A0,D1.L*4), D0

Conversion des instructions de pile et appels

Convention d'appel AAPCS (ARM) :

  1.   ; ARM : appel de func(a, b, c, d)
  2.   ; R0=a, R1=b, R2=c, R3=d (4 premiers args dans registres)
  3.     MOV  R0, a
  4.     MOV  R1, b
  5.     MOV  R2, c
  6.     MOV  R3, d
  7.     BL   func
  8.  
  9.   ; 68000 : convention C (arguments sur la pile)
  10.     MOVE.L  d, -(SP)
  11.     MOVE.L  c, -(SP)
  12.     MOVE.L  b, -(SP)
  13.     MOVE.L  a, -(SP)
  14.     JSR     func
  15.     LEA     16(SP), SP       ; nettoyer 4 long mots

Note : La convention d'appel ARM (AAPCS) passe les 4 premiers arguments dans R0-R3, le reste sur la pile. La convention C classique du 68000 passe tout sur la pile. Lors de la conversion, les arguments dans les registres ARM doivent être empilés pour le 68000, ou bien on peut adopter une convention registre personnalisée pour le 68000 (D0-D3 pour les arguments).

Prologue/épilogue de fonction :

  1.   ; ARM : appel de func(a, b, c, d)
  2.   ; R0=a, R1=b, R2=c, R3=d (4 premiers args dans registres)
  3.     MOV  R0, a
  4.     MOV  R1, b
  5.     MOV  R2, c
  6.     MOV  R3, d
  7.     BL   func
  8.  
  9.   ; 68000 : convention C (arguments sur la pile)
  10.     MOVE.L  d, -(SP)
  11.     MOVE.L  c, -(SP)
  12.     MOVE.L  b, -(SP)
  13.     MOVE.L  a, -(SP)
  14.     JSR     func
  15.     LEA     16(SP), SP       ; nettoyer 4 long mots

Accès aux paramètres et variables locales :

  1.   ; ARM : avec R11 (frame pointer)
  2.     LDR  R0, [R11, #-8]       ; variable locale
  3.     LDR  R1, [R11, #4]        ; parametre (sur la pile)
  4.  
  5.   ; 68000 : avec A6 (frame pointer, apres LINK)
  6.     MOVE.L  -8(A6), D0        ; variable locale
  7.     MOVE.L  8(A6), D1         ; 1er parametre

Sauvegarde/restauration de registres :

  1.   ; ARM : PUSH/POP
  2.     PUSH {R0-R3}               MOVEM.L D0-D3, -(SP)
  3.     POP  {R0-R3}               MOVEM.L (SP)+, D0-D3
  4.  
  5.   ; ARM : STMDB/LDMIA (equivalents de PUSH/POP)
  6.     STMDB SP!, {R4-R11, LR}   MOVEM.L D4-D7/A0-A3, -(SP)
  7.     LDMIA SP!, {R4-R11, PC}   MOVEM.L (SP)+, D4-D7/A0-A3
  8.                                 RTS

Conversion des instructions spécifiques ARM

Swap (SWP) :

ARM 68000
SWP R0, R1, [R8] ; Pas d'équivalent atomique
MOVE.L (A0), D0 ; lire ancien
MOVE.L D1, (A0) ; écrire nouveau
; Attention : non atomique !
; TAS.B est la seule op. atomique

Multiplication longue (UMULL, SMULL, UMLAL, SMLAL) :

ARM 68000
UMULL R0, R1, R2, R3 ; R1:R0 = R2 * R3 (64 bits)
; 68000 : routine logicielle
; 68020 : MULU.L D2,D0:D1
SMLAL R0, R1, R2, R3 ; R1:R0 += R2 * R3
; 68000 : routine logicielle

CLZ (Count Leading Zeros, ARMv5+) :

ARM 68000
CLZ R0, R1 ; Pas d'equivalent direct
; Implementer par boucle :
MOVEQ #32, D0
TST.L D1
BEQ.S .fin
MOVEQ #0, D0
.boucle:
BTST D0, D1
BNE.S .fin
ADDQ.L #1, D0
CMP.L #32, D0
BLT.S .boucle
.fin:
; Note: teste du bit 0 vers 31
; CLZ compte du bit 31 vers 0
; Ajuster: D0 = 31 - D0

MRS/MSR (accès au registre d'état) :

ARM 68000
MRS R0, CPSR MOVE.W SR, D0
; (mode superviseur requis
; pour lire SR complet)
MSR CPSR_f, R0 ; Pas d'equivalent simple
; Utiliser MOVE SR,Dn + AND/OR
; pour modifier les drapeaux

SWI (Software Interrupt) :

ARM 68000
SWI #0 TRAP #0
SWI #imm24 TRAP #n ; n = 0..15
; Le 68000 n'a que 16 TRAP
; Pour plus de fonctions, passer
; le numéro dans D0 :
MOVE.L #imm24, D0
TRAP #0

Instructions Thumb (jeu d'instructions 16 bits) :

Le mode Thumb de l'ARM utilise des instructions 16 bits pour une meilleure densité de code. Le 68000 n'a pas d'équivalent direct. Les instructions Thumb doivent être converties dans leur forme ARM équivalente, puis converties en 68000.

Conversion de l'exécution conditionnelle ARM

L'exécution conditionnelle est une caractéristique majeure de l'ARM. Presque toute instruction peut être rendue conditionnelle par un suffixe (EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL).

Méthode de conversion :

  1.   ; ARM : instruction conditionnelle simple
  2.     MOVEQ R0, #1                   BNE.S   .skip
  3.                                    MOVEQ   #1, D0
  4.                                  .skip:
  5.  
  6.   ; ARM : paire conditionnelle (if/else)
  7.     MOVEQ R0, #1                   BNE.S   .else
  8.     MOVNE R0, #0                   MOVEQ   #1, D0
  9.                                    BRA.S   .fin
  10.                                  .else:
  11.                                    CLR.L   D0
  12.                                  .fin:
  13.  
  14.   ; ARM : sequence conditionnelle longue
  15.     ADDEQ R0, R0, #1              BNE.S   .skip
  16.     SUBEQ R1, R1, #1              ADDQ.L  #1, D0
  17.     MOVEQ R2, #0                  SUBQ.L  #1, D1
  18.                                    CLR.L   D2
  19.                                  .skip:

Optimisation avec Scc du 68000 :

  1.   ; ARM : set conditionnel
  2.     MOVEQ R0, #1
  3.     MOVNE R0, #0
  4.  
  5.   ; 68000 : optimise avec Scc
  6.     SEQ     D0        ; D0 = $FF si Z=1, $00 sinon
  7.     AND.L   #1, D0    ; D0 = 1 si Z=1, 0 sinon
  8.  
  9.   ; ARM : increment conditionnel
  10.     CMP   R1, R2
  11.     ADDGT R0, R0, #1
  12.  
  13.   ; 68000 : equivalent
  14.     CMP.L   D2, D1
  15.     BLE.S   .skip
  16.     ADDQ.L  #1, D0
  17.   .skip:
  18.  
  19.   ; ARM : max(R0, R1)
  20.     CMP   R0, R1
  21.     MOVLT R0, R1
  22.  
  23.   ; 68000 : equivalent
  24.     CMP.L   D1, D0
  25.     BGE.S   .skip
  26.     MOVE.L  D1, D0
  27.   .skip:
  28.  
  29.   ; ARM : abs(R0)
  30.     CMP   R0, #0
  31.     RSBLT R0, R0, #0
  32.  
  33.   ; 68000 : equivalent (plus simple !)
  34.     TST.L   D0
  35.     BPL.S   .skip
  36.     NEG.L   D0
  37.   .skip:

Note : L'exécution conditionnelle ARM évite les branchements (bénéfique pour le pipeline ARM). Sur le 68000, les branches courtes (BCC.S) avec un déplacement 8 bits sont efficaces et le coût de la conversion est faible.

Exemples complets de conversion ARM → 68000

Exemple 1 : Longueur d'une chaîne (strlen)

  1.   ; --- ARM ---
  2.   strlen:
  3.     MOV   R1, R0              ; sauver debut
  4.   .boucle:
  5.     LDRB  R2, [R0], #1        ; charger octet, R0++
  6.     CMP   R2, #0
  7.     BNE   .boucle
  8.     SUB   R0, R0, R1           ; longueur = fin - debut
  9.     SUB   R0, R0, #1           ; -1 (terminateur)
  10.     BX    LR
  11.  
  12.   ; --- 68000 ---
  13.   strlen:
  14.     ; A0 = adresse de la chaine (entree)
  15.     ; D0 = longueur (sortie)
  16.     MOVEA.L A0, A1             ; sauver debut
  17.   .boucle:
  18.     TST.B   (A0)+              ; tester octet, A0++
  19.     BNE.S   .boucle
  20.     MOVE.L  A0, D0
  21.     SUB.L   A1, D0             ; fin - debut
  22.     SUBQ.L  #1, D0             ; -1 (terminateur)
  23.     RTS

Exemple 2 : Copie de mémoire (memcpy)

  1.   ; --- ARM ---
  2.   memcpy:
  3.     ; R0 = dest, R1 = src, R2 = nombre d'octets
  4.     PUSH  {R0}                 ; sauver dest pour retour
  5.   .boucle:
  6.     SUBS  R2, R2, #1
  7.     LDRBPL R3, [R1], #1
  8.     STRBPL R3, [R0], #1
  9.     BPL   .boucle
  10.     POP   {R0}
  11.     BX    LR
  12.  
  13.   ; --- 68000 ---
  14.   memcpy:
  15.     ; A0 = dest, A1 = src, D0 = nombre d'octets
  16.     MOVEA.L A0, A2             ; sauver dest pour retour
  17.     SUBQ.L  #1, D0
  18.     BMI.S   .fin
  19.   .boucle:
  20.     MOVE.B  (A1)+, (A0)+
  21.     DBRA    D0, .boucle
  22.   .fin:
  23.     MOVEA.L A2, A0             ; restaurer dest
  24.     RTS

Exemple 3 : Recherche dichotomique (binary search)

  1.   ; --- ARM ---
  2.   bsearch:
  3.     ; R0 = tableau, R1 = taille, R2 = valeur
  4.     MOV   R3, #0               ; bas = 0
  5.   .boucle:
  6.     CMP   R3, R1
  7.     BGE   .pas_trouve
  8.     ADD   R4, R3, R1
  9.     MOV   R4, R4, LSR #1      ; milieu = (bas+haut)/2
  10.     LDR   R5, [R0, R4, LSL #2] ; tab[milieu]
  11.     CMP   R5, R2
  12.     BEQ   .trouve
  13.     MOVLT R3, R4
  14.     ADDLT R3, R3, #1           ; bas = milieu + 1
  15.     MOVGT R1, R4               ; haut = milieu
  16.     B     .boucle
  17.   .trouve:
  18.     MOV   R0, R4               ; retourner index
  19.     BX    LR
  20.   .pas_trouve:
  21.     MVN   R0, #0               ; retourner -1
  22.     BX    LR
  23.  
  24.   ; --- 68000 ---
  25.   bsearch:
  26.     ; A0 = tableau, D1 = taille, D0 = valeur cherchee
  27.     ; Retour : D0 = index ou -1
  28.     MOVEM.L D2-D5, -(SP)
  29.     CLR.L   D3                 ; D3 = bas = 0
  30.   .boucle:
  31.     CMP.L   D1, D3
  32.     BGE.S   .pas_trouve
  33.     MOVE.L  D3, D4
  34.     ADD.L   D1, D4
  35.     LSR.L   #1, D4             ; D4 = milieu
  36.     MOVE.L  D4, D5
  37.     LSL.L   #2, D5             ; D5 = milieu * 4
  38.     MOVE.L  0(A0,D5.L), D2    ; D2 = tab[milieu]
  39.     CMP.L   D0, D2
  40.     BEQ.S   .trouve
  41.     BLT.S   .trop_petit
  42.     ; tab[milieu] > valeur : haut = milieu
  43.     MOVE.L  D4, D1
  44.     BRA.S   .boucle
  45.   .trop_petit:
  46.     ; tab[milieu] < valeur : bas = milieu + 1
  47.     MOVE.L  D4, D3
  48.     ADDQ.L  #1, D3
  49.     BRA.S   .boucle
  50.   .trouve:
  51.     MOVE.L  D4, D0
  52.     MOVEM.L (SP)+, D2-D5
  53.     RTS
  54.   .pas_trouve:
  55.     MOVEQ   #-1, D0
  56.     MOVEM.L (SP)+, D2-D5
  57.     RTS

Exemple 4 : Inversion d'endianness (utile pour le portage)

  1.   ; --- ARM (little-endian -> big-endian) ---
  2.   bswap32:
  3.     ; R0 = valeur a inverser
  4.     EOR   R1, R0, R0, ROR #16
  5.     BIC   R1, R1, #$00FF0000
  6.     MOV   R0, R0, ROR #8
  7.     EOR   R0, R0, R1, LSR #8
  8.     BX    LR
  9.  
  10.   ; --- 68000 (inutile si deja big-endian, mais pour reference) ---
  11.   bswap32:
  12.     ; D0 = valeur a inverser
  13.     ROL.W   #8, D0             ; swap octets mot bas
  14.     SWAP    D0                 ; echanger mots
  15.     ROL.W   #8, D0             ; swap octets mot haut
  16.     RTS

Exemple 5 : Factorielle récursive

  1.   ; --- ARM ---
  2.   factorielle:
  3.     CMP   R0, #1
  4.     MOVLE R0, #1
  5.     BXLE  LR
  6.     PUSH  {R0, LR}
  7.     SUB   R0, R0, #1
  8.     BL    factorielle
  9.     POP   {R1, LR}
  10.     MUL   R0, R0, R1
  11.     BX    LR
  12.  
  13.   ; --- 68000 ---
  14.   factorielle:
  15.     ; D0 = n (entree et sortie)
  16.     CMP.L   #1, D0
  17.     BGT.S   .recurse
  18.     MOVEQ   #1, D0
  19.     RTS
  20.   .recurse:
  21.     MOVE.L  D0, -(SP)         ; sauver n
  22.     SUBQ.L  #1, D0
  23.     BSR     factorielle        ; D0 = fact(n-1)
  24.     MOVE.L  (SP)+, D1         ; D1 = n
  25.     ; Multiplication 16 bits (suffisant pour petites valeurs)
  26.     MULU.W  D1, D0            ; D0 = n * fact(n-1)
  27.     RTS

Tableau récapitulatif des différences ARM → 68000

Aspect ARM 68000
Registres généraux 16 (R0-R15) 8 (D0-D7) + 8 (A0-A7)
Registres spéciaux SP(R13),LR(R14),PC(R15) SP(A7), PC
Architecture RISC load/store CISC memoire-memoire
Taille instructions 32 bits fixe 16-80 bits variable
Opérandes 3 (Rd, Rn, Op2) 2 (source, dest)
Barrel shifter Integre (Op2) Instructions séparées
Exécution conditionnelle Toute instruction Bcc/Scc seulement
Flags Optionnels (suffixe S) Automatiques
Chargement mémoire LDR/STR seulement MOVE depuis/vers mémoire
Transferts multiples LDM/STM (flexibles) MOVEM (An)+/-(An)
Appel fonction BL (LR=retour) BSR/JSR (pile=retour)
Retour fonction BX LR RTS
Interruption logicielle SWI #imm24 TRAP #0..15
Endianness Bi (souvent LE) Big-endian
Alignement 4 octets requis 2 octets requis
Modes adressage mémoire ~9 modes (LDR/STR) 14 modes (toute instruction)
Bassin de constantes Oui (LDR R,=const) Non (immédiat 32 bits)
Multiplication 32 bits MUL (32x32→32) Routine logicielle
Multiplication 64 bits UMULL/SMULL Routine logicielle
Division Aucune (logicielle) DIVU/DIVS (16 bits)
Swap atomique SWP TAS.B (octet seulement)
Comptage de zéros CLZ (ARMv5+) Boucle manuelle

Résumé

La conversion de code ARM en 68000 présente des défis spécifiques liés aux différences fondamentales entre architectures RISC et CISC. Voici les points clefs :



Dernière mise à jour : Jeudi, le 2 avril 2026