Section courante

A propos

Section administrative du site

Conversion de code 80386 en 68000

Cette page traite de la conversion de programmes écrits en assembleur Intel 80386 (i386) vers l'assembleur Motorola 68000. Elle aborde les aspects spécifiques au 80386 : registres 32 bits, modes d'adressage étendus (SIB), nouvelles instructions, et mode protégé.

Différences fondamentales entre 80386 et 68000

Le 80386 est une extension 32 bits du 8086. Il conserve la compatibilité ascendante mais ajoute des fonctionnalités significatives. Voici les différences majeures avec le 68000.

Critère Intel 80386 Motorola 68000
Taille des registres 32 bits 32 bits
Registres généraux 8 (EAX-EDI) 8 (D0-D7)
Registres d'adresse (inclus dans généraux) 8 (A0-A7/SP)
Registres de segment 6 (CS,DS,ES,FS,GS,SS) Aucun
Espace d'adressage 4 Go (32 bits) 16 Mo (24 bits)
Mode protégé Oui (GDT, LDT, IDT) Non (superviseur/user)
Pagination Oui (CR0, CR3) Non (68000 base)
Ordre des octets Little-endian Big-endian
Alignement mémoire Non requis Mots sur adresses paires
Pile Croissante vers bas Croissante vers bas
Modes SIB Oui (base+index*scale) Indirect indexe
Instructions de chaînes Oui (REP prefix) Non (boucles manuelles)
Coprocesseur intégré A partir du 80486 Séparé (68881/68882)

Différences clefs par rapport a la conversion 8086 :

Correspondance des registres 32 bits

Registre 80386 Équivalent 68000 Notes
EAX D0 Registre de travail principal
EBX D1 ou A0 Selon usage (donnée ou adresse)
ECX D2 Compteur de boucle
EDX D3 Extension MUL/DIV
ESI A1 ou A2 Index source
EDI A3 ou A4 Index destination
EBP A5 ou A6 Pointeur de cadre (frame)
ESP A7 (SP) Pointeur de pile
EIP PC Compteur ordinal
EFLAGS SR/CCR Registre d'état

Sous-registres :

80386 68000
AL D0.B (octet bas)
AH Pas d'accès direct ; utiliser ROL.W #8,D0
AX D0.W (mot bas)
EAX D0.L (long mot = registre complet)

