- Ce sujet contient 9 réponses, 7 participants et a été mis à jour pour la dernière fois par kyl83, le il y a 7 années et 4 mois.
-
Sujet
-
Vous savez taper quelques programmes Basic ? Vous avez lu et compris le manuel utilisateur à 50% ? Vous avez compris les instructions POKE et PEEK du BASIC ? Vous savez faire sortir un son ou afficher un Sprite ? Si les réponses sont oui c’est que vous êtes mure pour commencer à parler directement à votre ordinateur (ici le C64) avec le langage machine.
En effet, le basic du Commodore 64 est si pauvre qu’il n’a, en fait, jamais été aussi proche du langage machine !
Le langage assembleur n’est pas compliqué : il est même très simple. Trop simple en effet les instructions élémentaires d’un microprocesseur sont très primaires et il faut un peu plus d’instructions pour effectuer un simple PRINT et afficher un simple message à l’écran. Mais comme tout, il faut pratiquer et saisir quelques points élémentaires, et contrairement à ce que l’on peut penser, il ne faut pas beaucoup de temps pour devenir productif.
Enfin maitriser l’assembleur du Commodore 64, c’est également maitriser le langage machine de la légendaire famille des processeurs MOS 6502 qui équipa nombreuses star comme les Atari 8bit, les Apple (I et II) ou encore la NES de Nintendo (La SNES utilise une version 16 bits du MOS65xx) et par … le Terminator T-800. La famille de processeur MOS65xx est encore de nos jours produit en version 8/16 bits par Western Design (cofondé par Bill Mensch l’un des créateurs du 6502) et utilisée principalement dans l’informatique embarqué.
L’Assembleur et le langage machine sont équivalents. La différence est qu’en assembleur on utilise des petits mots mnémotechniques qui vont remplacer les obscurs chiffres du langage machines. Par exemple en assembleur, l’instruction LDA #0 est traduit en langage machine par deux octets : 169,0. (Ou bien $A9, $00 en hexadécimale c’est-à-dire 1010 1001 0000 0000 en binaire).
Le problème est que le Commodore 64 ne dispose pas d’assembleur (un programme qui fait la conversion assembleur->langage machine) en ROM, et en l’absence d’un programme externe (assembleur ou moniteur) il nous faut traduire manuellement les instructions assembleurs en langage machine décimal pour pouvoir les charger avec le BASIC.Les listings contiendrons le code assembleur suivit de la traduction en langage machine. Nous n’utiliserons pas l’hexadécimale mais chaque référence à une adresse contiendra entre parenthèse l’équivalant hexadécimal qui par convention commence par le caractère ‘$’ et sa décomposition en décimal tel que adresse=octet1+octet2*256. Exemple l’adresse de la couleur de bord 53280 (32,208 ; $D020)
Rassurez-vous la programmation en assembleur est beaucoup plus ergonomique et lors de prochain tutoriaux nous utiliserons bientôt un vrai assembleur ce qui nous facilitera beaucoup la tâche.
Ici, il s’agit surtout de bien sentir et comprendre ce qu’est le langage machine.
Afin d’éviter d’employer de l’hexadécimale, la première partie de ce tutoriel est prévue pour charger les instructions machine uniquement en BASIC. Mais j’ai conscience que cela semblera pour certain très rédhibitoire et même si le Monitor ne sera présenté que dans la seconde partie, on pourra quand même faire ce tutoriel avec un Monitor comme MON que l’on trouve dans les cartridges « Black-box » ou « Final » ou bien SUPERMON64 que vous trouverez ici.
Voilà pourquoi tout les listings contiennent 3 parties :- Le listing assembleur sans hexadécimale et sans labels.
- Le listing en code machine en décimale pour charger dans le Basic
- Le listing en assembleur pour les Monitor en hexadécimale.
Commençons…
PREMIERE PARTIE : LE LANGUAGE MACHINE
Fondamentaux :
La mémoire est subdivisée en cases qu’on appelle octet, c’est-à-dire que chaque case possède 8 bits pour la représentation de 256 valeurs différentes. Le commodore 64 contient 65536 cases. C’est dans la mémoire que le processeur va chercher les instructions machines à exécuter. Pour ce faire le processeur possède un registre spécial appelé PC (Program Counter) dans lequel est contenue l’adresse (ou le numéro de la case si vous préférez) de la mémoire qui contient la prochaine instruction à exécuter. En simplifiant, le processeur prélève tout d’abord de la mémoire, dans la case indiquée par son registre PC, l’instruction à exécuter, incrémente son PC en fonction, décode l’instruction et enfin l’exécute. Une fois fait, le processeur va chercher l’instruction suivante et le cycle se répète. C’est l’un des bases du fonctionnement d’un micro-processeur et tous fonctionnent ainsi, aussi bien le 6510 du C64 que le x86/64 de votre PC/MAC, le ARM de votre téléphone portable ou bien encore le RAD du rover Curiosity sur Mars. Une instruction machine est une suite de 0 et de 1 qui est la seul chose que le processeur comprenne et dont la taille peut varier en fonction de l’instruction (et bien sûr du processeur). Pour le 6510 (et tous les processeurs dérivés du 6502) les instructions varient de 1 à 3 octets. Voyons tout de suite quelques instructions du 6510.
ECRITURE MEMOIRE
Nous voulons changer la valeur du fond (cadre) et le bord de l’écran (overscan) en noire.
En basic on fait simplement :
POKE 53280,0 : POKE 53281,0
C’est-à-dire on écrit dans les cases mémoire 53280 (32,208 ; $D020) et 53281(33,208 ; $D021) la valeur de 0 (pour la couleur noire) ces cases représentent deux registres du circuit graphique (le VIC) pour sélectionner les couleurs de bord et de fond respectivement.
En assembleur la différence n’est pas énorme:
PROGRAMME 01 ADRESSE ASM MACHINE Décimal ASM MONITOR 49152 LDA #0 169,0 C000 LDA #$00 49154 STA 53280 141, 32, 208 C002 STA $D020 49157 STA 53281 141, 33, 208 C005 STA $D021 49160 RTS 96 C008 RTS
Chaque ligne correspond à une instruction spécifique au processeur du C64 le MOS6510. Le code, ci-dessus, se traduit donc en langage machine par la suite de nombre (Toujours entre 0 et 255) suivants :
169, 0, 141, 32, 208, 141, 33, 208, 96.
L’assembleur n’est qu’un moyen mnémotechnique pour écrire du langage machine. Celui-ci se logera dans les cases mémoire du C64. Ici, notre petite routine fait 9 octets et donc occupera 9 cases mémoire adjacentes.
Examinons en détail cette suite d’instructions.LDA #0 : On charge dans A la valeur 0 avec l’instruction LDA #valeur (169,valeur), le # indique qu’il s’agit d’une valeur direct. A est un registre du microprocesseur, une case mémoire de 1 octet qui se trouve dans le processeur et non dans la RAM. Le processeur du MOS6510 possède encore 2 autres registres X et Y plus trois autres registres : le PC et les registre SR (Status) et SP (Pile) que nous verrons plus tard. Pour charger la valeur 2 dans A on aurait fait LDA #2 (169,2), pour charger 56 LDA #56 etc. Le registre A est le registre principal du 6510 et la pluparts des opérations passeront par ce registre.
STA 53280 : On utilise ensuite l’instruction STA mem (141,mem) ou mem représente une adresse mémoire sur 2 octets pour y écrire la valeur que contient le registre A. Ici 53280 (32,208 ; $D020) fait référence au un registre du VIC qui contrôle la couleur du bord de l’écran. Nous avons précédemment chargé dans A la valeur de 0 et ainsi on écrit 0 dans la case mémoire 53280 (32,208 ; $D020) ce qui provoque le changement de la couleur du bord de l’écran en noire de la même façon qu’un POKE 53280,0 en BASIC.
STA 53281 : Exactement la même chose sauf que l’adresse où l’on charge la valeur du registre A correspond à la couleur de fond du cadre 53281 (33,208) ($D021).
RTS : Enfin, l’instruction RTS (96) permet de quitter notre routine, on terminera presque toujours nos routines assembleurs avec cette instruction.
Pour charger notre routine il suffit juste de « POKEr » les « opcodes » machine dans une partie de la mémoire avec le BASIC.
10 PRINT « CHARGEMENT » 20 ME=49152 : REM ADRESSE DE NOTRE ROUTINE 30 READ OP : REM LECTURE DATA 40 IF OP<0 THEN GOTO 80 : REM FIN DES DONNES 50 POKE ME,OP : REM CHARGEMENT DU CODE MACHINE 60 ME=ME+1 : REM CASE MEMOIRE SUIVANTE 70 GOTO 30 : REM BOUCLE 80 SYS 49152 : REM EXECUTION DE NOTRE ROUTINE 99 END 100 DATA 169,0 : REM LDA #0 110 DATA 141,32,208 : REM STA 53280 120 DATA 141,33,208 : REM STA 53281 130 DATA 96 : REM RTS 999 DATA -1 : REM FIN DES DONNEES
Dans les DATA notre programme en langage machine. Les commentaires de chaque ligne DATA donnent l’équivalent en assembleur. La commande SYS 49152 force le processeur à sauter en 49152 ($C000) pour exécuter notre routine. Taper ensuite RUN et vous constater que le cadre et le bord sont bien passé à la couleur noire. Dorénavant, nous utiliserons le corps de ce programme BASIC pour charger nos routine machine. Sauvegardons donc ce programme, il nous suffira ensuite de juste de modifier les DATA.
Avec cette routine extrêmement simple nous avons découverts deux instructions fondamentales en assembleurs : LDA #valeur STA mémoire.
Grace à ces instructions nous savons écrire n’importe quelle valeur dans n’importe quel endroit de la mémoire.
Rabâchons et précisons quelques points :
En code machine, l’instruction LDA #val se code très simplement : 169, val ou val est un chiffre compris entre 0 et 255. Donc si on veut charger 5 dans A, on écrira en ASM LDA #5 (169,5). Si nous voulons charger 39 dans A on écrira LDA #39 (169,39) Etc.
Le codage machine de l’instruction STA mémoire est un tout petit plus compliquée : Le code 141 sera toujours le premier octet, mais la valeur mémoire (l’adresse mémoire) doit être codée sur 2 octets de façons à ce que : mémoire =b1+b2*256 où b1 et b2 désigne les 2 octets suivants (toujours entre 0 et 255).
Par exemple 53280=208*256+32 et 53281=208*256+33.
Voilà pourquoi STA 53280 en code machine donne 141, 32, 208 (32+208*256=53280). De même que STA 53281 est code par 141, 33, 208 (53281=208*256+33).
Pour trouver b1 et b2 d’une adresse quelconque on doit d’abord la diviser l’adresse par 256. Le résultat entier donne b2. Pour trouver b1 on soustrait à l’adresse le résultat b2*256.
Ci-dessous le code basic pour trouver B1 et B2 de MEM.B2 = INT(MEM/256)
B1 = MEM – B2*256Petite astuce, si nous écrivons dans les registre du VIC (le circuit graphique du C-64), l’adresse haute (b2) sera toujours représenté par 208 et le l’adresse basse (b1) sera donc le numéro du registre VIC.
Grace aux instructions STA mémoire et LDA #Val nous sommes déjà en mesure de remplacer avantageusement l’instruction POKE du basic.
L’instruction RTS est l’équivalant de l’instruction RETURN du BASIC toutes nos routines devront, pour l’instant, se terminer par cette instruction.
Peut-être vous demandez vous pourquoi nous utilisons l’adresse 49152 ($C000) pour charger la routine machine. Et bien la réponse est très simple : l’espace entre les adresses 49152 et 53247 ($C000-$CFFF) est, par défaut, inutilisé ni par la ROM Kernel ni le BASIC et donc libre pour l’utilisateur.
LECTURE MEMOIRE
Introduisons une nouvelle instruction à travers cette petite routine :
PROGRAMME 02 ADDRESSE ASM MACHINE ASM MONITOR 49152 LDA 49664 173, 0, 194 C000 LDA $C200 49155 STA 53280 141, 32, 208 C003 STA $D020 49158 STA 53281 141, 33, 208 C006 STA $D021 49161 RTS 96 C009 RTS
Cela ressemble beaucoup à notre première routine à une différence importante : l’instruction LDA mémoire ne charge plus une valeur directement dans le registre A mais une valeur que contient une case mémoire de la RAM, ici 49664 (0,194 ;$C200). Le reste du programme est identique.
La traduction de cette nouvelle instruction en langage machine sera : 173,b1,b2 où le codage de l’adresse représente par b1 et b2 est exactement la même que pour l’instruction STA mémoire.
Cette instruction est donc l’équivalant de PEEK(N) en BASIC.
En faisant ainsi nous utilisons l’adresse 49664 dont la valeur est une variable que nous pouvons contrôler avec le BASIC. Par exemple le programme ci-dessous charge notre routine et ensuite va l’utiliser en changeant la valeur contenue à l’adresse 49664 pour appel ensuite notre routine machine.
10 FOR I=0 TO 10 : READ OP : POKE 49152+I,OP : NEXT I :REM CHARGEMENT DE NOTRE ROUTINE ASM ! 20 DATA 173,0,194 :REM LDA 49664 30 DATA 141,32,208 :REM STA 53280 40 DATA 141,33,208 :REM STA 53281 50 DATA 96 :REM RTS 100 X=0 :REM VARIABLE X 110 POKE 49664,X :REM ECRIT DANS 49664 LA VALEUR X 120 SYS 49152 :REM APPEL NOTRE ROUTINE ASM 130 X=X+1 : IF X>255 THEN X=0 :REM INCREMENTE X DOIT TOUJOURS ETRE INFERIEUR A 255 140 GOTO 110 :REM BOULCE
Registre X et Y :
Introduisons quelques nouvelles instructions. Ce sont quasiment les mêmes que nous avons vu précédemment à la différence près que ce n’est plus le registre A qui est concerné mais un autre registre en l’occurrence le registre X.
ADDRESSE ASM MACHINE ASM MONITOR 49152 LDX #00 162, 0 C000 LDX #$00 49154 STX 53280 142, 32, 208 C002 STX $D020 49157 STX 53281 142, 33, 208 C005 STX $D021 49160 RTS 96 C008 RTS
Le processeur du C64 contient en tout 3 registres avec lesquels nous pouvons travailler directement : le A, le X et le Y.
Le programme ci-dessus peut également s’écrire avec le registre Y :
ADRESSE ASM MACHINE ASM MONITOR 49152 LDY #00 160, 0 C000 LDY #$00 49154 STY 53280 140, 32, 208 C002 STY $D020 49157 STY 53281 140, 33, 208 C005 STY $D021 49160 RTS 96 C008 RTS
De même que notre deuxième routine utilisant la lecture peut aussi s’écrire:
ADRESSE ASM MACHINE ASM MONITOR 49152 LDX 49664 174, 0, 194 C000 LDX $C100 49155 STX 53280 142, 32, 208 C003 STX $D020 49158 STX 53281 142, 33, 208 C006 STX $D021 49161 RTS 96 C009 RTS
Ou bien en utilisant le registre Y:
ADRESSE ASM MACHINE ASM MONITOR 49152 LDY 49664 172, 0, 194 C000 LDY $C100 49155 STY 53280 140, 32, 208 C003 STY $D020 49158 STY 53281 140, 33, 208 C006 STY $D021 49161 RTS 96 C009 RTS
Le registre A est le registre principal du 6510 dans lequel passe la majorité des opérations effectuable. Les registres X et Y sont des registres dits d’index et comprennent quelques limitations dans leur utilisation. Mais pour l’instant contentons-nous de considérer ces trois registres comme équivalant.
Branchement et boucle :
A présent que nous savons remplacer les POKEs et PEEK du BASIC étudions maintenant l’équivalant assembleur du GOTO en faisant un truc un peu plus marrant avec le programme ci-dessous qui introduit 2 nouvelles instructions:
PROGRAMME 03 ADRESSE ASM MACHINE ASM MONITOR 49152 LDX #0 162, 0 C000 LDX #$00 49154 STX 53280 142, 32, 208 C002 STX $D020 49157 STX 53281 142, 33, 208 C005 STX $D021 49160 INX 232 C008 INX 49161 JMP 49154 76, 2, 192 C009 JMP $C002
L’instruction INX (232) incrémente le registre X d’une unité. Un peu comme X=X+1 en BASIC sauf que X en BASIC désigne un variable alors qu’en Assembleur X est un registre du processeur.
JMP mem (76, mem2,mem1) oblige le processeur à sauter à l’adresse spécifié en paramètres mem. C’est l’équivalent de de GOTO en Basic. Ici, l’instruction JMP obligera le processeur à recommencer à partir de l’instruction STX 53280 c’est-à-dire a l’adresse 49154.
49152 LDX #0 49154 STX 53280 49157 STX 53281 49160 INX 49161 JMP 49154
Attention : la routine va ainsi boucler indéfiniment changeant les couleurs du fond et du bord à toute vitesse et il nous sera impossible d’interrompre l’exécution de notre routine.
Exécuter ce programme : pas trop mal non ?
Essayez d’écrire ce même programme en basic et constater la différence de vitesse !
10 A = A + 1 : IF A>255 THEN A=0 20 POKE 53280,A :POKE 53281,A 30 GOTO 10
Le programme BASIC fait clignoter l’écran laborieusement avec des artefacts sur les lignes verticales tandis qu’en Assembleur cela va tellement vite que les changements se produise carrément au sein des lignes vertical.
Pour vous donner un ordre de grandeur l’assembleur est de 100 à 800 fois plus rapide que la BASIC soit la différence de vitesse entre un marcheur et un Avion supersonique !
Chaque instruction machine prend un certain nombre de cycles d’exécution. Par exemple, les instructions prennent 2 cycles pour LDA/X/Y #val, 4 cycles pour STA/X/Y mem et 6 cycles pour JMP mem. Le processeur étant cadence à environ 1 MHZ il exécute environ 1 millions de cycles par seconde. La boucle principale de notre petit programme prend 16 cycles.STX 53280 ; 4 CYCLES STX 53281 ; 4 CYCLES INX ; 2 CYCLES JMP 49154 ; 6 CYCLES
C’est à dire que ce bout de code s’exécute en 16 microsecondes (0,000016 secondes) ! Ou bien il peut être exécuté 62500 fois par seconde !!!
En réalité cette boucle s’exécute plus lentement car des évènements extérieurs au processeur sont susceptibles de lui voler des cycles. Le dernier programme de ce tutorial désactivera ces « mangeurs de cycles » pour permettre au MOS6510 de s’exprimer à sa pleine vitesse.
APPEL DE SOUS-ROUTINES :
Pour ne pas à redémarrer notre C64 à chaque fois il faudrait que notre programme puisse également lire l’état du clavier pour pouvoir l’interrompre. La ROM de notre C64 contient un bon nombre de routines destinées à nous faciliter la tâche.
Par exemple, la routine 65508 (228,255) ($FFE4) nous permet de tester l’état du clavier.
Pour appeler une routine on utilise l’instruction JSR mem (32, mem2, mem1) où MEM est l’adresse de la routine à appeler c’est l’exacte équivalant de la commande SYS MEM en BASIC et l’équivalant relatif de l’instruction GOSUB.
PROGRAMME 04 ADRESSE ASM MACHINE ASM MONITOR 49152 LDX #00 162, 0 C000 LDX #$00 49154 STX 53280 142, 32, 208 C002 STX $D020 49157 STX 53281 142, 33, 208 C005 STX $D021 49160 INX 232 C008 INX 49161 JSR 65508 32, 228, 255 C009 JSR $FFE4 49164 BNE 3 208, 3 C00C BNE $C011 49166 JMP 49154 76, 2, 192 C00E JMP $C002 49169 RTS 96 C011 RTS
L’instruction JSR 65508 renvoi l’état du clavier dans le registre A.
L’instruction BNE offset (208,offset) est une instruction de branchement conditionnelle. C’est-à-dire elle branche si une condition est réalisée ou en d’autre mot elle force le processeur à changer son registre PC pour aller exécuter une autre instruction que la suivante.
Bon attention, c’est là que ça se corse mais dites-vous que lorsque vous aurez compris ce point vous aurez tout compris au branchement conditionnel.
En réalité, BNE va tester l’état d’un autre registre dont l’accessibilité diffère par rapport aux registres A, X et Y.
Ce registre appelé STATUS parfois FLAGS (drapeaux) que l’on abrègera par SR contient 8 bits ou chaque bit donne diverses indications sur la dernière opération effectuée. Ces indications peuvent prendre que deux valeurs possible : vrai (1) ou faux (0).
Voici quelques exemples d’indications les plus utilisées :
Z (ZERO) indique si la dernière opération a engendrée une valeur de 0 auquel cas le bit Z Vrai.
N (NEGATIF) indique si la dernière opération a engendrée un nombre négatif auquel cas N sera Vrai.
C (CARRY ou Retenue) indique si la dernière opération a engendrée une retenue auquel cas C sera Vrai.
Par exemple l’instruction LDX #0 initialise le registre X à 0 mais également l’état Z du registre FLAG passe à l’état vrai.
De même l’instruction INX incrémente le registre X et cette opération agira sur l’état Z en fonction de la valeur de X. Si X est égale à 0, Z sera VRAI et FAUX dans le cas contraire.
Attention toutes les instructions n’agissent pas forcement sur SR et pas forcément sur tous les états. Par exemple, les instructions LDA, LDX, INX n’agissent que sur les états N et Z.
L’instruction BNE branche si l’état Z est faux. En d’autres termes, elle branche si la dernière opération a donné un résultat diffèrent de zéro.
Pour brancher si l’état Z est vrai, on utilise l’instruction BEQ offset (240,offset) qui est donc l’inverse de l’instruction BNE.
La deuxième chose délicate est que les instructions de branchement conditionnelles utilisent comme argument non pas l’adresse où le processeur doit sauter mais l’offset : c’est-à-dire un déplacement relatif sur 1 octets signée avec donc comme valeur possible de -128 à 127 par rapport à l’adresse qui suit les 2 octets de l’instruction de branchement.
Dans notre exemple :
ASM MACHINE ASM MONITOR JSR 65508 32, 228, 255 C009 JSR $FFE4 BNE 3 208, 3 C00C BNE $C011 JMP 49154 76, 2, 192 C00E JMP $C002 RTS 96 C011 RTS
La fonction 65508 renvoi l’état du clavier en registre A et modifie également le registre SR. Si une touche du clavier est pressée, le FLAG Zero sera faux et l’instruction BNE 3 vérifiant l’état du drapeau Z et, s’il est faux, saute de 3 octets et évite ainsi l’instruction JMP 49152 pour atteindre directement l’instruction RTS qui rend la main au BASIC. Si le FLAG Zero est vrai, l’instruction BNE 3 ne fait rien et le processeur atteint l’instruction JMP 49154 qui saute à l’adresse 49154 pour recommencer à changer les couleurs de l’écran.
Nous reviendrons sur le codage des octets signés lors d’un tutorial consacré à l’arithmétique avec le MOS6502, mais pour avoir le nombre négatif il suffit juste d’utiliser la formule 256-N où N est la valeur absolue de notre nombre négatif. Exemple -1 est codé par 256-1=255 ; -16 par 256-16=240 etc.
En utilisant un déplacement négatif on aurait pu sauver une instruction dans notre code de cette façon :
PROGRAMME 05 ADRESSE ASM MACHINE ASM MONITOR 49152 LDX #00 162, 0 C000 LDX #$00 49154 STX 53280 141, 32, 208 C002 STX $D020 49157 STX 53281 141, 33, 208 C005 STX $D021 49160 INX 232 C008 INX 49161 JSR 65508 32, 228, 255 C009 JSR $FFE4 49164 BEQ -12 240, 244 C00C BEQ $C002 49166 RTS 96 C00F RTS
Noter que nous pouvons tester le clavier de façon plus précise, par exemple nous voulons quitter le programme seulement lorsque l’utilisateur appuie sur la touche ‘Q’.
On va utiliser pour cela l’instruction CMP #valeur (201,valeur). Cette instruction compare le registre A avec la valeur passée en paramètre en effectuant en interne une soustraction (A-valeur) et va affecter les drapeaux en conséquence mais sans changer la valeur du registre A.
Changeons donc légèrement notre routine :
ASM MACHINE ASM MONITOR JSR 65508 32, 228, 255 C009 JSR $FFE4 CMP #81 201, 81 C00C CMP #$51 BEQ 3 240, 3 C00E BEQ $C013 JMP 49152 76, 0, 192 C010 JMP $C002 RTS 96 C013 RTS
Maintenant seul l’appui de la touche Q (81 est la valeur retourne par la fonction 65508 lorsque la touche Q est pressée) permet de quitter le programme.
Notez que lorsque l’on presse une autre touche l’affichage du programme se modifie : cela est lié aux mangeurs de cycles évoqués plus tôt ici c’est une interruption qui s’enclenche lorsqu’une touche du clavier est pressée. Nous verrons dans un autre tutoriel ce que sont les interruptions.
On peut même améliorer notre petit programme en rétablissant l’état initial des couleurs lorsque nous quittons:
PROGRAMME 06 ADRESSE ASM MACHINE ASM MONITOR 49152 LDX #00 162, 0 C000 LDX #$00 49154 STX 53280 141, 32, 208 C002 STX $D020 49157 STX 53281 141, 33, 208 C005 STX $D021 49160 INX 232 C008 INX 49161 JSR 65508 32, 228, 255 C009 JSR $FFE4 49164 CMP #81 201,81 C00C CMP #$51 49166 BEQ 3 240, 3 C00E BEQ $C013 49168 JMP 49152 76, 2, 192 C010 JMP $C002 49171 LDX #254 162, 254 C013 LDX #$FE 49173 STX $D020 141, 32, 208 C015 STX $D020 49176 LDX #246 162, 246 C018 LDX #$F6 49178 STX $D021 141, 33, 208 C01A STX $D021 49181 RTS 96 C01D RTS
Apres l’instruction JMP 49152 nous remettons les registres 53280 et 53281 à leur valeur d’origine (respectivement 254 et 246).
Un programme final
Voici un petit programme qui va clôturer ce tutoriel en utilisant trois nouvelles instructions SEI (120), CLI (88) et NOP (234) et agir sur un registre du VIC le 53265 (17,208 ; $D011) pour n’afficher que l’overscan.
Ce programme est fort similaire au précèdent. La différence est qu’il désactive une partie de VIC n’affichant plus que le bord d’écran et désactive les interruptions avec l’instruction SEI.
Enfin, la lecture du registre 56321 (01,220 ; $DC01) du CIA-I nous permets de tester les touches RUN/STOP-SPACE (et d’autres mais pas toutes) du clavier pour sortir de la boucle.
PROGRAMME 07 ADRESSE ASM MACHINE ASM MONITOR COMMENTAIRES 49152 LDA #0 169, 0 C000 LDA #$00 A = 0 49154 STA 53265 141, 17, 208 C002 STA $D011 Desactive le fond 49157 SEI 120 C005 SEI Desactive les interruptions 49158 LDX #00 162, 0 C006 LDX #$00 X = 0 49160 STX 53280 142, 32, 208 C008 STX $D020 Couleur de fond noir 49163 INX 232 C00B INX Incemente X 49164 NOP 234 C00C NOP Rien 49165 LDA 56321 173, 1, 220 C00D LDA $DC01 Lecture CIA-1 clavier colonne 0 49168 CMP #255 201, 255 C010 CMP #$FF Si aucune touche est presse tout les bits sont allumees 49170 BNE 3 208, 3 C012 BNE $C017 Sinon on saute a 49175 en evitant la reboucle 49172 JMP 49163 76, 08, 192 C014 JMP $C008 Reboucle 49175 CLI 88 C017 CLI Reactive les interruptions 49176 LDA #27 169, 27 C018 LDA #$1B Valeur orignial de $D011 en A pour reactiver le VIC 49178 STA 53265 141, 17, 208 C01A STA $D020 Reactive l’ecran de fond 49181 LDX #$254 162, 254 C01D LDX #$FE X = 254 couleur de bord par defaut 49183 STX 53280 142, 32, 208 C01F STX $D020 Couleur de bord = X = 254 49186 RTS 96 C012 RTS Quitte
Les instructions SEI et CLI inhibe et rétablit respectivement les interruptions. On désactive les interruptions pour permettre l’exécution du programme à pleine vitesse. Nous verrons en détail dans un prochain tutorial ce que sont les interruptions.
Enfin pour quitter le programme nous n’utilisons pas la fonction du ROM pour ne pas perdre de temps et lisons directement dans le registre 56321 ($DC01) dont la valeur par défaut (255) change lorsque on appuie sur les touches ESC, SPACE, Q et d’autres (La lecture direct du clavier est un petit plus complexe mais dans notre cas cela suffit).
Enfin l’instruction NOP est une instruction qui ne fait rien ! Mais ce n’est pas parce qu’une instruction ne fait rien qu’elle ne sert à rien : ici, on l’utilise pour perdre des cycles.
Programme BASIC pour charger et exécuter cette routine :
10 PRINT « CHARGEMENT » 20 ME=49152 : REM ADRESSE DE NOTRE ROUTINE 30 READ OP : REM LECTURE DATA 40 IF OP<0 THEN GOTO 80 : REM FIN DES DONNEES 50 POKE ME,OP : REM CHARGEMENT DU CODE MACHINE 60 ME=ME+1 : REM CASE MEMOIRE SUIVANTE 70 GOTO 30 : REM BOUCLE 80 SYS 49152 : REM EXECUTION DE NOTRE ROUTINE 100 DATA 169,0 : REM LDA #$00 120 DATA 141,17,208 : REM STA $D011 130 DATA 120 : REM SEI 140 DATA 162,0 : REM LDX 0 150 DATA 142,32,208 : REM STX $D020 160 DATA 232 : REM INX 170 DATA 234 : REM NOP 180 DATA 173,1,220 : REM LDA $DC01 190 DATA 201,255 : REM CMP #$FF 200 DATA 208,3 : REM BNE 3 210 DATA 76,08,192 : REM JMP 49160 (LINE 150 DATA) 220 DATA 88 : REM CLI 240 DATA 169,27 : REM LDA #$1B 250 DATA 141,17,208 : REM STA $D011 260 DATA 162,254 : REM LDX #254 270 DATA 142,32,208 : REM STX $D020 280 DATA 96 : REM RTS 999 DATA -1 : REM FIN DES DONNEES
Pour illustrer le tutorial j’ai fait une vidéo qui, je pense, facilitera peut-être la lecture un peu lourde comme n’importe quel tutorial sur l’assembleur :)
La vidéo s’amuse avec le dernier programme à rajouter des NOP dans la boucle interne modifiant ainsi complètement les effets de l’affichage.
Je vous encourage à faire de même et modifier ce programme en rajoutant des NOP ou des INX dans la boucle interne (Entre la ligne 150 et la ligne 210) et observer les changements produit !
J’ai souvent lu que l’un des principale reproche que font les gens, voulant apprendre l’assembleur, était qu’ils se décourageaient très vite devant le flot d’information obscure et finalement rien de bien concret. Donc j’ai essayé, et sans m’attarder sur le binaire et l’Hexadécimale (pourtant indispensable), de faire découvrir l’assembleur du processeur MOS65xx et son langage machine avec des programmes simples qui produisent des effets à l’écran impossible à reproduire avec le BASIC.
Ainsi se termine ce tutoriel en espérant qu’il vous a donné envie.
Mais il est évident que nous n’allons pas nous amuser à écrire directement du langage machine avec du BASIC. Il nous faut un outil d’assemblage. On peut distinguer trois types d’assembleur par ordre d’ergonomie.
Monitor: FINAL (BLACK BOX), SUPERMON.
Assembleur: TURBO Assembleur.
Cross-Assembleur : TMPX.Le prochain tutoriel présentera un Monitor, un programme pour assembler un programme en Mémoire. Ce sera beaucoup plus pratique que de passer par le BASIC (encore que…). Nous y verrons la notation hexadécimal, l’adressage indexe, la pile et quelques autres trucs sympas.
Enfin la troisième partie présentera l’assembleur TMP sous C-64 et un cross-assembleur (TMPX) pour une ergonomie maximale.
Tout en présentant ces outils nous en profiterons pour voir quelques points omis dans ce tutorial pourtant indispensables.
Une référence en français sur l’assembleur du MOS6510 est disponible sur l’incontournable site de Idoc64. Un cours d’Assembleur du MOS65xx en anglais sur AtariArchives dans lequel vous trouverez la description complète des instructions.
Pzawa
Vous aimez Amiga France ? Alors aidez nous en partageant et en participant au forum. =)
- Vous devez être connecté pour répondre à ce sujet.