Section courante

A propos

Section administrative du site

Exemples de code

Cette page présente des exemples complets de programmes en assembleur 6502. Chaque exemple est commenté et illustre une technique ou un algorithme fondamental. Les exemples utilisent les conventions de l'assembleur ASM6502.PAS (syntaxe compatible Motorola/MOS Technology).

Note : Les exemples utilisent les routines KERNAL du Commodore 64 pour les entrées/sorties, ce qui est la convention la plus répandue pour le 6502. Sur d'autres systèmes (Apple II, Atari 800, NES), les appels d'entrées/sorties varient mais le code algorithmique reste identique.

Conventions communes aux exemples :

Hello World

Programme minimal affichant un message à l'écran :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.1 : Hello World
  3.   ; Affiche "Hello, World!" puis retourne au BASIC.
  4.   ; Cible : Commodore 64 (KERNAL)
  5.   ; ------------------------------------------------------------------
  6.  
  7.             ORG   $C000
  8.  
  9.   CHROUT    EQU   $FFD2          ; Routine KERNAL : afficher caractere
  10.  
  11.   start:
  12.             LDX   #0             ; Index dans la chaine
  13.   @loop:
  14.             LDA   message,X      ; Charger le caractere suivant
  15.             BEQ   @done          ; Si zero, fin de chaine
  16.             JSR   CHROUT         ; Afficher le caractere
  17.             INX                  ; Caractere suivant
  18.             BNE   @loop          ; Boucler (max 256 caracteres)
  19.   @done:
  20.             RTS                  ; Retour au BASIC
  21.  
  22.   message:
  23.             DB    'Hello, World!', $0D, 0
  24.  
  25.             END   start

Variante Apple II (moniteur) :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.1b : Hello World - Apple II
  3.   ; Utilise la routine COUT du moniteur Apple II.
  4.   ; ------------------------------------------------------------------
  5.  
  6.             ORG   $0300
  7.  
  8.   COUT      EQU   $FDED          ; Routine moniteur : afficher caractere
  9.  
  10.   start:
  11.             LDY   #0             ; Index dans la chaine
  12.   @loop:
  13.             LDA   message,Y      ; Charger le caractere
  14.             BEQ   @done          ; Zero = fin
  15.             ORA   #$80           ; Mettre le bit 7 (Apple II normal)
  16.             JSR   COUT           ; Afficher
  17.             INY                  ; Suivant
  18.             BNE   @loop          ; Boucler
  19.   @done:
  20.             RTS
  21.  
  22.   message:
  23.             DB    'Hello, World!', $0D, 0
  24.  
  25.             END   start

Variante NES (PPU) :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.1c : Hello World - NES
  3.   ; Ecrit directement dans la memoire video PPU.
  4.   ; ------------------------------------------------------------------
  5.  
  6.             ORG   $8000
  7.  
  8.   PPUCTRL   EQU   $2000
  9.   PPUMASK   EQU   $2001
  10.   PPUSTAT   EQU   $2002
  11.   PPUADDR   EQU   $2006
  12.   PPUDATA   EQU   $2007
  13.  
  14.   start:
  15.             ; Attendre 2 VBlank pour que le PPU soit pret
  16.             LDA   PPUSTAT        ; Effacer le flag VBlank
  17.   @vb1:     LDA   PPUSTAT
  18.             BPL   @vb1           ; Attendre bit 7 = 1
  19.   @vb2:     LDA   PPUSTAT
  20.             BPL   @vb2           ; Deuxieme VBlank
  21.  
  22.             ; Positionner l'adresse PPU (nametable 0, ligne 14, col 10)
  23.             LDA   #$21           ; Adresse haute = $21
  24.             STA   PPUADDR
  25.             LDA   #$CA           ; Adresse basse = $CA
  26.             STA   PPUADDR
  27.  
  28.             ; Ecrire les tiles "Hello, World!"
  29.             LDX   #0
  30.   @loop:    LDA   message,X
  31.             BEQ   @done
  32.             STA   PPUDATA        ; Ecrire le tile dans la VRAM
  33.             INX
  34.             BNE   @loop
  35.   @done:
  36.  
  37.             ; Activer l'affichage
  38.             LDA   #%00001010     ; Afficher le fond, pas de clip gauche
  39.             STA   PPUMASK
  40.  
  41.   @infini:  JMP   @infini        ; Boucle infinie (le NES ne retourne pas)
  42.  
  43.   message:
  44.             DB    'Hello, World!', 0
  45.  
  46.             ; Vecteurs d'interruption
  47.             ORG   $FFFA
  48.             DW    start          ; NMI
  49.             DW    start          ; RESET
  50.             DW    start          ; IRQ/BRK
  51.  
  52.             END

Calcul de factorielle

Calcul itératif de N! pour des valeurs petites (résultat 8 bits ou 16 bits). La récursion est peu pratique sur le 6502 en raison de la pile limitée a 256 octets :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.2 : Factorielle iterative (8 bits)
  3.   ; Entree : X = N (0 a 5 pour rester en 8 bits)
  4.   ; Sortie : A = N!
  5.   ; Note : 5! = 120 (max pour un resultat 8 bits)
  6.   ;        Pour N > 5, utiliser la version 16 bits ci-dessous.
  7.   ; ------------------------------------------------------------------
  8.  
  9.             ORG   $C000
  10.  
  11.   CHROUT    EQU   $FFD2
  12.  
  13.   start:
  14.             LDX   #5             ; Calculer 5!
  15.             JSR   factorielle    ; A = 120
  16.             JSR   print_dec      ; Afficher en decimal
  17.             RTS
  18.  
  19.   ; ------------------------------------------------------------------
  20.   ; Sous-routine : factorielle
  21.   ; Entree : X = N (0-5)
  22.   ; Sortie : A = N!
  23.   ; Modifie : A, X, Y
  24.   ; ------------------------------------------------------------------
  25.   factorielle:
  26.             CPX   #0             ; N == 0 ?
  27.             BEQ   @un            ; 0! = 1
  28.             CPX   #1             ; N == 1 ?
  29.             BEQ   @un            ; 1! = 1
  30.  
  31.             LDA   #1             ; Accumulateur = 1
  32.             STX   @count         ; Sauvegarder N
  33.             LDY   #1             ; Compteur de boucle = 1
  34.   @loop:
  35.             ; Multiplier A par Y (addition repetee)
  36.             TAX                  ; Sauvegarder A dans X
  37.             LDA   #0             ; Resultat partiel = 0
  38.             STY   @mult          ; Nombre de fois a ajouter
  39.   @madd:    CLC
  40.             ADC   @mult+1        ; Ajouter... non, on va simplifier
  41.             ; Methode simple : table de multiplication
  42.             ; Pour factorielle, on multiplie A * (Y+1)
  43.             ; On va utiliser une approche directe par table
  44.  
  45.             ; Version simplifiee avec table precalculee :
  46.             LDX   #0             ; Trouver X dans la table
  47.             RTS                  ; (voir version 16 bits ci-dessous)
  48.  
  49.   @un:      LDA   #1
  50.             RTS
  51.  
  52.   @count:   DB    0
  53.   @mult:    DW    0
  54.  
  55.   ; ------------------------------------------------------------------
  56.   ; Version 16 bits : factorielle avec resultat sur 2 octets
  57.   ; Entree : A = N (0-8, car 8! = 40320 < 65535)
  58.   ; Sortie : result (2 octets, little-endian)
  59.   ; ------------------------------------------------------------------
  60.  
  61.   result:   DW    0              ; Resultat 16 bits
  62.   temp:     DW    0              ; Temporaire pour multiplication
  63.  
  64.   fact16:
  65.             CMP   #0
  66.             BEQ   @un16
  67.             CMP   #1
  68.             BEQ   @un16
  69.  
  70.             TAX                  ; X = N (compteur)
  71.             LDA   #1             ; result = 1
  72.             STA   result
  73.             LDA   #0
  74.             STA   result+1
  75.  
  76.             LDY   #2             ; Multiplicateur = 2
  77.   @loop16:
  78.             ; Multiplier result par Y
  79.             ; result = result * Y (multiplication 16x8 -> 16)
  80.             LDA   result
  81.             STA   temp
  82.             LDA   result+1
  83.             STA   temp+1
  84.  
  85.             LDA   #0
  86.             STA   result
  87.             STA   result+1
  88.  
  89.             ; Additionner temp Y fois
  90.             STY   @cnt
  91.   @addlp:   CLC
  92.             LDA   result
  93.             ADC   temp
  94.             STA   result
  95.             LDA   result+1
  96.             ADC   temp+1
  97.             STA   result+1
  98.             DEC   @cnt
  99.             BNE   @addlp
  100.  
  101.             INY                  ; Multiplicateur suivant
  102.             DEX                  ; Decrementer N
  103.             CPX   #1
  104.             BNE   @loop16        ; Continuer si N > 1
  105.  
  106.             RTS
  107.  
  108.   @un16:    LDA   #1
  109.             STA   result
  110.             LDA   #0
  111.             STA   result+1
  112.             RTS
  113.  
  114.   @cnt:     DB    0
  115.  
  116.   ; ------------------------------------------------------------------
  117.   ; Sous-routine : print_dec
  118.   ; Affiche la valeur de A en decimal (0-255).
  119.   ; ------------------------------------------------------------------
  120.   print_dec:
  121.             LDX   #0             ; Flag centaines
  122.             CMP   #100
  123.             BCC   @dizaines
  124.   @cent:    SBC   #100           ; Soustraire 100
  125.             INX                  ; Compter les centaines
  126.             CMP   #100
  127.             BCS   @cent
  128.             PHA                  ; Sauvegarder le reste
  129.             TXA
  130.             CLC
  131.             ADC   #'0'           ; Convertir en ASCII
  132.             JSR   CHROUT         ; Afficher centaines
  133.             PLA
  134.             LDX   #1             ; Marquer qu'on a affiche
  135.   @dizaines:
  136.             LDY   #0             ; Compteur dizaines
  137.             CMP   #10
  138.             BCC   @unites_chk
  139.   @diz:     SBC   #10
  140.             INY
  141.             CMP   #10
  142.             BCS   @diz
  143.             PHA
  144.             TYA
  145.             CLC
  146.             ADC   #'0'
  147.             JSR   CHROUT         ; Afficher dizaines
  148.             PLA
  149.             JMP   @unites
  150.   @unites_chk:
  151.             CPX   #0             ; A-t-on deja affiche un chiffre ?
  152.             BEQ   @unites        ; Non -> afficher directement
  153.             PHA
  154.             LDA   #'0'           ; Afficher '0' pour les dizaines
  155.             JSR   CHROUT
  156.             PLA
  157.   @unites:
  158.             CLC
  159.             ADC   #'0'           ; Convertir en ASCII
  160.             JSR   CHROUT         ; Afficher unites
  161.             RTS
  162.  
  163.             END   start

Tri a bulles

Tri d'un tableau d'octets par l'algorithme du tri a bulles (bubble sort). Algorithme simple mais O(n^2) :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.3 : Tri a bulles (Bubble Sort)
  3.   ; Trie un tableau d'octets en ordre croissant.
  4.   ; Entree : tableau = adresse du tableau
  5.   ;          taille  = nombre d'elements
  6.   ; ------------------------------------------------------------------
  7.  
  8.             ORG   $C000
  9.  
  10.   CHROUT    EQU   $FFD2
  11.  
  12.   taille    EQU   8              ; Nombre d'elements
  13.  
  14.   start:
  15.             JSR   bubble_sort    ; Trier le tableau
  16.             JSR   afficher       ; Afficher le resultat
  17.             RTS
  18.  
  19.   ; ------------------------------------------------------------------
  20.   ; Sous-routine : bubble_sort
  21.   ; Trie 'tableau' (taille octets) en ordre croissant.
  22.   ; Algorithme :
  23.   ;   Repeter
  24.   ;     echange = faux
  25.   ;     Pour i = 0 a taille-2
  26.   ;       Si tableau[i] > tableau[i+1] Alors
  27.   ;         Echanger tableau[i] et tableau[i+1]
  28.   ;         echange = vrai
  29.   ;   Jusqu'a echange = faux
  30.   ; ------------------------------------------------------------------
  31.   bubble_sort:
  32.   @passe:
  33.             LDA   #0
  34.             STA   @echange       ; echange = faux (0)
  35.             LDX   #0             ; i = 0
  36.   @comp:
  37.             LDA   tableau,X      ; A = tableau[i]
  38.             CMP   tableau+1,X    ; Comparer avec tableau[i+1]
  39.             BCC   @ok            ; Si tableau[i] < tableau[i+1], ok
  40.             BEQ   @ok            ; Si egaux, ok
  41.  
  42.             ; Echanger
  43.             LDY   tableau+1,X    ; Y = tableau[i+1]
  44.             STA   tableau+1,X    ; tableau[i+1] = A (ancien tableau[i])
  45.             TYA
  46.             STA   tableau,X      ; tableau[i] = Y (ancien tableau[i+1])
  47.             LDA   #1
  48.             STA   @echange       ; echange = vrai
  49.   @ok:
  50.             INX                  ; i++
  51.             CPX   #taille-1      ; i < taille-1 ?
  52.             BNE   @comp          ; Oui -> continuer
  53.  
  54.             LDA   @echange       ; Y a-t-il eu un echange ?
  55.             BNE   @passe         ; Oui -> nouvelle passe
  56.  
  57.             RTS
  58.  
  59.   @echange: DB    0
  60.  
  61.   ; ------------------------------------------------------------------
  62.   ; Sous-routine : afficher
  63.   ; Affiche les elements du tableau separes par des espaces.
  64.   ; ------------------------------------------------------------------
  65.   afficher:
  66.             LDX   #0
  67.   @loop:
  68.             LDA   tableau,X
  69.             JSR   print_dec      ; Afficher en decimal (voir 9.2)
  70.             LDA   #' '
  71.             JSR   CHROUT         ; Espace separateur
  72.             INX
  73.             CPX   #taille
  74.             BNE   @loop
  75.             LDA   #$0D
  76.             JSR   CHROUT         ; Retour chariot
  77.             RTS
  78.  
  79.   ; Donnees de test (non triees)
  80.   tableau:
  81.             DB    64, 25, 12, 99, 1, 47, 83, 36
  82.  
  83.   print_dec:
  84.             LDX   #0             ; Flag centaines
  85.             CMP   #100
  86.             BCC   @dizaines
  87.   @cent:    SBC   #100           ; Soustraire 100
  88.             INX                  ; Compter les centaines
  89.             CMP   #100
  90.             BCS   @cent
  91.             PHA                  ; Sauvegarder le reste
  92.             TXA
  93.             CLC
  94.             ADC   #'0'           ; Convertir en ASCII
  95.             JSR   CHROUT         ; Afficher centaines
  96.             PLA
  97.             LDX   #1             ; Marquer qu'on a affiche
  98.   @dizaines:
  99.             LDY   #0             ; Compteur dizaines
  100.             CMP   #10
  101.             BCC   @unites_chk
  102.   @diz:     SBC   #10
  103.             INY
  104.             CMP   #10
  105.             BCS   @diz
  106.             PHA
  107.             TYA
  108.             CLC
  109.             ADC   #'0'
  110.             JSR   CHROUT         ; Afficher dizaines
  111.             PLA
  112.             JMP   @unites
  113.   @unites_chk:
  114.             CPX   #0             ; A-t-on deja affiche un chiffre ?
  115.             BEQ   @unites        ; Non -> afficher directement
  116.             PHA
  117.             LDA   #'0'           ; Afficher '0' pour les dizaines
  118.             JSR   CHROUT
  119.             PLA
  120.   @unites:
  121.             CLC
  122.             ADC   #'0'           ; Convertir en ASCII
  123.             JSR   CHROUT         ; Afficher unites
  124.             RTS
  125.  
  126.             END   start

