C’est votre première fois ? Moi aussi !

Nous allons commencer en douceur, par un programme qui colorie le fond de l’écran, la partie supérieure en bleu pour le ciel, la partie inférieure en vert pour la prairie. Comme ça ensuite, il restera à ajouter un gros bouton moche « Démarrer » vert, et on croira avoir un xp sur sa console (mais non, je déconne 😉 ).

Soyons conscients dès le départ de la différence entre une image NTSC et une image PAL (fréquence, nombre de lignes, palette de couleurs). Par facilité, nous coderons dans un premier temps en NTSC, l’émulateur s’en accommode très bien, et la majorité des ressources liées au vcs proviennent d’outre-atlantique.

J’emprunte à l’auteur du tutorial 101 son schéma décrivant la composition d’une image :

La structure même d’une image étant toujours identique, ce programme minimaliste pourra servir de canevas pour nos futures productions.

Exprimons à DASM que nous voulons du binaire 6502, commençant à l’adresse $F000. L’include contient les registres de base du vcs (il est plus facile de se souvenir de WSYNC que de $02 !)

   processor 6502     
   include "vcs.h"    
   ORG $F000

Une mémoire à l’allumage contient des données aléatoires, qu’il convient de nettoyer :

Start        
    SEI       ; désactive les interruptions
    CLD       ; le bit bcd
    LDX #$FF
    TXS    ; mets la pile en $FF (= pile vide)

    ; Ràz de la mémoire de $FF à $00
    ; (il est plus efficace de décrémenter)
    LDA #0
Clear_Mem
    STA 0,X
    DEX
    BNE Clear_Mem    

Comme le schéma le montre, une image commence par 3 lignes pour se synchroniser verticalement :

New_Frame 
    ; nouvelle image
    LDA #2 
    STA VSYNC ; 2e bit à 1 = synchro verticale demandée
    
    STA WSYNC ; y mettre quelque chose
    STA WSYNC ; fait attendre le signal
    STA WSYNC ; de nouvelle ligne

La zone suivante est le vertical blank, soit 37 lignes non visibles. Cette zone est idéale pour effectuer diverses opérations, calculer des déplacements, des scores, etc.. nous n’allons donc pas simplement faire 37 WSYNC, mais plutôt appliquer une autre méthode utilisant un timer.
Nous avons plusieurs timers à notre disposition : TIM1T, TIM8T, TIM64T et TIM1024T. Une fois initialisé, le timer va décrémenter tous les x cycles, sa valeur courante se trouvant à l’adresse INTIM. TIM64T est un timer décrémentant tous les 64 cycles cpu. Combien de cycles vont durer ces 37 lignes ? Chaque ligne dure 76 cycles : 37*76=2812. Mais il faut retrancher le temps cpu consommé par l’initialisation du timer, ainsi que par la sortie de boucle, soit 6 et 10. Reste à diviser le résultat par 64 pour connaitre la valeur de départ du timer : (2812-16)/64=43.6875. Soit 43 en valeur entière.

    LDA  #43    ;    2 cycles
    STA  TIM64T ; 4 cycles

    LDA #0     
    STA VSYNC  ; C'est bon, on peut arrêter
               ; la demande de synchro V
   
 ; ici on pourra y mettre la logique du programme
 ; pour autant que cela ne dépasse pas les 2812 cycles au total

Wait_VBLANK_End
   LDA INTIM            ; 4 cycles
   BPL Wait_VBLANK_End  ; 3 cycles (max)

   STA WSYNC            ; 3 cycles
   LDA #0 
   STA VBLANK           ; Blank terminé, le TIA peut commencer 
                        ; à afficher quelque chose

Voici enfin la partie visible de l’iceberg (oui bon, en l’occurrence c’est plutôt un tout petit glaçon 🙂 ), 192 lignes prêtes à accueillir tous nos délires visuels :

   ; --------- Kernel = logique d'affichage -------------------
   LDX #$82    ; bleu ciel (ntsc)
   STX COLUBK  ; couleur de fond (BacKground)
   LDY #192    ; nombre de scanlines
   
Loop1
   STA WSYNC   ; cpu attend la ligne suivante
   DEY         ; ça fait une ligne en moins
   CPY #100    ; 92 lignes plus bas (n'oublions pas 
               ; que nous décrémentons)
   BNE Suite   ; nous changeons de couleur
   LDX #$c0    ; vert prairie (ntsc)
   STX COLUBK  ; couleur de fond (BacKground)    
Suite        
   CPY #0
   BNE Loop1
   ; ---------- Kernel terminé --------------------------------

Retour en coulisse, pour 30 lignes d’overscan, non visibles, donc « BLANK » :

   LDA #2
   STA WSYNC     ; on attend la fin de la ligne en cours

   ; overscan
   STA VBLANK    ; fin de l'affichage, retour au blank
       
   LDY #30       ; 30 lignes d'overscan
Loop2
   STA WSYNC
   DEY
   BNE Loop2

Overscan terminé, nous sommes prêts pour une nouvelle image :

   ; Image suivante
   JMP New_Frame        

On indique enfin à notre console préférée à quelle adresse commence le programme :

    ORG $FFFA 
        .word Start  ; utilisé pour le reset
        .word Start  ; et pour d'autres choses 
        .word Start  ; exclusives au 7800

Et voila, notre chef-d’œuvre est terminé !
Une fois proprement compilé et exécuté, cette magnifique image va s’afficher sous vos yeux ébahis :

Cet exercice nous a fait mettre en pratique

  • VSYNC : demande de synchro verticale
  • WSYNC : attente de synchro horizontale
  • VBLANK : dés/activation de l’affichage
  • TIM64T : timer 64 cycles
  • INTIM : lecture du timer
  • COLUBK : couleur de fond d’écran

Vous pouvez télécharger ce fichier source prêt à compiler ici : http://dl.dropbox.com/u/56947388/Cambouis/testfond.asm
(click-droit/enregistrer la cible sous)

Sources d’inspiration (qu’elles soient chaudement remerciées) :

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :