Section courante

A propos

Section administrative du site

Modes d'adressage

Le 6502 dispose de 13 modes d'adressage qui, malgré l'apparente simplicité du processeur, offrent une grande flexibilité pour accéder aux données en mémoire. Ces modes d'adressage sont l'une des forces du 6502 par rapport a ses concurrents 8 bits.

Les modes d'adressage du 6502 se repartissent en plusieurs catégories :

Modes sans opérande mémoire :

Modes avec opérande immédiat :

Modes avec accès a la page zéro ($0000-$00FF) :

Modes avec accès absolu ($0000-$FFFF) :

Modes indirects (via un pointeur en page zéro) :

Modes de branchement :

L'adresse effective (Effective Address, EA) est l'adresse finale en mémoire a laquelle le processeur accède pour lire ou écrire une donnée. Le mode d'adressage détermine comment cette adresse est calculée.

Le choix du mode d'adressage affecte :

Codage de l'opcode :

Bits 4-2 Mode d'adressage
000 (Indexed Indirect,X) ($ZP,X)
001 Zéro Page $ZP
010 Immédiate #$nn
011 Absolute $nnnn
100 (Indirect Indexed),Y ($ZP),Y
101 Zero Page,X $ZP,X
110 Absolute,Y $nnnn,Y
111 Absolute,X $nnnn,X

Ce schéma s'applique aux instructions du groupe "a" (ORA, AND, EOR, ADC, STA, LDA, CMP, SBC). Les autres groupes suivent des schémas différents avec un sous-ensemble de ces modes.

Adressage implicite (Implied)

L'instruction n'a pas d'opérande explicite. Elle agit sur un registre ou un état interne spécifique du processeur. L'opérande est implicitement déterminé par l'opcode.

Taille de l'instruction : 1 octet (opcode seul)

Nombre de cycles : 2

Instructions utilisant ce mode :

Transferts de registres :

Instruction Opération
TAX ($AA) A → X
TAY ($A8) A → Y
TXA ($8A) X → A
TYA ($98) Y → A
TSX ($BA) SP → X
TXS ($9A) X → SP

Incrémentation/décrémentation de registres :

Instruction Opération
INX ($E8) X := X + 1
INY ($C8) Y := Y + 1
DEX ($CA) X := X - 1
DEY ($88) Y := Y - 1

Opérations sur la pile :

Instruction Opération Nombre de cycles d'horloges
PHA ($48) Empiler A 3 cycles
PLA ($68) dépiler A 4 cycles
PHP ($08) empiler P 3 cycles
PLP ($28) dépiler P 4 cycles

Contrôle des drapeaux :

Instruction Opération
CLC ($18) C := 0
SEC ($38) C := 1
CLD ($D8) D := 0
SED ($F8) D := 1
CLI ($58) I := 0
SEI ($78) I := 1
CLV ($B8) V := 0

Contrôle du flux :

Instruction Opération Nombre de cycles d'horloges
RTS ($60) Retour de sous-routine 6 cycles
RTI ($40) Retour d'interruption 6 cycles
BRK ($00) Interruption logicielle 7 cycles
NOP ($EA) Pas d'opération 2 cycles

Exemples :

  1. CLC               ; effacer la retenue avant une addition
  2. ADC #$10          ; A = A + $10 + 0
  3.  
  4. INX               ; X = X + 1
  5. DEY               ; Y = Y - 1
  6.  
  7. PHA               ; sauvegarder A sur la pile
  8. ; ... code ...
  9. PLA               ; restaurer A depuis la pile

Remarques :

Adressage par accumulateur (Accumulator)

L'instruction agit directement sur le registre A (accumulateur). Ce mode est utilise uniquement par les instructions de décalage et de rotation. Il est parfois considéré comme un cas particulier de l'adressage implicite.