Analyse de complexité :

Multiplication 16 bits

Multiplication de deux nombres 16 bits non signes avec résultat sur 32 bits, par l'algorithme de décalage et addition.

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.4 : Multiplication 16 bits non signee
  3.   ; Entree : mplier (2 octets) = multiplicande
  4.   ;          mpcand (2 octets) = multiplicateur
  5.   ; Sortie : result (4 octets) = produit 32 bits
  6.   ; Methode : decalage et addition (shift-and-add)
  7.   ; ------------------------------------------------------------------
  8.  
  9.             ORG   $C000
  10.  
  11.   mplier:   DW    0              ; Multiplicande (16 bits)
  12.   mpcand:   DW    0              ; Multiplicateur (16 bits)
  13.   result:   DS    4              ; Resultat (32 bits)
  14.  
  15.   start:
  16.             ; Exemple : 1000 * 500 = 500000
  17.             LDA   #<1000         ; $E8
  18.             STA   mplier
  19.             LDA   #>1000         ; $03
  20.             STA   mplier+1
  21.  
  22.             LDA   #<500          ; $F4
  23.             STA   mpcand
  24.             LDA   #>500          ; $01
  25.             STA   mpcand+1
  26.  
  27.             JSR   mult16
  28.             RTS
  29.  
  30.   ; ------------------------------------------------------------------
  31.   ; Sous-routine : mult16
  32.   ; Multiplication 16x16 -> 32 bits non signee
  33.   ; Algorithme :
  34.   ;   result = 0
  35.   ;   Pour chaque bit du multiplicateur (16 bits) :
  36.   ;     Decaler result a droite
  37.   ;     Si bit courant du multiplicateur = 1 :
  38.   ;       Ajouter multiplicande aux 16 bits hauts de result
  39.   ;     Decaler multiplicateur a droite
  40.   ; ------------------------------------------------------------------
  41.   mult16:
  42.             ; Initialiser result a 0
  43.             LDA   #0
  44.             STA   result
  45.             STA   result+1
  46.             STA   result+2
  47.             STA   result+3
  48.  
  49.             LDX   #16            ; 16 bits a traiter
  50.   @loop:
  51.             ; Decaler result (32 bits) a droite
  52.             LSR   result+3
  53.             ROR   result+2
  54.             ROR   result+1
  55.             ROR   result
  56.  
  57.             ; Tester le bit 0 du multiplicateur
  58.             LSR   mpcand+1       ; Decaler mpcand a droite
  59.             ROR   mpcand
  60.             BCC   @noadd         ; Bit = 0 -> pas d'addition
  61.  
  62.             ; Ajouter mplier aux octets hauts de result
  63.             CLC
  64.             LDA   result+2
  65.             ADC   mplier
  66.             STA   result+2
  67.             LDA   result+3
  68.             ADC   mplier+1
  69.             STA   result+3
  70.  
  71.   @noadd:
  72.             DEX
  73.             BNE   @loop
  74.  
  75.             RTS
  76.  
  77.             END   start

