Section courante

A propos

Section administrative du site

Gestion des interruptions

Types d'interruptions

Le 6502 possède trois types d'interruptions, plus le signal de réinitialisation (RESET). Contrairement au 68000 (256 vecteurs) ou au 80386 (256 entrées dans l'IDT), le 6502 ne dispose que de trois vecteurs fixes en fin de mémoire.

Les quatre événements interrompant le flux normal d'exécution :

Événement Type Masquable Vecteur Priorité
RESET Réinitialisé Non $FFFC-$FFFD 1 (max)
NMI Materielle Non $FFFA-$FFFB 2
IRQ Materielle Oui (I=1) $FFFE-$FFFF 3
BRK Logicielle Oui (I=1) $FFFE-$FFFF 4 (minimum)

Points clefs :

Comparaison avec d'autres microprocesseurs :

Microprocesseur Vecteurs Masquage Priorités
MOS 6502 3 fixes 1 bit (I) Fixe : RESET > NMI > IRQ
Zilog Z80 3 modes EI/DI 3 modes (0,1,2)
Intel 8080 8 (RST) EI/DI Fixe
Motorola 6800 3 fixes 1 bit (I) Fixe : RESET > NMI > IRQ
Motorola 6809 7 vecteurs 2 bits (I,F) RESET > NMI > FIRQ > IRQ > SWI
Motorola 68000 256 3 bits IPL 7 niveaux + NMI
Intel 80386 256 (IDT) IF + PIC Programmable via PIC

Interruption matérielle (IRQ)

L'IRQ (Interrupt Request) est le mécanisme d'interruption principal du 6502. La ligne IRQ est active a l'état bas (active low) et sensible au niveau (level-triggered).

Caractéristiques de la ligne IRQ

Caractéristique Description
Signal Actif a l'état bas (0 = demande d'interruption)
Type Sensible au niveau (level-triggered)
Masquable Oui, par le drapeau I du registre P
Vecteur $FFFE-$FFFF
Latence 7 cycles minimum

La ligne IRQ est généralement un bus a collecteur ouvert (open collector / open drain), ce qui permet a plusieurs périphériques de partager la même ligne. Quand un périphérique veut interrompre le processeur, il tire la ligne IRQ a l'état bas. La ligne remonte a l'état haut (via une résistance de rappel) quand tous les périphériques ont relâché la ligne.

Sensibilité au niveau

Puisque la ligne IRQ est sensible au NIVEAU (et non au front), le microprocesseur continue de détecter une demande d'interruption tant que la ligne reste à l'état bas. Cela implique :

Exemple de partage IRQ sur le Commodore 64 :

  1. IRQ_Handler:
  2.   ; Verifier quel peripherique a cause l'interruption
  3.   LDA $D019        ; registre d'etat des interruptions du VIC-II
  4.   BMI VIC_IRQ      ; bit 7 = 1 si le VIC-II a cause l'IRQ
  5.   LDA $DC0D        ; registre d'etat du CIA #1
  6.   BMI CIA1_IRQ     ; bit 7 = 1 si le CIA #1 a cause l'IRQ
  7.   LDA $DD0D        ; registre d'etat du CIA #2
  8.   BMI CIA2_IRQ     ; bit 7 = 1 si le CIA #2 a cause l'IRQ
  9.   JMP Fin_IRQ      ; pas d'interruption identifiee (spurious)
  10.  
  11. VIC_IRQ:
  12.   STA $D019        ; acquitter l'interruption du VIC-II
  13.   ; ... traiter l'interruption VIC-II ...
  14.   JMP Fin_IRQ
  15.  
  16. CIA1_IRQ:
  17.   ; (la lecture de $DC0D acquitte automatiquement)
  18.   ; ... traiter l'interruption CIA #1 ...
  19.   JMP Fin_IRQ
  20.  
  21. CIA2_IRQ:
  22.   ; (la lecture de $DD0D acquitte automatiquement)
  23.   ; ... traiter l'interruption CIA #2 ...
  24.  
  25. Fin_IRQ:
  26.   PLA              ; restaurer A (si empile au debut)
  27.   TAX              ; etc.
  28.   RTI

Masquage des IRQ

Le drapeau I (Interrupt Disable) du registre P contrôle si les interruptions IRQ sont acceptées :

Instructions pour contrôler le masquage :

  1. SEI    ; I := 1 (masquer les IRQ)
  2. CLI    ; I := 0 (autoriser les IRQ)