Notation assembleur : A (ou parfois rien après l'instruction)

Taille de l'instruction : 1 octet (opcode seul)

Nombre de cycles : 2

Instructions utilisant ce mode :

Instruction Opération
ASL A ($0A) décalage arithmétique a gauche de A
C ← [76543210] ← 0
LSR A ($4A) décalage logique a droite de A
0 → [76543210] → C
ROL A ($2A) rotation a gauche via C
C ← [76543210] ← C
ROR A ($6A) Rotation a droite via C
C → [76543210] → C

Schéma des opérations de décalage et rotation :

ASL A :


LSR A :


ROL A :


ROR A :


Exemples :

  1. ; Multiplier A par 2
  2. ASL A             ; A = A * 2 (C recoit le bit de poids fort)
  3.  
  4. ; Diviser A par 2 (non signe)
  5. LSR A             ; A = A / 2 (C recoit le bit de poids faible)
  6.  
  7. ; Multiplier A par 4
  8. ASL A             ; A = A * 2
  9. ASL A             ; A = A * 4
  10.  
  11. ; Rotation 16 bits a gauche (poids fort dans $81, poids faible dans $80)
  12. ASL $80           ; decaler poids faible, bit 7 -> C
  13. ROL $81           ; decaler poids fort, C -> bit 0
  14.  
  15. ; Tester le bit 7 de A
  16. ASL A             ; bit 7 -> C
  17. BCS BitEstUn      ; brancher si C = 1

Remarques :

Adressage immédiat (Immediate)

L'opérande est une constante de 8 bits codée directement dans l'instruction, immédiatement après l'opcode. La valeur n'est pas une adresse mémoire mais la donnée elle-même.

Notation assembleur : #valeur (le préfixe # indique l'immédiat)

Taille de l'instruction : 2 octets (opcode + valeur 8 bits)

Nombre de cycles : 2

Formule : opérande = octet suivant l'opcode

Instructions utilisant ce mode :

Chargement :

Instruction Opération
LDA #nn ($A9) A := nn
LDX #nn ($A2) X := nn
LDY #nn ($A0) Y := nn

Arithmétique :

Instruction Opération
ADC #nn ($69) A := A + nn + C
SBC #nn ($E9) A := A - nn - NOT(C)

Logique :

Instruction Opération
AND #nn ($29) A := A AND nn
ORA #nn ($09) A := A OR nn
EOR #nn ($49) A := A XOR nn

Comparaison :

Instruction Opération
CMP #nn ($C9) Comparer A avec nn (positionne N, Z, C)
CPX #nn ($E0) Comparer X avec nn
CPY #nn ($C0) Comparer Y avec nn

Exemples :

  1. LDA #$42          ; A = $42 (66 en decimal)
  2. LDX #0            ; X = 0
  3. LDY #255          ; Y = $FF
  4.  
  5. AND #$0F          ; masquer les 4 bits de poids fort
  6. ORA #$80          ; forcer le bit 7 a 1
  7. EOR #$FF          ; inverser tous les bits (complement a 1)
  8.  
  9. CMP #'A'          ; comparer A avec le code ASCII de 'A'
  10. BEQ EstUnA        ; brancher si A = 'A'
  11.  
  12. ADC #$01          ; A = A + 1 + C
  13. SBC #$10          ; A = A - $10 - NOT(C)

Formats numériques acceptes par les assembleurs :

  1. #$FF              ; hexadecimal (prefixe $)
  2. #%10110011        ; binaire (prefixe %)
  3. #255              ; decimal (pas de prefixe)
  4. #'A'              ; caractere ASCII
  5. #<$1234           ; poids faible ($34) de l'adresse $1234
  6. #>$1234           ; poids fort ($12) de l'adresse $1234

Remarques :

Adressage page zéro (Zero Page)

L'opérande est un octet en page zéro ($0000-$00FF). Seul l'octet de poids faible de l'adresse est spécifié dans l'instruction; l'octet de poids fort est implicitement $00.

Notation assembleur : $nn (adresse 8 bits sans préfixe #)

Taille de l'instruction : 2 octets (opcode + adresse 8 bits)

Nombre de cycles : 3 (lecture), 3 (écriture), 5 (lecture-modification-écriture : ASL, LSR, ROL, ROR, INC, DEC)

Formule : EA = $00nn

Instructions utilisant ce mode (exemples) :

Chargement/entreposage :

Instruction Opération
LDA $nn ($A5) A := [$00nn]
LDX $nn ($A6) X := [$00nn]
LDY $nn ($A4) Y := [$00nn]
STA $nn ($85) [$00nn] := A
STX $nn ($86) [$00nn] := X
STY $nn ($84) [$00nn] := Y

Arithmétique :

Instruction Opération
ADC $nn ($65) A := A + [$00nn] + C
SBC $nn ($E5) A := A - [$00nn] - NOT(C)

Logique :

Instruction Opération
AND $nn ($25) A := A AND [$00nn]
ORA $nn ($05) A := A OR [$00nn]
EOR $nn ($45) A := A XOR [$00nn]

Comparaison :

Instruction Opération
CMP $nn ($C5) Comparer A avec [$00nn]
CPX $nn ($E4) Comparer X avec [$00nn]
CPY $nn ($C4) Comparer Y avec [$00nn]

Modification mémoire :

Instruction Opération
INC $nn ($E6) [$00nn] := [$00nn] + 1
DEC $nn ($C6) [$00nn] := [$00nn] - 1
ASL $nn ($06) Décalage a gauche de [$00nn]
LSR $nn ($46) Décalage a droite de [$00nn]
ROL $nn ($26) Rotation a gauche de [$00nn]
ROR $nn ($66) Rotation a droite de [$00nn]

Test de bits :

Instruction Opération
BIT $nn ($24) teste les bits de [$00nn]
Z := A AND [$00nn] = 0
N := bit 7 de [$00nn]
V := bit 6 de [$00nn]

Exemples :

  1. LDA $80           ; A = contenu de l'adresse $0080
  2. STA $90           ; stocker A a l'adresse $0090
  3. INC $FF           ; incrementer le contenu de $00FF
  4. BIT $20           ; tester les bits a l'adresse $0020
  5.  
  6. ; Utiliser la page zero comme pseudo-registres
  7. LDA $80           ; charger le "pseudo-registre" a $80
  8. ADC $81           ; additionner avec le "pseudo-registre" a $81
  9. STA $82           ; stocker le resultat dans $82

Avantages par rapport a l'adressage absolu :

Remarques :

Adressage page zéro indexe par X (Zero Page,X)

L'adresse effective est calculée en ajoutant le contenu du registre X a l'adresse de base en page zéro. Le résultat est tronque a 8 bits (modulo 256), ce qui signifie que l'adresse reste TOUJOURS en page zéro, même en cas de débordement.

Notation assembleur : $nn,X

Taille de l'instruction : 2 octets (opcode + adresse 8 bits)

Nombre de cycles : 4 (lecture/écriture), 6 (lecture-modification-écriture)

Formule : EA = ($nn + X) AND $FF

(le résultat est toujours en page zéro)

Instructions utilisant ce mode :

Instruction Opération
LDA $nn,X ($B5) A := [($nn + X) AND $FF]
STA $nn,X ($95) [($nn + X) AND $FF] := A
LDY $nn,X ($B4) Y := [($nn + X) AND $FF]
STY $nn,X ($94) [($nn + X) AND $FF] := Y
ADC $nn,X ($75) A := A + [($nn + X) AND $FF] + C
SBC $nn,X ($F5) A := A - [($nn + X) AND $FF] - NOT(C)
AND $nn,X ($35) A := A AND [($nn + X) AND $FF]
ORA $nn,X ($15) A := A OR [($nn + X) AND $FF]
EOR $nn,X ($55) A := A XOR [($nn + X) AND $FF]
CMP $nn,X ($D5) Comparer A avec [($nn + X) AND $FF]
INC $nn,X ($F6) [($nn + X) AND $FF] += 1
DEC $nn,X ($D6) [($nn + X) AND $FF] -= 1
ASL $nn,X ($16) Décalage a gauche de [($nn + X) AND $FF]
LSR $nn,X ($56) Décalage a droite de [($nn + X) AND $FF]
ROL $nn,X ($36) Rotation a gauche de [($nn + X) AND $FF]
ROR $nn,X ($76) Rotation a droite de [($nn + X) AND $FF]

Exemples :

  1.     ; Tableau de 8 octets a partir de $80 en page zero
  2.     LDX #$03          ; index = 3
  3.     LDA $80,X         ; A = contenu de $0083 (= $80 + 3)
  4.     STA $88,X         ; stocker A a $008B (= $88 + 3)
  5.  
  6.     ; Boucle sur un tableau en page zero
  7.     LDX #$07          ; X = 7 (dernier element)
  8.   Boucle:
  9.     LDA $80,X         ; lire l'element X du tableau
  10.     STA $90,X         ; copier dans un autre tableau
  11.     DEX               ; X = X - 1
  12.     BPL Boucle        ; boucler tant que X >= 0
  13.  
  14.     ; Debordement silencieux (wrapping)
  15.     LDX #$80          ; X = $80 (128)
  16.     LDA $C0,X         ; EA = ($C0 + $80) AND $FF = $40
  17.                       ; lit a l'adresse $0040, PAS $0140

Remarques :

Adressage page zéro indexe par Y (Zero Page,Y)

Similaire au mode Zero Page,X mais utilise le registre Y comme index. Ce mode n'est disponible que pour les instructions LDX et STX. C'est un mode spécialisé pour les cas ou X est déjà utilisé comme index et ou l'on veut indexer LDX/STX par Y.

Notation assembleur : $nn,Y

Taille de l'instruction : 2 octets (opcode + adresse 8 bits)

Nombre de cycles : 4

Formule : EA = ($nn + Y) AND $FF

Instructions utilisant ce mode :

Instruction Opération
LDX $nn,Y ($B6) X := [($nn + Y) AND $FF]
STX $nn,Y ($96) [($nn + Y) AND $FF] := X

Exemples :

  1. ; Charger X depuis un tableau en page zero, indexe par Y
  2. LDY #$02          ; Y = 2
  3. LDX $80,Y         ; X = contenu de $0082 (= $80 + 2)
  4.  
  5. ; Entreposer X dans un tableau en page zero, indexe par Y
  6. LDY #$05
  7. STX $A0,Y         ; [$A0 + 5] = X, soit $00A5

Remarques :

Adressage absolu (Absolute)

L'opérande se trouve a une adresse 16 bits quelconque dans l'espace d'adressage de 64 Ko. L'adresse complète (2 octets) est codée dans l'instruction en format little-endian (poids faible d'abord, poids fort ensuite).

Notation assembleur : $nnnn (adresse 16 bits)

Taille de l'instruction : 3 octets (opcode + adresse 16 bits)

Nombre de cycles : 4 (lecture/écriture), 6 (lecture-modification-écriture), 3 (JMP), 6 (JSR)

Formule : EA = $hhll (ou ll = poids faible, hh = poids fort)

Codage en mémoire :

Adresse Description
Adresse n opcode
Adresse n+1 Poids faible de l'adresse (ll)
Adresse n+2 Poids fort de l'adresse (hh)

Instructions utilisant ce mode (exemples) :

Chargement/entreposage :

Instruction Opération
LDA $nnnn ($AD) A := [$nnnn]
LDX $nnnn ($AE) X := [$nnnn]
LDY $nnnn ($AC) Y := [$nnnn]
STA $nnnn ($8D) [$nnnn] := A
STX $nnnn ($8E) [$nnnn] := X
STY $nnnn ($8C) [$nnnn] := Y

Arithmétique et logique :

Instruction Opération
ADC $nnnn ($6D) A := A + [$nnnn] + C
SBC $nnnn ($ED) A := A - [$nnnn] - NOT(C)
AND $nnnn ($2D) A := A AND [$nnnn]
ORA $nnnn ($0D) A := A OR [$nnnn]
EOR $nnnn ($4D) A := A XOR [$nnnn]

Comparaison :

Instruction Opération
CMP $nnnn ($CD) Comparer A avec [$nnnn]
CPX $nnnn ($EC) Comparer X avec [$nnnn]
CPY $nnnn ($CC) Comparer Y avec [$nnnn]

Modification mémoire :

Instruction Opération
INC $nnnn ($EE) [$nnnn] := [$nnnn] + 1
DEC $nnnn ($CE) [$nnnn] := [$nnnn] - 1
ASL $nnnn ($0E) Décalage a gauche de [$nnnn]
LSR $nnnn ($4E) Décalage a droite de [$nnnn]
ROL $nnnn ($2E) Rotation a gauche de [$nnnn]
ROR $nnnn ($6E) Rotation a droite de [$nnnn]

Test de bits :

Instruction Opération
BIT $nnnn ($2C) Teste les bits de [$nnnn]

Contrôle du flux :

Instruction Opération
JMP $nnnn ($4C) PC := $nnnn (saut absolu, 3 cycles)
JSR $nnnn ($20) Empiler PC-1, PC := $nnnn (6 cycles)

Exemples :

  1. LDA $1234         ; A = contenu de l'adresse $1234
  2. STA $D020         ; stocker A dans le registre de couleur
  3.   ; de bordure du C64 (VIC-II)
  4. INC $0400         ; incrementer l'octet a l'adresse $0400
  5. JMP $C000         ; sauter a l'adresse $C000
  6. JSR $FFD2         ; appeler la routine CHROUT du Kernal C64
  7.  
  8. ; Codage de "LDA $1234" en memoire :
  9. ;   $AD $34 $12
  10. ;   (opcode, poids faible, poids fort = little-endian)

Remarques :

Adressage absolu indexe par X (Absolute,X)

L'adresse effective est calculée en ajoutant le contenu du registre X a une adresse de base de 16 bits. Contrairement au mode Zero Page,X, le résultat n'est pas tronque : l'addition se fait sur 16 bits.

Notation assembleur : $nnnn,X

Taille de l'instruction : 3 octets (opcode + adresse 16 bits)

Nombre de cycles : 4* (lecture), 5 (écriture), 7 (lecture-modification-écriture)

* : +1 cycle si le franchissement de page se produit (page boundary crossing)

Formule : EA = $nnnn + X (addition 16 bits)

Franchissement de page (page boundary crossing) :

Une "page" dans le contexte du 6502 est un bloc de 256 octets aligne ($xx00 a $xxFF). Un franchissement de page se produit quand l'ajout de X fait passer l'adresse dans la page suivante (l'octet de poids fort de l'adresse change).

Exemple sans franchissement :

Base = $10F0, X = $05 → EA = $10F5 (même page $10xx) → pas de cycle supplémentaire

Exemple avec franchissement : Base = $10F0, X = $20 → EA = $1110 (page $11xx, différente) → +1 cycle supplémentaire

Le cycle supplémentaire est du au fait que le 6502 calcule d'abord l'adresse avec l'octet de poids faible seul. Si une retenue se produit vers l'octet de poids fort, un cycle supplémentaire est nécessaire pour corriger l'adresse.

Instructions utilisant ce mode :

Instruction Opération
LDA $nnnn,X ($BD) A := [$nnnn + X]
STA $nnnn,X ($9D) [$nnnn + X] := A
(toujours 5 cycles)
LDY $nnnn,X ($BC) Y := [$nnnn + X]
ADC $nnnn,X ($7D) A := A + [$nnnn + X] + C
SBC $nnnn,X ($FD) A := A - [$nnnn + X] - NOT(C)
AND $nnnn,X ($3D) A := A AND [$nnnn + X]
ORA $nnnn,X ($1D) A := A OR [$nnnn + X]
EOR $nnnn,X ($5D) A := A XOR [$nnnn + X]
CMP $nnnn,X ($DD) Comparer A avec [$nnnn + X]
INC $nnnn,X ($FE) [$nnnn + X] += 1 (toujours 7 cycles)
DEC $nnnn,X ($DE) [$nnnn + X] -= 1
ASL $nnnn,X ($1E) Décalage a gauche de [$nnnn + X]
LSR $nnnn,X ($5E) Décalage a droite de [$nnnn + X]
ROL $nnnn,X ($3E) Rotation a gauche de [$nnnn + X]
ROR $nnnn,X ($7E) Rotation a droite de [$nnnn + X]

Exemples :

  1.     ; Parcourir un tableau de 256 octets a partir de $2000
  2.     LDX #$00
  3.   Boucle:
  4.     LDA $2000,X       ; lire l'octet X du tableau
  5.     STA $0400,X       ; copier vers l'ecran (C64)
  6.     INX
  7.     BNE Boucle        ; boucler tant que X != 0
  8.  
  9.     ; Acces a un tableau de plus de 256 elements avec index
  10.     ; sur 16 bits (poids faible dans X, poids fort ajoute a l'adresse)
  11.     ; Lire l'element a l'offset $0103 du tableau :
  12.     LDA Table+$01,X   ; ou X = $03, Table est la base
  13.                       ; EA = Table + $0100 + $03 = Table + $0103

Remarques :

Adressage absolu indexe par Y (Absolute,Y)

Identique a Absolute,X mais utilise le registre Y comme index. Ce mode est disponible pour un sous-ensemble d'instructions plus restreint que Absolute,X.

Notation assembleur : $nnnn,Y

Taille de l'instruction : 3 octets (opcode + adresse 16 bits)

Nombre de cycles : 4* (lecture), 5 (ecriture)

* : +1 cycle si franchissement de page

Formule : EA = $nnnn + Y (addition 16 bits)

Instructions utilisant ce mode :

Instruction Opération
LDA $nnnn,Y ($B9) A := [$nnnn + Y]
STA $nnnn,Y ($99) [$nnnn + Y] := A (toujours 5 cycles)
LDX $nnnn,Y ($BE) X := [$nnnn + Y]
ADC $nnnn,Y ($79) A := A + [$nnnn + Y] + C
SBC $nnnn,Y ($F9) A := A - [$nnnn + Y] - NOT(C)
AND $nnnn,Y ($39) A := A AND [$nnnn + Y]
ORA $nnnn,Y ($19) A := A OR [$nnnn + Y]
EOR $nnnn,Y ($59) A := A XOR [$nnnn + Y]
CMP $nnnn,Y ($D9) comparer A avec [$nnnn + Y]

Exemples :

  1.     ; Copier 256 octets de $2000 vers $3000
  2.     LDY #$00
  3.   Boucle:
  4.     LDA $2000,Y       ; lire depuis la source
  5.     STA $3000,Y       ; ecrire vers la destination
  6.     INY
  7.     BNE Boucle        ; boucler tant que Y != 0
  8.  
  9.     ; Charger X depuis un tableau indexe par Y
  10.     LDX Table,Y       ; X = Table[Y]

Remarques :

Adressage indirect (Indirect)

L'adresse effective est lue depuis un emplacement mémoire de 16 bits. Le processeur lit d'abord un pointeur (2 octets) a l'adresse spécifiée, puis utilise cette valeur comme adresse effective. Ce mode n'est utilise que par l'instruction JMP.

Notation assembleur : ($nnnn)

Taille de l'instruction : 3 octets (opcode + adresse 16 bits)

Nombre de cycles : 5

Formule : EA = [[$nnnn+1] << 8 | [$nnnn]]

(lire un pointeur 16 bits little-endian a l'adresse $nnnn)

Instructions utilisant ce mode :

Instruction Opération
JMP ($nnnn) ($6C) PC := [[$nnnn+1]:[$nnnn]]

Exemples :

  1. ; Saut indirect via un vecteur en memoire
  2. JMP ($FFFC)       ; sauter a l'adresse contenue dans le
  3.   ; vecteur de RESET ($FFFC-$FFFD)
  4.  
  5. ; Table de saut
  6. ; En memoire :
  7. ;   $2000 : $00 $C0  -> pointe vers $C000
  8. ;   $2002 : $00 $D0  -> pointe vers $D000
  9. JMP ($2000)       ; PC := $C000
  10.  
  11. ; Vecteur de saut modifiable
  12. LDA #<Routine     ; poids faible de l'adresse de Routine
  13. STA VecteurJmp
  14. LDA #>Routine     ; poids fort de l'adresse de Routine
  15. STA VecteurJmp+1
  16. JMP (VecteurJmp)  ; sauter a Routine

BUG IMPORTANT du 6502 NMOS (JMP indirect sur limite de page) :

Si l'adresse du pointeur se trouve en fin de page (octet de poids faible = $FF), le 6502 NMOS ne franchit PAS la page pour lire l'octet de poids fort du pointeur. Au lieu de lire l'octet suivant a la page suivante, il lit l'octet au début de la MEME page.

Exemple du bug :

Ce bug affecte TOUS les 6502 NMOS (y compris le 6510 du C64 et le 2A03 de la NES). Il est corrige sur le 65C02 (CMOS).

Contournement :

Remarques :

Adressage indirect indexe par X (Indexed Indirect, (Ind,X))

Aussi appelé "Indexed Indirect" ou "Pre-Indexed Indirect". Le registre X est ajoute a une adresse en page zéro, et le résultat (tronque a 8 bits) pointe vers un emplacement en page zéro contenant l'adresse effective 16 bits (le pointeur).

Notation assembleur : ($nn,X)

Taille de l'instruction : 2 octets (opcode + adresse page zéro)

Nombre de cycles : 6

Formule :

pointeur = ($nn + X) AND $FF
EA = [[$0000 + pointeur + 1] << 8 | [$0000 + pointeur]]

Étapes détaillées :

Instructions utilisant ce mode :

Instruction Opération
LDA ($nn,X) ($A1) A := [[($nn + X) AND $FF]]
STA ($nn,X) ($81) [[($nn + X) AND $FF]] := A
ADC ($nn,X) ($61) A := A + [[($nn + X) AND $FF]] + C
SBC ($nn,X) ($E1) A := A - [[($nn + X) AND $FF]] - NOT(C)
AND ($nn,X) ($21) A := A AND [[($nn + X) AND $FF]]
ORA ($nn,X) ($01) A := A OR [[($nn + X) AND $FF]]
EOR ($nn,X) ($41) A := A XOR [[($nn + X) AND $FF]]
CMP ($nn,X) ($C1) Comparer A avec [[($nn + X) AND $FF]]

Exemples :

  1.     ; Table de pointeurs en page zero
  2.     ; $80-$81 : pointeur 0 = $2000
  3.     ; $82-$83 : pointeur 1 = $3000
  4.     ; $84-$85 : pointeur 2 = $4000
  5.     LDX #$02          ; index = 1 (2 octets par pointeur)
  6.     LDA ($80,X)       ; ptr = ($80+2) AND $FF = $82
  7.                       ; lit le pointeur a $82-$83 = $3000
  8.                       ; A = contenu de $3000
  9.  
  10.     ; Avec X = 0, equivalent a de l'indirect simple
  11.     LDX #$00
  12.     LDA ($80,X)       ; ptr = $80, lit pointeur a $80-$81
  13.                       ; A = contenu de l'adresse pointee par $80-$81
  14.  
  15.     ; Parcourir une table de pointeurs
  16.     LDX #$00
  17.   Boucle:
  18.     LDA ($80,X)       ; lire la donnee pointee par le pointeur X/2
  19.     ; ... traitement ...
  20.     INX
  21.     INX               ; X += 2 (avancer au pointeur suivant)
  22.     CPX #$06          ; 3 pointeurs * 2 octets = 6
  23.     BNE Boucle

Schéma mémoire (exemple avec $80,X ou X=$02) :

Page zéro :

  1. $80 : $00 $20   ; pointeur 0 -> $2000
  2. $82 : $00 $30   ; pointeur 1 -> $3000  <- selectionne (X=2)
  3. $84 : $00 $40   ; pointeur 2 -> $4000

Mémoire :

  1. $3000 : $42      ; <- donnee lue par LDA ($80,X)

Remarques :

Adressage indirect indexe par Y (Indirect Indexed, (Ind),Y)

Aussi appelé "Indirect Indexed" ou "Post-Indexed Indirect". C'est l'un des modes d'adressage les plus importants du 6502. Un pointeur 16 bits est d'abord lu depuis la page zero, puis le registre Y est ajoute a cette adresse pour former l'adresse effective.

Notation assembleur : ($nn),Y

Taille de l'instruction : 2 octets (opcode + adresse page zero)

Nombre de cycles : 5* (lecture), 6 (écriture)

* : +1 cycle si franchissement de page

Formule :

base = [[$0000 + $nn + 1] << 8 | [$0000 + $nn]]
EA = base + Y (addition 16 bits)

Étapes détaillées :

Instructions utilisant ce mode :

Instruction Opération
LDA ($nn),Y ($B1) A := [[$nn] + Y] (pointeur en page zéro)
STA ($nn),Y ($91) [[$nn] + Y] := A (toujours 6 cycles)
ADC ($nn),Y ($71) A := A + [[$nn] + Y] + C
SBC ($nn),Y ($F1) A := A - [[$nn] + Y] - NOT(C)
AND ($nn),Y ($31) A := A AND [[$nn] + Y]
ORA ($nn),Y ($11) A := A OR [[$nn] + Y]
EOR ($nn),Y ($51) A := A XOR [[$nn] + Y]
CMP ($nn),Y ($D1) comparer A avec [[$nn] + Y]

Exemples :

  1.     ; Pointeur vers un buffer a $80-$81
  2.     ; $80 = $00, $81 = $20 -> pointeur = $2000
  3.     LDY #$05
  4.     LDA ($80),Y       ; lit le pointeur $2000 a $80-$81
  5.                       ; A = contenu de $2000 + $05 = $2005
  6.  
  7.     ; Copier un bloc de memoire avec pointeur source et destination
  8.     ; $80-$81 = pointeur source
  9.     ; $82-$83 = pointeur destination
  10.     LDY #$00
  11.   Boucle:
  12.     LDA ($80),Y       ; lire un octet depuis la source
  13.     STA ($82),Y       ; ecrire a la destination
  14.     INY
  15.     CPY #$40          ; copier 64 octets
  16.     BNE Boucle
  17.  
  18.     ; Parcourir une chaine ASCIIZ pointee par $80-$81
  19.     LDY #$00
  20.   Boucle:
  21.     LDA ($80),Y       ; lire le caractere courant
  22.     BEQ Fin           ; si zero, fin de chaine
  23.     JSR AfficherChar  ; afficher le caractere
  24.     INY
  25.     BNE Boucle        ; boucler (max 256 caracteres)
  26.   Fin:
  27.  
  28.     ; Copier un bloc de plus de 256 octets
  29.     ; (incrementer le poids fort du pointeur)
  30.     LDY #$00
  31.     LDX #$04          ; 4 pages = 1024 octets
  32.   BouclePage:
  33.     LDA ($80),Y       ; lire depuis la source
  34.     STA ($82),Y       ; ecrire vers la destination
  35.     INY
  36.     BNE BouclePage    ; boucle interne (256 octets)
  37.     INC $81           ; page suivante (source)
  38.     INC $83           ; page suivante (destination)
  39.     DEX
  40.     BNE BouclePage    ; boucle externe (pages)

Schéma mémoire (exemple avec ($80),Y ou Y=$05) :

Page zéro :

  1. $80 : $00        ; poids faible du pointeur
  2. $81 : $20        ; poids fort du pointeur -> $2000

Mémoire :

  1. $2000 : ...
  2. $2005 : $42      ; <- donnee lue (base $2000 + Y $05)

Remarques :

Différence entre ($nn,X) et ($nn),Y :

Adressage Description
($nn,X) Pre-indexe → X sélectionne QUEL pointeur utiliser EA = [table_de_pointeurs + X]. Utile pour : tables de pointeurs, dispatch
($nn),Y Post-indexe → Y est un OFFSET dans les données EA = [pointeur] + Y. Utile pour : parcours de tableaux, accès a des structures via un pointeur de base.

Adressage relatif (Relative)

L'adresse effective est calculée en ajoutant un déplacement signe de 8 bits a l'adresse de l'instruction SUIVANT le branchement. Ce mode est utilisé exclusivement par les instructions de branchement conditionnel.

Notation assembleur : label (l'assembleur calcule le déplacement)

Taille de l'instruction : 2 octets (opcode + déplacement 8 bits)

Nombre de cycles : 2 (branchement non pris), 3 (branchement pris, même page), 4 (branchement pris, franchissement de page)

Formule : EA = PC + deplacement_signe (ou PC est l'adresse de l'instruction suivant le branchement, c'est-a-dire l'adresse du branchement + 2)

Déplacement :

Instructions utilisant ce mode :

Instruction Opération
BCC ($90) Brancher si C = 0 (Carry Clear)
BCS ($B0) Brancher si C = 1 (Carry Set)
BEQ ($F0) Brancher si Z = 1 (Equal / Zero)
BNE ($D0) Brancher si Z = 0 (Not Equal / Not Zero)
BMI ($30) Brancher si N = 1 (Minus / Negative)
BPL ($10) Brancher si N = 0 (Plus / Positive)
BVC ($50) Brancher si V = 0 (Overflow Clear)
BVS ($70) Brancher si V = 1 (Overflow Set)

Utilisation pour les comparaisons :

Instruction Opération
CMP #val / BCC label Brancher si A < val (non signe)
CMP #val / BCS label Brancher si A >= val (non signe)
CMP #val / BEQ label Brancher si A = val
CMP #val / BNE label Brancher si A != val
CMP #val / BMI label Brancher si A < val (signe, approx.)
CMP #val / BPL label Brancher si A >= val (signe, approx.)

Exemples :

  1. ; Boucle simple
  2. LDX #$10        ; X = 16
  3. Boucle:
  4. DEX             ; X = X - 1
  5. BNE Boucle      ; boucler tant que X != 0
  6.  
  7. ; Test et branchement
  8. LDA Score
  9. CMP #100        ; score >= 100 ?
  10. BCS NiveauSuivant  ; oui, passer au niveau suivant
  11.  
  12. ; Branchement hors de portee (contournement)
  13. ; Si la cible est trop loin pour un deplacement de 8 bits :
  14. BEQ ProcheLabel ; si egal, sauter a ProcheLabel
  15. JMP Suite       ; sinon, continuer
  16. ProcheLabel:
  17. JMP LoinLabel   ; sauter a la cible eloignee
  18. Suite:
  19. ; ... code ...
  20.  
  21. ; Equivalent de "BRA" (branchement inconditionnel) sur 6502 :
  22. ; Le 6502 n'a PAS d'instruction BRA. On peut simuler :
  23. CLC
  24. BCC Toujours    ; BCC apres CLC branche toujours
  25. ; Ou :
  26. JMP Toujours    ; mais prend 3 octets au lieu de 2

Calcul du déplacement par l'assembleur :

L'assembleur calcule automatiquement le déplacement :

déplacement = adresse_cible - (adresse_branchement + 2)

Exemple : branchement a $1000 depuis $0FF0

déplacement = $1000 - ($0FF0 + 2) = $1000 - $0FF2 = $0E
→ BNE $0E (déplacement positif de 14)

Exemple : branchement a $0FE0 depuis $1000

déplacement = $0FE0 - ($1000 + 2) = $0FE0 - $1002 = $FFDE
→ En signe 8 bits : $DE = -34
→ BNE $DE (déplacement négatif de 34)

Timing des branchements :

Ce comportement asymétrique est important pour l'optimisation :

Remarques :

Résumé et tableau comparatif

Les 13 modes d'adressage du 6502 :

No Mode Syntaxe Taille Formule EA
1 Implicite (aucune) 1 octet (pas d'EA)
2 Accumulateur A 1 octet (pas d'EA, agit sur A)
3 Immediat #$nn 2 octets operande = nn
4 Page zero $nn 2 octets EA = $00nn
5 Page zero,X $nn,X 2 octets EA = ($nn+X) AND $FF
6 Page zero,Y $nn,Y 2 octets EA = ($nn+Y) AND $FF
7 Absolu $nnnn 3 octets EA = $nnnn
8 Absolu,X $nnnn,X 3 octets EA = $nnnn + X
9 Absolu,Y $nnnn,Y 3 octets EA = $nnnn + Y
10 Indirect ($nnnn) 3 octets EA = [$nnnn]
11 Indirect indexe X ($nn,X) 2 octets EA = [($nn+X) AND $FF]
12 Indirect indexe Y ($nn),Y 2 octets EA = [$nn] + Y
13 Relatif $rr 2 octets EA = PC + déplacement

Nombre de cycles par mode (lecture) :

Mode Cycles Cycles (écriture) Page cross
Implicite 2 - -
Accumulateur 2 - -
Immédiat 2 - -
Page zéro 3 3 -
Page zero,X 4 4 -
Page zero,Y 4 4 -
Absolu 4 4 -
Absolu,X 4(+1) 5 +1 cycle
Absolu,Y 4(+1) 5 +1 cycle
Indirect - - -
Indirect indexe X 6 6 -
Indirect indexe Y 5(+1) 6 +1 cycle
Relatif (pris) 3(+1) - +1 cycle
Relatif (non pris) 2 - -

Comparaison avec le Z80 :

Aspect 6502 Z80
Nombre de modes 13 ~10
Page zero / directe Oui ($00-$FF) Non
Indexe avec offset Non (sauf indirects) Oui (IX+d, IY+d)
Indirect registre Via page zero (HL), (BC), (DE)
Post-increment Non Non (sauf LDI/LDD)
Pre-decrement Non Non (sauf LDI/LDD)
Relatif (données) Non Non
Relatif (branchements) Oui (8 bits signe) Oui (8 bits signe)
Immediat 16 bits Non Oui (LD rr,nn)
Bit indexation Non Oui (BIT/SET/RES)
Espace adressable 64 Ko 64 Ko

Comparaison avec le 68000 :

Aspect 6502 68000
Nombre de modes 13 14
Auto-increment Non (An)+
Auto-decrement Non -(An)
Indirect registre Via page zero (An)
Indirect + offset ($nn),Y (8 bits) d16(An)
Indirect indexe ($nn,X), ($nn),Y d8(An,Xn)
Absolu court Page zéro (8 bits) (xxx).W (16 bits)
Absolu long 16 bits 32 bits
PC-relatif (données) Non d16(PC), d8(PC,Xn)
PC-relatif (branches) Oui (8 bits) Oui (8/16/32 bits)
Immediat 8 bits 8/16/32 bits
Page zéro Oui (256 octets) Non

Le 6502 compense son faible nombre de registres par l'utilisation intensive de la page zéro comme extension des registres internes. Les modes d'adressage indirects via la page zéro permettent de manipuler des pointeurs 16 bits avec seulement des registres de 8 bits, ce qui est l'une des innovations clefs de l'architecture du 6502.



Dernière mise à jour : Dimanche, le 22 mars 2026