Vérification : 1000 * 500 = 500000 = $0007A120

Variante optimisée (multiplicande 8 bits) :

  1.   ; Multiplication rapide 8x8 -> 16 bits
  2.   ; ------------------------------------------------------------------
  3.   ; Entree : A = multiplicande, Y = multiplicateur
  4.   ; Sortie : prod (2 octets)
  5.   ; Plus rapide pour les petites valeurs.
  6.   ; ------------------------------------------------------------------
  7.  
  8.   prod:     DW    0
  9.  
  10.   mult8x8:
  11.             STA   @mcand         ; Sauvegarder multiplicande
  12.             LDA   #0
  13.             STA   prod
  14.             STA   prod+1
  15.  
  16.             TYA                  ; A = multiplicateur
  17.             LDX   #8             ; 8 bits
  18.   @loop:
  19.             LSR                  ; Bit de poids faible dans C
  20.             BCC   @noadd
  21.             PHA                  ; Sauvegarder A
  22.             CLC
  23.             LDA   prod
  24.             ADC   @mcand
  25.             STA   prod
  26.             LDA   prod+1
  27.             ADC   #0
  28.             STA   prod+1
  29.             PLA                  ; Restaurer A
  30.   @noadd:
  31.             ASL   @mcand         ; Decaler multiplicande a gauche
  32.             DEX
  33.             BNE   @loop
  34.             RTS
  35.  
  36.   @mcand:   DB    0

Performances :

Routine de délai (temporisation)