Lors du traitement d'une interruption (IRQ ou NMI), le processeur met automatiquement I a 1 pour empêcher les interruptions imbriquées. Le programmeur peut re-autoriser les interruptions dans le descripteur avec CLI si les interruptions imbriquées sont désirées.

Séquence typique de section critique :

  1. SEI              ; desactiver les IRQ
  2. ; ... code critique (pas d'interruption possible) ...
  3. LDA compteur     ; lecture atomique d'une variable
  4. STA copie        ;   partagee avec le handler
  5. CLI              ; re-autoriser les IRQ

Sources d'IRQ typiques par machine

Commodore 64 :

Apple II :

NES (Nintendo) :

Atari 2600 :

Interruption non masquable (NMI)

La NMI (Non-Maskable Interrupt) est une interruption qui ne peut PAS être masquée par le drapeau I. Elle est prioritaire sur l'IRQ.

Caractéristiques de la ligne NMI

Caractéristique Description
Signal Actif sur front descendant (edge-triggered)
Type Sensible au front (falling edge)
Masquable Non (le drapeau I est ignore)
Vecteur $FFFA-$FFFB
Latence 7 cycles minimum

Différence cruciale avec l'IRQ : la NMI est détectée sur le FRONT descendant (passage de haut a bas), et non sur le niveau. Cela signifie :

Détection du front descendant

Le 6502 échantillonne la ligne NMI a chaque cycle d'horloge.

Le front descendant est détecté quand :

Cette détection par front a des conséquences importantes :

Sources de NMI typiques par machine

Commodore 64 :

NES (Nintendo) :

Apple II :

Atari 800/XL/XE :

Exemple : descripteur NMI sur la NES

  1. NMI_Handler:
  2.   PHA              ; sauvegarder A
  3.   TXA
  4.   PHA              ; sauvegarder X
  5.   TYA
  6.   PHA              ; sauvegarder Y
  7.  
  8.   ; Lire le registre d'etat du PPU pour acquitter la NMI
  9.   LDA $2002        ; PPUSTATUS - aussi remet le latch d'adresse
  10.  
  11.   ; Effectuer les mises a jour graphiques pendant le VBlank
  12.   ; (ecriture OAM, mise a jour de la nametable, etc.)
  13.   LDA #$00
  14.   STA $2003        ; OAMADDR = 0
  15.   LDA #$02
  16.   STA $4014        ; DMA OAM depuis la page $0200
  17.  
  18.   ; Mettre a jour le defilement
  19.   LDA scroll_x
  20.   STA $2005        ; defilement horizontal
  21.   LDA scroll_y
  22.   STA $2005        ; defilement vertical
  23.  
  24.   ; Restaurer les registres
  25.   PLA
  26.   TAY              ; restaurer Y
  27.   PLA
  28.   TAX              ; restaurer X
  29.   PLA              ; restaurer A
  30.   RTI

Interruption logicielle (BRK)

L'instruction BRK déclenche une interruption logicielle. C'est l'équivalent du TRAP du 68000 ou de l'INT du 80386.

Comportement de BRK

Caractéristique Description
Opcode $00
Taille 1 octet (mais consomme 2 octets)
Cycles 7
Vecteur $FFFE-$FFFF (même vecteur que IRQ)
Drapeau B Mis a 1 dans la copie empilée de P

Séquence d'exécution de BRK :

L'octet signature (padding byte)

BRK avance le PC de 2 (et non de 1), ce qui fait que l'octet immédiatement après BRK est saute. Cet octet est appelé "signature byte" ou "padding byte" et peut etre utilise pour transmettre une information au descripteur :

  1. BRK
  2. .BYTE $01        ; signature : code de la fonction demandee

Dans le descripteur, pour récupérer la signature :

  1. ; Le PC empile pointe sur l'octet APRES la signature
  2. ; Donc PC_empile - 1 = adresse de la signature
  3. Handler_BRK:
  4.   PLA              ; recuperer P depuis la pile
  5.   PHA              ; le remettre
  6.   TSX              ; X := SP
  7.   LDA $0102,X      ; lire PCL depuis la pile (SP+2)
  8.   SEC
  9.   SBC #$01         ; PCL - 1
  10.   STA ptr_low
  11.   LDA $0103,X      ; lire PCH depuis la pile (SP+3)
  12.   SBC #$00         ; propager le borrow
  13.   STA ptr_high
  14.   ; (ptr_low, ptr_high) pointe maintenant sur la signature
  15.   LDY #$00
  16.   LDA (ptr_low),Y  ; lire la signature
  17.   ; Dispatcher selon la valeur de la signature...

Distinction BRK / IRQ

Puisque BRK et IRQ partagent le même vecteur ($FFFE-$FFFF), le descripteur doit les distinguer en examinant le drapeau B dans la copie de P empilée sur la pile :

Le drapeau B n'existe pas physiquement dans le registre P ; il n'est présent que dans la copie empilée.

Code typique de distinction :

  1. IRQ_BRK_Handler:
  2.   PHA              ; sauvegarder A
  3.   TXA
  4.   PHA              ; sauvegarder X
  5.   TYA
  6.   PHA              ; sauvegarder Y
  7.  
  8.   TSX              ; X := SP
  9.   LDA $0104,X      ; lire la copie de P depuis la pile
  10. ; (offset 4 car on a empile 3 registres)
  11.   AND #$10         ; tester le bit B (bit 4)
  12.   BNE Est_BRK      ; si B=1, c'est un BRK
  13.  
  14. Est_IRQ:
  15.   ; ... traiter l'IRQ ...
  16.   JMP Fin_Handler
  17.  
  18. Est_BRK:
  19.   ; ... traiter le BRK ...
  20.  
  21. Fin_Handler:
  22.   PLA
  23.   TAY              ; restaurer Y
  24.   PLA
  25.   TAX              ; restaurer X
  26.   PLA              ; restaurer A
  27.   RTI

Utilisations de BRK

Bug connu : BRK + IRQ simultanée

Si une IRQ se produit exactement au même moment qu'un BRK, le comportement du 6502 NMOS est le suivant :

Ce bug est corrigé sur le 65C02 (CMOS).

Vecteurs d'interruption

Les vecteurs d'interruption sont situés aux six derniers octets de l'espace d'adressage, dans la page $FFxx :

Adresse Contenu Événement
$FFFA NMI vector (low byte) Interruption NMI
$FFFB NMI vector (high byte)
$FFFC RESET vector (low) Réinitialisation
$FFFD RESET vector (high)
$FFFE IRQ/BRK vector (low) Interruption IRQ ou BRK
$FFFF IRQ/BRK vector (high)

Chaque vecteur est une adresse 16 bits entreposée en format little-endian (octet de poids faible d'abord).

Placement des vecteurs en mémoire

Sur la plupart des systèmes, les vecteurs se trouvent en ROM (mémoire morte) car ils doivent être disponibles au démarrage avant toute initialisation du système.

Les valeurs typiques des vecteurs par machine :

Commodore 64 (ROM KERNAL) :

Adresse Description
$FFFA-$FFFB $FE43 (NMI → routine KERNAL NMI)
$FFFC-$FFFD $FCE2 (RESET → initialisation système)
$FFFE-$FFFF $FF48 (IRQ/BRK → routine KERNAL IRQ)

Apple II :

Adresse Description
$FFFA-$FFFB $0000 (NMI - pas utilise en standard)
$FFFC-$FFFD Varie selon la ROM
$FFFE-$FFFF Pointe vers le descripteur dans le moniteur

NES (Nintendo) :

Les vecteurs sont dans la ROM de la cartouche. Chaque ensemble définit ses propres vecteurs.

Exemple typique (assembleur) :

  1. .ORG $FFFA
  2. .WORD NMI_Handler    ; adresse du descripteur NMI
  3. .WORD RESET_Handler  ; adresse du descripteur RESET
  4. .WORD IRQ_Handler    ; adresse du descripteur IRQ/BRK

Atari 2600 :

Adresse Description
$FFFA-$FFFB Adresse du descripteur NMI (pas utilise)
$FFFC-$FFFD Adresse du point d'entrée du programme
$FFFE-$FFFF Adresse du descripteur IRQ/BRK

Redirection des vecteurs (vectoring par RAM)

Puisque les vecteurs sont en ROM, il est impossible de les modifier directement. La plupart des systèmes utilisent un mécanisme de redirection par RAM : le descripteur en ROM lit une adresse en RAM et saute a cette adresse avec un JMP indirect.

Exemple sur le Commodore 64 :

Le descripteur IRQ en ROM ($FF48) fait :

  1. PHA
  2. TXA
  3. PHA
  4. TYA
  5. PHA
  6. TSX
  7. LDA $0104,X    ; lire P empile
  8. AND #$10       ; tester bit B
  9. BNE BRK_entry  ; si BRK, aller au descripteur BRK
  10. JMP ($0314)    ; sinon, sauter au vecteur RAM IRQ

Les vecteurs RAM du C64 sont :

Adresse Description
$0314-$0315 Vecteur IRQ (defaut = $EA31, routine KERNAL)
$0316-$0317 Vecteur BRK (defaut = $FE66, routine KERNAL)
$0318-$0319 Vecteur NMI (defaut = $FE47, routine KERNAL)

Pour installer un descripteur IRQ personnalisé :

  1.   SEI              ; desactiver les IRQ
  2.   LDA #<Mon_IRQ    ; low byte de l'adresse du descripteur
  3.   STA $0314
  4.   LDA #>Mon_IRQ    ; high byte
  5.   STA $0315
  6.   CLI              ; re-autoriser les IRQ
  7.  
  8. Mon_IRQ:
  9.   ; ... code personnalise ...
  10.   JMP $EA31        ; chainer avec le descripteur par defaut
  11. ; (ou JMP $EA81 pour sauter le scan clavier)

Séquence de traitement d'une interruption

Séquence IRQ (7 cycles)

Quand le processeur détecte une demande IRQ et que I=0 :

Cycle Action
1 Lecture de l'opcode a PC (instruction interrompue est terminée avant de traiter l'IRQ)
2 Lecture de l'octet suivant (ignore)
3 Empiler PCH a l'adresse $0100+SP, SP := SP-1
4 Empiler PCL a l'adresse $0100+SP, SP := SP-1
5 Empiler P a l'adresse $0100+SP (avec B=0), SP := SP-1, mettre I := 1
6 Lire PCL := [$FFFE]
7 Lire PCH := [$FFFF]

État de la pile après le traitement :

Adresse Contenu
$0100+SP+3 PCH (octet haut de l'adresse de retour)
$0100+SP+2 PCL (octet bas de l'adresse de retour)
$0100+SP+1 P (registre d'état, avec B=0 pour IRQ)

Le PC empile pointe sur l'instruction qui aurait été exécutée si l'interruption n'avait pas eu lieu.

Séquence NMI (7 cycles)

La séquence NMI est identique a celle de l'IRQ, sauf :

Cycle Action
1 Lecture de l'opcode a PC (ignore)
2 Lecture de l'octet suivant (ignore)
3 Empiler PCH a l'adresse $0100+SP, SP := SP-1
4 Empiler PCL a l'adresse $0100+SP, SP := SP-1
5 Empiler P a l'adresse $0100+SP (avec B=0), SP := SP-1, mettre I := 1
6 Lire PCL := [$FFFA]
7 Lire PCH := [$FFFB]

Séquence BRK (7 cycles)

La séquence BRK est similaire a celle de l'IRQ, mais :

Cycle Action
1 Lecture de l'opcode ($00) a PC
2 Lecture de l'octet suivant (signature), PC := PC+2
3 Empiler PCH a l'adresse $0100+SP, SP := SP-1
4 Empiler PCL a l'adresse $0100+SP, SP := SP-1
5 Empiler P a l'adresse $0100+SP (avec B=1), SP := SP-1, mettre I := 1
6 Lire PCL := [$FFFE]
7 Lire PCH := [$FFFF]

Séquence RESET

Le RESET est différent des autres interruptions : il ne sauvegarde pas de contexte sur la pile. Il réinitialise le microprocesseur a un état connu.

Cycle Action
1-6 Le microprocesseur effectue des cycles internes (similaires a une interruption mais les écritures sur la pile sont transformées en lectures)
SP := SP - 3 (le pointeur de pile est décrementé mais rien n'est écrit)
7 Mettre I := 1 (masquer les IRQ)
Mettre D := 0 (désactiver le mode décimal sur 65C02)
8 Lire PCL := [$FFFC]
9 Lire PCH := [$FFFD]

État du processeur après RESET :

Note : le RESET ne réinitialise PAS les registres A, X, Y ni le contenu de la RAM. Seuls le PC (charge depuis le vecteur), le drapeau I (mis a 1) et le SP (décrémenté) sont affectés. Le code d'initialisation au vecteur RESET doit initialiser explicitement tous les registres et la mémoire.

Code typique d'initialisation au RESET :

  1. RESET_Handler:
  2.   SEI              ; masquer les IRQ (deja fait par le RESET
  3. ; mais par securite)
  4.   CLD              ; desactiver le mode decimal
  5.   LDX #$FF
  6.   TXS              ; initialiser le pointeur de pile a $FF
  7.  
  8.   ; Initialiser la RAM a zero
  9.   LDA #$00
  10.   TAX
  11. Clear_RAM:
  12.   STA $0000,X
  13.   STA $0100,X
  14.   STA $0200,X
  15.   STA $0300,X
  16.   STA $0400,X
  17.   STA $0500,X
  18.   STA $0600,X
  19.   STA $0700,X
  20.   INX
  21.   BNE Clear_RAM
  22.  
  23.   ; Initialiser le materiel
  24.   ; ... (depend du systeme) ...
  25.  
  26.   CLI              ; autoriser les IRQ
  27.   JMP Main         ; sauter au programme principal

Séquence RTI (6 cycles)

L'instruction RTI (Return from Interrupt) restaure le contexte sauvegarde et reprend l'exécution interrompue :

Cycle Action
1 Lecture de l'opcode ($40) a PC
2 Lecture de l'octet suivant (ignore)
3 SP := SP + 1 (ajuster SP)
4 Lire P := [$0100+SP], SP := SP + 1
5 Lire PCL := [$0100+SP], SP := SP + 1
6 Lire PCH := [$0100+SP]

Notes importantes :

Comparaison RTI vs RTS :

Instruction Registres restaures PC après retour
RTI P, PCL, PCH Valeur exacte empilée
RTS PCL, PCH Valeur empilée + 1

La différence de PC s'explique par le fait que JSR empile PC-1 (dernière adresse de l'instruction JSR), tandis que les interruptions empilent l'adresse exacte de la prochaine instruction a exécuter.

Cas limites et interactions

Plusieurs situations peuvent créer des comportements subtils :

NMI pendant le traitement d'une IRQ :

IRQ pendant le traitement d'une NMI :

NMI qui hijack le vecteur IRQ/BRK :

Double NMI :

Résumé du comportement de la pile

État de la pile dans chaque cas :

Cas Description
Avant l'interruption SP pointe sur la dernière donnée empilée (ou sur $FF si la pile est vide)

Pendant une interruption : 3 octets sont empiles

$0100 + SP_ancien → PCH
$0100 + SP_ancien - 1 → PCL
$0100 + SP_ancien - 2 → P (avec B=0 pour IRQ/NMI, B=1 pour BRK)
SP := SP_ancien - 3

Après RTI : 3 octets sont depiles :

P := [$0100 + SP + 1]
PCL := [$0100 + SP + 2]
PCH := [$0100 + SP + 3]
SP := SP + 3

Diagramme temporel des interruptions

Ligne de temps typique pour une IRQ :

Horloge : 1 2 3 4 5 6 7
PC cur cur+1 - - - lo hi
Action fetch fetch push push push read read
op op PCH PCL P $FFFE $FFFF
SP SP SP SP-1 SP-2 SP-3 SP-3 SP-3
Drapeaux         I:=1    

Après le cycle 7, le processeur commence a exécuter l'instruction a l'adresse lue depuis le vecteur.

Comparaison avec d'autres microprocesseurs

Microprocesseur Contexte sauvegarde Cycles Pile
MOS 6502 P, PCL, PCH (3 octets) 7 $0100-$01FF
Zilog Z80 PC (2 octets) ~13 Quelconque
Intel 8080 PC (2 octets) ~11 Quelconque
Motorola 6800 PC,X,A,B,CC (7 octets) 12 Quelconque
Motorola 6809 Tous registres (12 oct) 19 Quelconque
Motorola 68000 SR, PC (6 octets min) ~44 Superviseur
Intel 80386 EFLAGS, CS, EIP (+err) Variable TSS/pile

Le 6502 sauvegarde le minimum sur la pile (seulement P et PC), ce qui rend l'entrée en interruption rapide (7 cycles) mais oblige le descripteur a sauvegarder manuellement A, X et Y si nécessaire. Le 6809, en revanche, sauvegarde automatiquement tous les registres (12 octets) mais au prix de 19 cycles.



Dernière mise à jour : Vendredi, le 27 mars 2026