Registres de segment (pas d'équivalent 68000) :

80386 68000
CS (aucun) - pas de segmentation
DS (aucun)
ES (aucun)
FS (aucun) - nouveaux sur 80386
GS (aucun)
SS (aucun)

Registres de contrôle (pas d'équivalent direct 68000) :

80386 68000
CR0 Pas d'équivalent (pagination/mode protégé)
CR2 Pas d'équivalent (adresse faute de page)
CR3 Pas d'équivalent (base table des pages)
DR0-DR7 Pas d'équivalent (debug registers)
TR6, TR7 Pas d'équivalent (test registers)

Conversion des instructions de transfert 32 bits

Le 80386 ajoute des transferts 32 bits aux transferts 8/16 bits du 8086. Sur le 68000, les transferts 32 bits utilisent le suffixe .L.

80386 68000
MOV EAX, EBX MOVE.L D1, D0
MOV EAX, 12345678h MOVE.L #$12345678, D0
MOV EAX, [EBX] MOVE.L (A0), D0
MOV EAX, [EBX+100] MOVE.L 100(A0), D0
MOV EAX, [12345678h] MOVE.L $12345678, D0
MOV [EDI], EAX MOVE.L D0, (A3)
MOV [EDI+20], EAX MOVE.L D0, 20(A3)
MOV DWORD PTR [EBX], 0 MOVE.L #0, (A0) ; ou CLR.L (A0)
XCHG EAX, EBX EXG D0, D1
LEA EAX, [EBP+20] LEA 20(A6), A0
PUSH EAX MOVE.L D0, -(SP)
POP EAX MOVE.L (SP)+, D0
PUSH DWORD 12345678h MOVE.L #$12345678, -(SP)
PUSHAD MOVEM.L D0-D7/A0-A6, -(SP)
POPAD MOVEM.L (SP)+, D0-D7/A0-A6
PUSHFD MOVE.W SR, -(SP) ; (16 bits)
POPFD MOVE.W (SP)+, SR

Instructions de transfert avec extension (nouveautés 80386) :

80386 68000
MOVZX EAX, BL CLR.L D0 ; Mettre a zero
MOVE.B D1, D0 ; Copier l'octet
MOVZX EAX, BX CLR.L D0
MOVE.W D1, D0
MOVSX EAX, BL MOVE.B D1, D0
EXT.W D0 ; .B -> .W
EXT.L D0 ; .W -> .L
MOVSX EAX, BX MOVE.W D1, D0
EXT.L D0 ; .W -> .L

Note : MOVZX (zero-extend) et MOVSX (sign-extend) du 80386 n'ont pas d'équivalent direct unique sur le 68000. MOVZX se simule par CLR.L + MOVE.B/W. MOVSX se simule par MOVE + EXT. Le 68020 ajoute EXTB.L pour étendre un octet directement en long mot (sans passer par .W).

Conversion des instructions arithmétiques 32 bits

80386 68000
ADD EAX, EBX ADD.L D1, D0
ADD EAX, 100 ADD.L #100, D0
; ou ADDQ.L #n, D0 (si 1 <= n <= 8)
ADD EAX, [EBX] ADD.L (A0), D0
ADC EAX, EBX ADDX.L D1, D0
SUB EAX, EBX SUB.L D1, D0
SUB EAX, 100 SUB.L #100, D0
SBB EAX, EBX SUBX.L D1, D0
INC EAX ADDQ.L #1, D0
DEC EAX SUBQ.L #1, D0
NEG EAX NEG.L D0
CMP EAX, EBX CMP.L D1, D0
CMP EAX, 0 TST.L D0
CMP EAX, 100 CMP.L #100, D0

Multiplication et division 32 bits :

Le 80386 ajoute des multiplications/divisions 32 bits.

80386 68000
MUL EBX
; EDX:EAX = EAX * EBX
; (32x32 -> 64 bits)
; 68000 de base : pas de MUL 32 bits
; -> utiliser une routine logicielle
; Le 68020 a MULU.L D1,D2:D0
IMUL EBX
; EDX:EAX = EAX * EBX (signe)
; Même situation : routine logicielle
; Le 68020 a MULS.L D1,D2:D0
IMUL EAX, EBX
; EAX = EAX * EBX (32 bits)
; 68000 : routine logicielle
; Le 68020 a MULS.L D1,D0
IMUL EAX, EBX, 100
; EAX = EBX * 100
; 68000 : routine logicielle
; Le 68020 : MULS.L #100,D0 avec D1 -> D0
DIV EBX
; EAX = EDX:EAX / EBX
; EDX = EDX:EAX MOD EBX
; 68000 : routine logicielle
; Le 68020 a DIVU.L D1,D2:D0
IDIV EBX
; idem signe
; 68000 : routine logicielle
; Le 68020 a DIVS.L D1,D2:D0

Multiplication 32 bits sur 68000 (routine logicielle) :

  1.   ; mul32 : D0.L = D0.L * D1.L (resultat 32 bits bas)
  2.   ; Methode : decomposer en 16x16
  3.   ;   D0 = (D0h * 65536 + D0l) * (D1h * 65536 + D1l)
  4.   ;      = D0l * D1l + (D0h * D1l + D0l * D1h) * 65536
  5.   ;   (on ignore D0h * D1h * 65536^2 car > 32 bits)
  6.   mul32:
  7.       MOVEM.L D2-D4, -(SP)
  8.       MOVE.L  D0, D2         ; D2 = D0 (copie)
  9.       MOVE.L  D1, D3         ; D3 = D1 (copie)
  10.       SWAP    D2             ; D2.W = D0 haut
  11.       SWAP    D3             ; D3.W = D1 haut
  12.       MOVE.W  D0, D4
  13.       MULU.W  D1, D4         ; D4.L = D0l * D1l
  14.       MULU.W  D1, D2         ; D2.L = D0h * D1l
  15.       MULU.W  D0, D3         ; D3.L = D0l * D1h
  16.       SWAP    D2
  17.       CLR.W   D2             ; D2 = (D0h * D1l) << 16
  18.       SWAP    D3
  19.       CLR.W   D3             ; D3 = (D0l * D1h) << 16
  20.       ADD.L   D2, D4
  21.       ADD.L   D3, D4
  22.       MOVE.L  D4, D0         ; D0.L = resultat
  23.       MOVEM.L (SP)+, D2-D4
  24.       RTS

Conversion des instructions logiques et décalage 32 bits

80386 68000
AND EAX, EBX AND.L D1, D0
AND EAX, 0FFFFh AND.L #$FFFF, D0
OR EAX, EBX OR.L D1, D0
XOR EAX, EBX EOR.L D1, D0
XOR EAX, EAX CLR.L D0
NOT EAX NOT.L D0
TEST EAX, EBX MOVE.L D0, D7 ; Copie temp
AND.L D1, D7 ; Positionner drapeaux
SHL EAX, 1 LSL.L #1, D0
SHL EAX, CL LSL.L D2, D0
SHR EAX, 1 LSR.L #1, D0
SHR EAX, CL LSR.L D2, D0
SAR EAX, 1 ASR.L #1, D0
SAR EAX, CL ASR.L D2, D0
ROL EAX, 1 ROL.L #1, D0
ROL EAX, CL ROL.L D2, D0
ROR EAX, 1 ROR.L #1, D0
RCL EAX, 1 ROXL.L #1, D0
RCR EAX, 1 ROXR.L #1, D0

Nouvelles instructions logiques du 80386 :

80386 68000
BT EAX, 5 BTST #5, D0 ; Tester bit 5
BTS EAX, 5 BSET #5, D0 ; Tester et mettre a 1
BTR EAX, 5 BCLR #5, D0 ; Tester et mettre a 0
BTC EAX, 5 BCHG #5, D0 ; Tester et inverser
BT EAX, ECX BTST D2, D0 ; Bit variable
BSF EAX, EBX ; Pas d'equivalent direct
; -> boucle de test bit par bit
BSR EAX, EBX ; Pas d'equivalent direct
; -> boucle de test bit par bit

Note : BT/BTS/BTR/BTC du 80386 trouvent des équivalents directs dans BTST/BSET/BCLR/BCHG du 68000. La différence est que sur le 80386, le drapeau CF reçoit le bit teste, tandis que sur le 68000, le drapeau Z est affecte (Z=1 si le bit était 0). Les tests doivent être adaptes en conséquence :

BSF (Bit Scan Forward) et BSR (Bit Scan Reverse) n'ont pas d'équivalent sur le 68000. Voici une implémentation :

  1. ; bsf32 : trouver le premier bit a 1 en partant du bit 0
  2. ; Entree : D1.L = valeur, Sortie : D0.L = position du bit
  3. ; Z=1 si D1 = 0
  4. bsf32:
  5.     TST.L   D1
  6.     BEQ.S   .zero
  7.     MOVEQ   #0, D0
  8. .boucle:
  9.     BTST    D0, D1
  10.     BNE.S   .trouve
  11.     ADDQ.L  #1, D0
  12.     BRA.S   .boucle
  13. .trouve:
  14.     RTS
  15. .zero:
  16.     RTS                    ; Z est deja positionne

Instructions de décalage double (nouveautés 80386) :

80386 68000
SHLD EAX, EBX, 4
; Decale EAX a gauche de 4
; et insere les bits hauts ; de EBX
; Pas d'equivalent direct
; Implementer avec :
; LSL.L #4, D0
; MOVE.L D1, D7
; LSR.L #28, D7
; OR.L D7, D0
SHRD EAX, EBX, 4
; Decale EAX a droite de 4
; et insere les bits bas
; de EBX
; Pas d'equivalent direct
; LSR.L #4, D0
; MOVE.L D1, D7
; LSL.L #28, D7
; OR.L D7, D0

Conversion des instructions de branchement et boucles

Les instructions de branchement du 80386 sont identiques a celles du 8086, mais avec des déplacements 32 bits en plus des 8 et 16 bits.

80386 68000
JMP label BRA label
JMP NEAR label BRA.W label
JMP SHORT label BRA.S label
CALL proc BSR proc ; ou JSR proc
RET RTS
ENTER 16, 0 LINK A6, #-16
LEAVE UNLK A6

Branchements conditionnels avec déplacements 32 bits : Le 80386 permet Jcc rel32 (déplacements 32 bits). Le 68000 de base est limite a Bcc.S (8 bits) et Bcc.W (16 bits). Le 68020+ permet Bcc.L (32 bits).

Pour les cas ou le déplacement dépasse 16 bits sur le 68000 :

  1. ; 80386 : JE loin    (deplacement > 32 Ko)
  2. ; 68000 : inverser la condition + JMP
  3.   BNE.S   .skip
  4.   JMP     loin
  5. .skip:

Nouvelles instructions conditionnelles du 80386 :

80386 68000
SETcc reg8
SETE AL
; Pas d'equivalent direct
; Met reg8 a 1 si cc, 0 sinon
; Equivalent :
Scc D0 ; Scc met $FF si vrai
AND.B #1, D0 ; Reduire a 0 ou 1

Note sur Scc du 68000 : l'instruction Scc met l'octet destination a $FF (tous les bits a 1) si la condition est vraie, et $00 si fausse. Le SETcc du 80386 met 1 ou 0. Si le code dépend de la valeur exacte 1, ajouter AND.B #1 ou NEG.B après Scc.

Correspondance des conditions Scc :

80386 SETcc 68000 Scc
SETE / SETZ SEQ
SETNE / SETNZ SNE
SETA / SETNBE SHI
SETAE / SETNB SCC / SHS
SETB / SETNAE SCS / SLO
SETBE / SETNA SLS
SETG / SETNLE SGT
SETGE / SETNL SGE
SETL / SETNGE SLT
SETLE / SETNG SLE
SETS SMI
SETNS SPL

Boucles :

Le 80386 utilise toujours LOOP/LOOPE/LOOPNE avec ECX comme compteur (au lieu de CX sur le 8086).

80386 68000
MOV ECX, 1000
.boucle:
; ... corps ...
LOOP .boucle
JECXZ label
MOVE.L #1000-1, D2
.boucle:
; ... corps ...
DBRA D2, .boucle

TST.L D2
BEQ label

Note : DBRA utilise un compteur 16 bits seulement (-1 a 65535).

Pour des boucles avec compteur 32 bits, utiliser :

  1. SUBQ.L  #1, D2
  2. BNE     .boucle

Conversion des modes d'adressage étendus (SIB)

Le 80386 introduit le byte SIB (Scale-Index-Base) permettant des modes d'adressage de la forme :

[base + index * scale + deplacement]

avec scale = 1, 2, 4 ou 8.

Le 68000 de base supporte seulement d(An,Dn.W) ou d(An,Dn.L) sans facteur d'échelle. Pour simuler les modes SIB, il faut précalculer l'index multiplie.

80386 68000
; --- Scale = 1 ---
MOV EAX, [EBX+ESI]
MOV EAX, [EBX+ESI+8]

MOVE.L 0(A0,A1.L), D0
MOVE.L 8(A0,A1.L), D0
; --- Scale = 2 ---
MOV EAX, [EBX+ESI*2]

MOVE.L A1, D7
ADD.L D7, D7 ; D7 = index * 2
MOVE.L 0(A0,D7.L), D0
; --- Scale = 4 ---
MOV EAX, [EBX+ESI*4]

MOVE.L A1, D7
LSL.L #2, D7 ; D7 = index * 4
MOVE.L 0(A0,D7.L), D0
; --- Scale = 8 ---
MOV EAX, [EBX+ESI*8]

MOVE.L A1, D7
LSL.L #3, D7 ; D7 = index * 8
MOVE.L 0(A0,D7.L), D0
; --- Avec deplacement ---
MOV EAX, [EBX+ESI*4+100]

MOVE.L A1, D7
LSL.L #2, D7
ADD.L A0, D7
MOVE.L 100(D7), D0
; Ou bien :
LEA 100(A0), A4
MOVE.L A1, D7
LSL.L #2, D7
MOVE.L 0(A4,D7.L), D0

Accès aux tableaux (cas courant du SIB) :

  1.   ; 80386 : acces a un tableau de long mots (DWORD)
  2.     MOV EAX, [tableau + ESI*4]
  3.  
  4.   ; 68000 : equivalent
  5.     LEA     tableau, A0
  6.     MOVE.L  A1, D7          ; D7 = copie de l'index
  7.     LSL.L   #2, D7          ; * 4 (taille d'un long mot)
  8.     MOVE.L  0(A0,D7.L), D0
  9.  
  10.   ; 68000 : alternative avec ADD
  11.     LEA     tableau, A0
  12.     MOVE.L  A1, D7
  13.     ADD.L   D7, D7          ; * 2
  14.     ADD.L   D7, D7          ; * 4
  15.     MOVE.L  0(A0,D7.L), D0

Note sur le 68020+ : Le 68020 et versions ultérieures supportent des modes d'adressage étendus avec facteur d'échelle (*1, *2, *4, *8), ce qui donne un équivalent direct au SIB du 80386 :

  1. MOVE.L  (A0,A1.L*4), D0    ; 68020+ seulement

Conversion des instructions de pile et appels

Convention d'appel C sur 80386 (paramètres 32 bits) :

  1.   ; 80386 : appel cdecl de func(a, b, c)
  2.     PUSH  DWORD c            ; 3e argument
  3.     PUSH  DWORD b            ; 2e argument
  4.     PUSH  DWORD a            ; 1er argument
  5.     CALL  func
  6.     ADD   ESP, 12            ; Nettoyer 3 longs mots
  7.  
  8.   ; 68000 : equivalent
  9.     MOVE.L  c, -(SP)
  10.     MOVE.L  b, -(SP)
  11.     MOVE.L  a, -(SP)
  12.     JSR     func
  13.     LEA     12(SP), SP       ; Nettoyer la pile

Cadre de pile (stack frame) :

  1. ; 80386 : prologue avec ENTER
  2.   PUSH  EBP
  3.   MOV   EBP, ESP
  4.   SUB   ESP, 16            ; 16 octets pour variables locales
  5.   ; ou ENTER 16, 0
  6.  
  7. ; 68000 : equivalent avec LINK
  8.   LINK    A6, #-16         ; Sauve A6, A6=SP, SP-=16
  9.  
  10. ; 80386 : epilogue avec LEAVE
  11.   MOV   ESP, EBP
  12.   POP   EBP
  13.   RET
  14.   ; ou LEAVE / RET
  15.  
  16. ; 68000 : equivalent avec UNLK
  17.   UNLK    A6
  18.   RTS

Accès aux arguments (convention C, long mots 32 bits) :

  1.   ; 80386 : avec EBP
  2.     MOV   EAX, [EBP+8]      ; 1er argument
  3.     MOV   EBX, [EBP+12]     ; 2e argument
  4.     MOV   ECX, [EBP+16]     ; 3e argument
  5.  
  6.   ; 68000 : avec A6 (apres LINK)
  7.     MOVE.L  8(A6), D0        ; 1er argument
  8.     MOVE.L  12(A6), D1       ; 2e argument
  9.     MOVE.L  16(A6), D2       ; 3e argument

Note : Les déplacements sont identiques car l'adresse de retour est un long mot (4 octets) sur les deux architectures en mode 32 bits.

Sauvegarde de registres :

  1. ; 80386 : PUSHAD/POPAD (tous les registres 32 bits)
  2.   PUSHAD                     ; Empile EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI
  3.  
  4. ; 68000 : MOVEM
  5.   MOVEM.L D0-D7/A0-A6, -(SP)  ; 15 registres (pas A7/SP)
  6.  
  7. ; 80386 : sauvegarde selective
  8.   PUSH  EBX
  9.   PUSH  ESI
  10.   PUSH  EDI
  11.  
  12. ; 68000 : sauvegarde groupee
  13.   MOVEM.L D1/A1-A3, -(SP)

Conversion des nouvelles instructions 80386

Le 80386 ajoute plusieurs instructions n'existant pas sur le 8086. Voici comment les convertir.

80386 68000
  1.   CDQ                           
  2.     ; EDX = signe de EAX        
  3.  
  4.  
  5.  
  6.  
  7.     ; Ou plus simplement :
  8.  
  9.  
  10.  
  11.  
  12.     .pos:
  1.  ; Pas d'equivalent direct
  2.  MOVE.L  D0, D3
  3.   ASR.L   #8, D3
  4.   ASR.L   #8, D3
  5.   ASR.L   #8, D3
  6.   ASR.L   #7, D3   ; D3 = 0 ou -1
  7.  
  8.   MOVEQ   #0, D3
  9.   TST.L   D0
  10.   BPL.S   .pos
  11.   MOVEQ   #-1, D3

CWDE (extension de signe AX → EAX) :

80386 68000
  1. CWDE
  2.   ; EAX = signe-etendu(AX)
  1. EXT.L   D0       ; .W -> .L

BSWAP (inversion d'octets) :

Le 80386 (80486+) a BSWAP pour inverser l'ordre des octets d'un registre 32 bits. Utile pour la conversion d'endianness.

80386 68000
  1. BSWAP EAX                      
  2.   ; $12345678 -> $78563412     
  3.                                
  4.                                
  5.  
  6. ; Verification : $12345678
  7. ;   ROL.W #8  -> $12347856
  8. ;   SWAP      -> $78561234
  9. ;   ROL.W #8  -> $78563412  OK
  1. ; Pas d'equivalent direct
  2.  ROL.W   #8, D0    ; Swap octets mot bas                        
  3.  SWAP    D0         ; Echanger les mots                        
  4.  ROL.W   #8, D0    ; Swap octets mot haut        

CMPXCHG (comparaison et échange atomique) : Instruction atomique du 80386+ pour la synchronisation.

80386 68000
  1. CMPXCHG [mem], EBX            
  2.   ; Si EAX=[mem], alors       
  3.   ;   [mem]=EBX, ZF=1         
  4.   ; Sinon                     
  5.   ;   EAX=[mem], ZF=0         
  6.                               
  7.                               
  8.                               
  9.                               
  10.                               
  11.                               
  12.                               
  13.   ; Attention : non atomique !
  1. ; Pas d'equivalent direct complet
  2.  ; TAS (test-and-set) est la seule
  3.  ; instruction atomique du 68000
  4.  ; Pour une approximation :
  5.   MOVE.L  (A0), D7
  6.   CMP.L   D0, D7
  7.   BNE.S   .diff
  8.   MOVE.L  D1, (A0)
  9.   BRA.S   .fin
  10. .diff:
  11.   MOVE.L  D7, D0
  12. .fin:

Conversion du mode protégé et segmentation 80386

Le mode protégé du 80386 n'a pas d'équivalent sur le 68000. Les instructions suivantes du 80386 liées au mode protégé ne peuvent pas être converties directement.

Instructions sans équivalent sur le 68000 :

80386 Description 68000
LGDT mem Charger GDT register (aucun)
SGDT mem Entreposer GDT register (aucun)
LLDT reg16 Charger LDT register (aucun)
SLDT reg16 Entreposer LDT register (aucun)
LIDT mem Charger IDT register (aucun)
SIDT mem Entreposer IDT register (aucun)
LTR reg16 Charger Task Register (aucun)
STR reg16 Entreposer Task Register (aucun)
LMSW reg16 Charger Machine Status Word (aucun)
SMSW reg16 Entreposer Machine Status Word (aucun)
MOV CRn, reg Charger registre contrôle (aucun)
MOV reg, CRn Lire registre contrôle (aucun)
MOV DRn, reg Charger registre debug (aucun)
MOV reg, DRn Lire registre debug (aucun)
ARPL reg16, reg16 Ajuster RPL (aucun)
LAR reg, mem16 Charger droits d'accès (aucun)
LSL reg, mem16 Charger limite segment (aucun)
VERR mem16 Vérifier lecture segment (aucun)
VERW mem16 Vérifier écriture segment (aucun)
CLTS Effacer flag Task Switched (aucun)
INVD Invalider cache (aucun)
WBINVD Écrire + invalider cache (aucun)
INVLPG mem Invalider page TLB (aucun)

Stratégie de conversion du mode protégé :

Le mode protégé du 80386 fournit :

Le 68000 offre une séparation basique superviseur/utilisateur. Pour porter du code mode protégé :

Registres de segment utilises comme sélecteurs :

  1.   ; 80386 en mode protege
  2.     MOV AX, selecteur_donnees
  3.     MOV DS, AX
  4.     MOV EAX, DS:[EBX]
  5.  
  6.   ; 68000 : supprimer completement la segmentation
  7.     MOVE.L  (A0), D0         ; Acces direct lineaire
  8.     ; Les selecteurs de segment n'ont pas d'equivalent

Exemples complets de conversion 80386 → 68000

Exemple 1 : Copie de memoire 32 bits (memcpy optimise)

  1.   ; --- 80386 ---
  2.   memcpy32:
  3.     ; ESI = source, EDI = dest, ECX = nombre d'octets
  4.     PUSH  ESI
  5.     PUSH  EDI
  6.     MOV   EAX, ECX
  7.     SHR   ECX, 2             ; ECX = nombre de long mots
  8.     REP   MOVSD              ; Copier par long mots
  9.     MOV   ECX, EAX
  10.     AND   ECX, 3             ; ECX = octets restants
  11.     REP   MOVSB              ; Copier les octets restants
  12.     POP   EDI
  13.     POP   ESI
  14.     RET
  15.  
  16.   ; --- 68000 ---
  17.   memcpy32:
  18.     ; A1 = source, A0 = dest, D0 = nombre d'octets
  19.     MOVEM.L D0-D2/A0-A1, -(SP)
  20.     MOVE.L  D0, D2           ; D2 = total octets
  21.     LSR.L   #2, D0           ; D0 = nombre de long mots
  22.     BEQ.S   .octets          ; Si 0 long mot, passer aux octets
  23.     SUBQ.L  #1, D0           ; Ajuster pour DBRA
  24.   .copie4:
  25.     MOVE.L  (A1)+, (A0)+
  26.     DBRA    D0, .copie4
  27.   .octets:
  28.     MOVE.L  D2, D0
  29.     AND.L   #3, D0           ; Octets restants
  30.     BEQ.S   .fin
  31.     SUBQ.L  #1, D0
  32.   .copie1:
  33.     MOVE.B  (A1)+, (A0)+
  34.     DBRA    D0, .copie1
  35.   .fin:
  36.     MOVEM.L (SP)+, D0-D2/A0-A1
  37.     RTS

Exemple 2 : Recherche dans un tableau de long mots

  1.   ; --- 80386 ---
  2.   chercher32:
  3.     ; ESI = tableau, ECX = nombre d'elements, EAX = valeur
  4.     PUSH  ECX
  5.     MOV   EDI, ESI
  6.     REPNE SCASD              ; Chercher EAX dans ES:EDI
  7.     JNE   .non_trouve
  8.     SUB   EDI, 4
  9.     MOV   EAX, EDI           ; EAX = adresse de l'element
  10.     POP   ECX
  11.     RET
  12.   .non_trouve:
  13.     XOR   EAX, EAX           ; EAX = 0 (non trouve)
  14.     POP   ECX
  15.     RET
  16.  
  17.   ; --- 68000 ---
  18.   chercher32:
  19.     ; A0 = tableau, D1 = nombre d'elements, D0 = valeur
  20.     ; Retour : A0 = adresse element ou 0 si non trouve
  21.     MOVEM.L D1-D2, -(SP)
  22.     SUBQ.L  #1, D1
  23.   .boucle:
  24.     CMP.L   (A0)+, D0
  25.     DBEQ    D1, .boucle
  26.     BNE.S   .non_trouve
  27.     SUBQ.L  #4, A0           ; Revenir sur l'element
  28.     MOVEM.L (SP)+, D1-D2
  29.     RTS
  30.   .non_trouve:
  31.     SUBA.L  A0, A0           ; A0 = 0
  32.     MOVEM.L (SP)+, D1-D2
  33.     RTS
  34.  
  35.   Exemple 3 : Tri par insertion (32 bits)
  36.  
  37.   ; --- 80386 ---
  38.   tri_insertion:
  39.     ; ESI = adresse tableau, ECX = nombre d'elements
  40.     PUSH  EBX
  41.     PUSH  EDI
  42.     MOV   EDI, 1             ; i = 1
  43.   .externe:
  44.     CMP   EDI, ECX
  45. JGE   .fin
  46.     MOV   EAX, [ESI+EDI*4]  ; cle = tab[i]
  47.     MOV   EBX, EDI
  48.     DEC   EBX               ; j = i - 1
  49.   .interne:
  50.     CMP   EBX, 0
  51.     JL    .inserer
  52.     CMP   [ESI+EBX*4], EAX
  53.     JLE   .inserer
  54.     MOV   EDX, [ESI+EBX*4]
  55.     MOV   [ESI+EBX*4+4], EDX  ; tab[j+1] = tab[j]
  56.     DEC   EBX
  57.     JMP   .interne
  58.   .inserer:
  59.     MOV   [ESI+EBX*4+4], EAX  ; tab[j+1] = cle
  60.     INC   EDI
  61.     JMP   .externe
  62.   .fin:
  63.     POP   EDI
  64.     POP   EBX
  65.     RET
  66.  
  67.   ; --- 68000 ---
  68.   tri_insertion:
  69.     ; A0 = adresse tableau, D7 = nombre d'elements
  70.     MOVEM.L D0-D4/A1, -(SP)
  71.     MOVEQ   #1, D3           ; D3 = i = 1
  72.   .externe:
  73.     CMP.L   D7, D3
  74.     BGE.S   .fin
  75.     ; Calculer adresse tab[i]
  76.     MOVE.L  D3, D4
  77.     LSL.L   #2, D4           ; D4 = i * 4
  78.     MOVE.L  0(A0,D4.L), D0  ; D0 = cle = tab[i]
  79.     MOVE.L  D3, D1
  80.     SUBQ.L  #1, D1           ; D1 = j = i - 1
  81.   .interne:
  82.     TST.L   D1
  83.     BMI.S   .inserer
  84.     MOVE.L  D1, D4
  85.     LSL.L   #2, D4           ; D4 = j * 4
  86.     CMP.L   0(A0,D4.L), D0
  87.     BGE.S   .inserer
  88.     MOVE.L  0(A0,D4.L), D2  ; D2 = tab[j]
  89.     MOVE.L  D2, 4(A0,D4.L)  ; tab[j+1] = tab[j]
  90.     SUBQ.L  #1, D1
  91.     BRA.S   .interne
  92.   .inserer:
  93.     MOVE.L  D1, D4
  94.     ADDQ.L  #1, D4
  95.     LSL.L   #2, D4           ; D4 = (j+1) * 4
  96.     MOVE.L  D0, 0(A0,D4.L)  ; tab[j+1] = cle
  97.     ADDQ.L  #1, D3
  98.     BRA.S   .externe
  99.   .fin:
  100.     MOVEM.L (SP)+, D0-D4/A1
  101.     RTS

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

  1.   ; --- 80386 ---
  2.   ; BSWAP n'est disponible qu'a partir du 80486
  3.   ; Version 80386 pour inverser les octets d'un buffer
  4.   swap_endian32:
  5.     ; ESI = buffer, ECX = nombre de long mots
  6.   .boucle:
  7.     MOV   EAX, [ESI]
  8.     XCHG  AL, AH             ; Swap octets bas
  9.     ROL   EAX, 16            ; Echanger mots
  10.     XCHG  AL, AH             ; Swap octets haut
  11.     MOV   [ESI], EAX
  12.     ADD   ESI, 4
  13.     LOOP  .boucle
  14.     RET
  15.  
  16.   ; --- 68000 ---
  17.   swap_endian32:
  18.     ; A0 = buffer, D1 = nombre de long mots
  19.     MOVEM.L D0-D1, -(SP)
  20.     SUBQ.L  #1, D1
  21.   .boucle:
  22.     MOVE.L  (A0), D0
  23.     ROL.W   #8, D0           ; Swap octets du mot bas
  24.     SWAP    D0               ; Echanger les mots
  25.     ROL.W   #8, D0           ; Swap octets du mot haut
  26.     MOVE.L  D0, (A0)+
  27.     DBRA    D1, .boucle
  28.     MOVEM.L (SP)+, D0-D1
  29.     RTS

Exemple 5 : Calcul CRC-32 (utilise instructions 32 bits)

  1.   ; --- 80386 ---
  2.   crc32:
  3.     ; ESI = donnees, ECX = longueur, EAX = crc initial
  4.     NOT   EAX
  5.   .boucle:
  6.     XOR   AL, [ESI]
  7.     MOV   EDX, 8
  8.   .bit:
  9.     SHR   EAX, 1
  10.     JNC   .zero
  11.     XOR   EAX, 0EDB88320h   ; Polynome CRC-32
  12.   .zero:
  13.     DEC   EDX
  14.     JNZ   .bit
  15.     INC   ESI
  16.     LOOP  .boucle
  17.     NOT   EAX
  18.     RET
  19.  
  20.   ; --- 68000 ---
  21.   crc32:
  22.     ; A0 = donnees, D1 = longueur, D0 = crc initial
  23.     MOVEM.L D2-D3/A0, -(SP)
  24.     NOT.L   D0
  25.     SUBQ.L  #1, D1
  26.   .boucle:
  27.     MOVE.B  (A0)+, D2
  28.     EOR.B   D2, D0
  29.     MOVEQ   #7, D3
  30.   .bit:
  31.     LSR.L   #1, D0
  32.     BCC.S   .zero
  33.     EOR.L   #$EDB88320, D0
  34.   .zero:
  35.     DBRA    D3, .bit
  36.     DBRA    D1, .boucle
  37.     NOT.L   D0
  38.     MOVEM.L (SP)+, D2-D3/A0
  39.     RTS

Tableau récapitulatif des différences 80386 → 68000

Aspect 80386 68000
Registres 32 bits EAX-EDI (8) D0-D7 (8) + A0-A7 (8)
Sous-registres AL,AH,AX,EAX .B,.W,.L (pas AH)
Segmentation 6 regs (CS-GS) Aucune (espace plat)
Mode protégé Oui (rings 0-3) Non (super/user)
Pagination Oui (CR0,CR3) Non (68000 de base)
SIB addressing base+idx*scale+disp d(An,Dn) sans scale>
Extension zéro MOVZX CLR.L + MOVE.B/W
Extension signe MOVSX MOVE + EXT.W + EXT.L
Bits test/set/clr BT/BTS/BTR/BTC BTST/BSET/BCLR/BCHG
Bit scan BSF/BSR Boucle manuelle
Décalage double SHLD/SHRD LSL+LSR+OR manuels
Set conditionnel SETcc (0/1) Scc ($00/$FF)
Byte swap BSWAP (486+) ROL.W+SWAP+ROL.W
Compare-exchange CMPXCHG Non atomique
MUL 32x32→64 MUL reg32 Routine logicielle
DIV 64/32→32 DIV reg32 Routine logicielle
ENTER/LEAVE Oui LINK/UNLK
PUSHAD/POPAD Oui MOVEM.L
REP MOVSD/STOSD Oui (32 bits) Boucle MOVE.L
Boucle 32 bits LOOP (ECX) SUBQ.L/BNE
Branch 32 bits Jcc rel32 BNE.S+JMP (68000)
Bcc.L (68020+)

Résumé

La conversion de code 80386 en 68000 reprend les principes de la conversion 8086 avec les considérations supplémentaires suivantes :



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