Routines de temporisation utilisant des boucles calibrées. Le temps est calcule en cycles d'horloge du processeur :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.5 : Routines de delai
  3.   ; Base sur un processeur a 1 MHz (1 cycle = 1 microseconde).
  4.   ;
  5.   ; Delai court : delai_256us (~256 microsecondes)
  6.   ; Delai moyen : delai_ms (A millisecondes, 1-255)
  7.   ; Delai long  : delai_sec (A secondes, 1-255)
  8.   ; ------------------------------------------------------------------
  9.  
  10.             ORG   $C000
  11.  
  12.   start:
  13.             ; Exemple : clignoter la bordure pendant 5 secondes
  14.             LDX   #10            ; 10 clignotements
  15.   @blink:
  16.             LDA   #1             ; Couleur blanche
  17.             STA   $D020          ; Bordure blanche
  18.  
  19.             LDA   #250           ; 250 ms
  20.             JSR   delai_ms       ; Attendre
  21.  
  22.             LDA   #0             ; Couleur noire
  23.             STA   $D020          ; Bordure noire
  24.  
  25.             LDA   #250           ; 250 ms
  26.             JSR   delai_ms       ; Attendre
  27.  
  28.             DEX
  29.             BNE   @blink         ; Repeter
  30.             RTS
  31.  
  32.   ; ------------------------------------------------------------------
  33.   ; Sous-routine : delai_256us
  34.   ; Delai d'environ 256 microsecondes (a 1 MHz).
  35.   ; Modifie : Y
  36.   ;
  37.   ; Calcul exact :
  38.   ;   LDY #$33 = 2 cycles
  39.   ;   DEY = 2 cycles * 51
  40.   ;   BNE = 3 cycles * 50 + 2 cycles * 1
  41.   ;   RTS = 6 cycles
  42.   ;   Total = 2 + (2+3)*50 + (2+2) + 6 = 260 cycles ~ 260 us
  43.   ; ------------------------------------------------------------------
  44.   delai_256us:
  45.             LDY   #$33           ; 51 iterations
  46.   @loop:    DEY                  ; 2 cycles
  47.             BNE   @loop          ; 3 cycles (2 si pas de branchement)
  48.             RTS                  ; 6 cycles
  49.  
  50.   ; ------------------------------------------------------------------
  51.   ; Sous-routine : delai_ms
  52.   ; Delai de A millisecondes (1-255).
  53.   ; Entree : A = nombre de millisecondes
  54.   ; Modifie : A, X, Y
  55.   ;
  56.   ; 1 ms = 1000 cycles a 1 MHz
  57.   ; Boucle interne : ~5 cycles * 200 = 1000 cycles = 1 ms
  58.   ; ------------------------------------------------------------------
  59.   delai_ms:
  60.             TAX                  ; X = nombre de ms
  61.   @outer:
  62.             LDY   #200           ; 200 iterations internes
  63.   @inner:   NOP                  ; 2 cycles (ajustement)
  64.             DEY                  ; 2 cycles
  65.             BNE   @inner         ; 3 cycles -> 5 * 200 = 1000 cycles
  66.             DEX                  ; ms restantes
  67.             BNE   @outer         ; Boucler
  68.             RTS
  69.  
  70.   ; ------------------------------------------------------------------
  71.   ; Sous-routine : delai_sec
  72.   ; Delai de A secondes (1-255).
  73.   ; Entree : A = nombre de secondes
  74.   ; Modifie : A, X, Y, @sec_cnt
  75.   ; ------------------------------------------------------------------
  76.   delai_sec:
  77.             STA   @sec_cnt       ; Sauvegarder le compteur
  78.   @sec_lp:
  79.             ; 1 seconde = 4 * 250 ms
  80.             LDA   #250
  81.             JSR   delai_ms
  82.             LDA   #250
  83.             JSR   delai_ms
  84.             LDA   #250
  85.             JSR   delai_ms
  86.             LDA   #250
  87.             JSR   delai_ms
  88.  
  89.             DEC   @sec_cnt
  90.             BNE   @sec_lp
  91.             RTS
  92.  
  93.   @sec_cnt: DB    0
  94.  
  95.             END   start

Notes sur la précision :

Copie de bloc mémoire

Routines pour copier, remplir et déplacer des blocs de mémoire. Le 6502 n'a pas d'instructions de bloc (comme REP MOVSB sur x86), donc ces opérations doivent être codées manuellement :

  1.   ; ------------------------------------------------------------------
  2.   ; Exemple 9.6a : Copie de bloc (jusqu'a 256 octets)
  3.   ; Entree : src  = adresse source (page zero, 2 octets)
  4.   ;          dst  = adresse destination (page zero, 2 octets)
  5.   ;          Y    = nombre d'octets a copier (1-256, 0 = 256)
  6.   ; ------------------------------------------------------------------
  7.  
  8.             ORG   $C000
  9.  
  10.   src       EQU   $FB            ; Pointeur source (page zero)
  11.   dst       EQU   $FD            ; Pointeur destination (page zero)
  12.  
  13.   start:
  14.             ; Copier 128 octets de $2000 vers $4000
  15.             LDA   #<$2000
  16.             STA   src
  17.             LDA   #>$2000
  18.             STA   src+1
  19.  
  20.             LDA   #<$4000
  21.             STA   dst
  22.             LDA   #>$4000
  23.             STA   dst+1
  24.  
  25.             LDY   #128           ; 128 octets
  26.             JSR   copy_blk
  27.             RTS
  28.  
  29.   ; ------------------------------------------------------------------
  30.   ; Sous-routine : copy_blk
  31.   ; Copie Y octets de (src) vers (dst).
  32.   ; Copie de la fin vers le debut (Y-1 a 0).
  33.   ; ------------------------------------------------------------------
  34.   copy_blk:
  35.             DEY                  ; Commencer a l'offset Y-1
  36.   @loop:
  37.             LDA   (src),Y        ; Charger octet source
  38.             STA   (dst),Y        ; Stocker a destination
  39.             DEY                  ; Octet precedent
  40.             BPL   @loop          ; Continuer tant que Y >= 0
  41.             RTS
  42.  
  43.   ; ------------------------------------------------------------------
  44.   ; Exemple 9.6b : Copie de grand bloc (plus de 256 octets)
  45.   ; Entree : src    = adresse source (page zero)
  46.   ;          dst    = adresse destination (page zero)
  47.   ;          blklen = longueur en octets (2 octets)
  48.   ; ------------------------------------------------------------------
  49.  
  50.   blklen:   DW    0              ; Longueur du bloc
  51.  
  52.   copy_big:
  53.             LDY   #0             ; Index dans la page courante
  54.             LDX   blklen+1       ; Nombre de pages completes
  55.             BEQ   @reste         ; Si 0, aller au reste
  56.  
  57.             ; Copier les pages completes (256 octets chacune)
  58.   @page:
  59.             LDA   (src),Y        ; Charger
  60.             STA   (dst),Y        ; Stocker
  61.             INY                  ; Octet suivant
  62.             BNE   @page          ; 256 octets par page
  63.  
  64.             INC   src+1          ; Page source suivante
  65.             INC   dst+1          ; Page destination suivante
  66.             DEX                  ; Page suivante
  67.             BNE   @page          ; Continuer
  68.  
  69.             ; Copier le reste (0 a 255 octets)
  70.   @reste:
  71.             LDX   blklen         ; Nombre d'octets restants
  72.             BEQ   @done          ; Si 0, termine
  73.   @tail:
  74.             LDA   (src),Y
  75.             STA   (dst),Y
  76.             INY
  77.             DEX
  78.             BNE   @tail
  79.   @done:
  80.             RTS
  81.  
  82.   ; ------------------------------------------------------------------
  83.   ; Exemple 9.6c : Remplissage de bloc (memset)
  84.   ; Entree : dst    = adresse destination (page zero)
  85.   ;          A      = valeur de remplissage
  86.   ;          blklen = longueur en octets (2 octets)
  87.   ; ------------------------------------------------------------------
  88.  
  89.   fill_blk:
  90.             LDY   #0
  91.             LDX   blklen+1       ; Pages completes
  92.             BEQ   @reste
  93.   @page:
  94.             STA   (dst),Y        ; Remplir
  95.             INY
  96.             BNE   @page          ; 256 octets
  97.             INC   dst+1          ; Page suivante
  98.             DEX
  99.             BNE   @page
  100.   @reste:
  101.             LDX   blklen         ; Octets restants
  102.             BEQ   @done
  103.   @tail:
  104.             STA   (dst),Y
  105.             INY
  106.             DEX
  107.             BNE   @tail
  108.   @done:
  109.             RTS
  110.  
  111.   ; ------------------------------------------------------------------
  112.   ; Exemple 9.6d : Copie avec recouvrement (memmove)
  113.   ; Si src < dst : copier de la fin vers le debut
  114.   ; Si src >= dst : copier du debut vers la fin
  115.   ; Entree : src, dst, blklen
  116.   ; ------------------------------------------------------------------
  117.  
  118.   move_blk:
  119.             ; Comparer src et dst
  120.             LDA   src+1
  121.             CMP   dst+1
  122.             BCC   @backward      ; src < dst (page haute)
  123.             BNE   @forward       ; src > dst
  124.             LDA   src
  125.             CMP   dst
  126.             BCC   @backward      ; src < dst (page basse)
  127.  
  128.   @forward:
  129.             ; Copie avant (src >= dst) - identique a copy_big
  130.             JMP   copy_big
  131.  
  132.   @backward:
  133.             ; Copie arriere (src < dst)
  134.             ; Positionner a la fin du bloc
  135.             CLC
  136.             LDA   src
  137.             ADC   blklen
  138.             STA   src
  139.             LDA   src+1
  140.             ADC   blklen+1
  141.             STA   src+1
  142.  
  143.             CLC
  144.             LDA   dst
  145.             ADC   blklen
  146.             STA   dst
  147.             LDA   dst+1
  148.             ADC   blklen+1
  149.             STA   dst+1
  150.  
  151.             ; Copier du dernier octet vers le premier
  152.             LDX   blklen+1       ; Pages
  153.             LDY   blklen         ; Reste
  154.             BEQ   @bkpage        ; Si reste = 0, commencer par pages
  155.   @bktail:
  156.             DEY
  157.             LDA   (src),Y
  158.             STA   (dst),Y
  159.             CPY   #0
  160.             BNE   @bktail
  161.  
  162.   @bkpage:
  163.             CPX   #0
  164.             BEQ   @bkdone
  165.             DEC   src+1
  166.             DEC   dst+1
  167.             LDY   #$FF
  168.   @bklp:
  169.             LDA   (src),Y
  170.             STA   (dst),Y
  171.             DEY
  172.             CPY   #$FF           ; Wraparound de 0 a $FF
  173.             BNE   @bklp
  174.             DEX
  175.             BNE   @bkpage
  176.  
  177.   @bkdone:
  178.             RTS
  179.  
  180.             END   start

Performances comparées (copie de 1024 octets a 1 MHz) :

Méthode Cycles Temps
copy_blk (256 octets) ~1540 ~1.5 ms
copy_big (1024 octets) ~9240 ~9.2 ms
fill_blk (1024 octets) ~6160 ~6.2 ms
DMA (C64, si disponible) ~1024 ~1.0 ms

Comparaison avec d'autres microprocesseurs :

Microprocesseur Instruction Cycles/1024 octets
MOS 6502 Boucle LDA/STA ~9240
Zilog Z80 LDIR ~5120
Intel 8086 REP MOVSB ~9216
Motorola 68000 MOVE.L (loop) ~12288
Intel 80386 REP MOVSD ~2048

Récapitulatif des exemples

Exemple Titre Instructions clefs
9.1 Hello World LDA, JSR, INX, BNE, BEQ
9.2 Calcul de factorielle ADC, SBC, STA, CMP, BCS
9.3 Tri a bulles CMP, BCC, LDY, STA, INX
9.4 Multiplication 16 bits LSR, ROR, ADC, BCC, DEX
9.5 Routine de délai DEY, BNE, NOP, DEC
9.6 Copie de bloc mémoire LDA (zp),Y / STA (zp),Y


Dernière mise à jour : Lundi, le 30 mars 2026