- Ce sujet contient 10 réponses, 6 participants et a été mis à jour pour la dernière fois par PZAWA, le il y a 6 années et 8 mois.
-
Sujet
-
Dans la première partie nous avons vu, mine de rien, pas mal de choses essentielles : Ce qu’est le langage machine, les écritures et lectures en mémoire, les registres du MOS6510 (A, X et Y) et les branchements et l’appel de routine.
Nous allons poursuivre maintenant notre apprentissage de l’assembleur sur le Commodore 64 en présentant un Monitor.
(NDLR : Pour ceux qui ne l’ont pas encore suivi, vous devriez commencer par la première partie de ce tutoriel.)
PARTIE 2-1 : ASSEMBLER AVEC SUPERMON
C’est un programme simple et relativement court qui permets d’explorer, de modifier la mémoire, d’en extraire du code machine en désassemblant des zones de mémoire et bien évidement, d’assembler des programmes en langage assembleur ce qui sera plus pratique que d’écrire directement en langage machine avec le BASIC.
Vous trouverez ce programme dans les cardridges « Final ». Ne possédant pas ce cardridge j’utilise SUPERMON de Jim Butterfield qui est légèrement plus contraignant que le MON de Final. Il en existe bien entendu d’autres mais le gros avantage de SUPERMON est qu’il est très peu volumineux comparé aux autres existants.
Vous trouverez SUPERMON64 chez moi.
L’article original ici :
Sur atarimagazines.com
Sur Archives.orgApres son chargement, SUPERMON occupe l’espace mémoires de $97ED à $9FFF.
HEXADECIMAL
Attention les monitors ne comprennent que l’hexadécimale !
Les nombres en représentation hexadécimale sont en base de 16 (au lieu de notre base courante de 10). Pour compter en hexadécimale on commence normalement par 0, 1, 2 etc jusqu’à 9. Ensuite A, B, C, D, E, F et enfin 10 qui représentera donc 16 en base décimale. Les caractères A, B, C, D, E et F représentent respectivement les nombres décimaux 10, 11, 12, 13, 14 et 15.
Lorsque l’on assemblera avec un Monitor, nous devrons toujours faire précéder nos valeurs ou adresses par le préfixe ‘$’ par exemple LDA #0 est impossible il faut écrire LDA #$00 de même STA 53280 n’est pas possible nous devons écrire STA $D020.
Sous SUPERMON, une autre contrainte est qu’il faut écrire l’adresse complète : STA $800 n’est pas possible, il faut écrire STA $0800
Pourquoi utiliser la représentation hexadécimale ? Tout simplement, un nombre hexadécimal permet de représenter un octet avec 2 caractères. En fait, un seul caractère hexadécimale permet de représenter 4 bits et, avec l’habitude, un nombre hexadécimale se converti facilement mentalement en binaire et vice-versa.
La représentation en hexadécimale est idéale lorsque l’on manipule des bits ou des adresses. De plus je vous garantis qu’il est beaucoup plus facile de retenir les registre ou des adresses en hexadécimale qu’en décimale.
Donc pour convertir un octet hexadécimale en décimal on procède ainsi : decimal=hex1*16+hex0
Tableau d’exemples :
Une adresse étant représentée sur 2 octets on utilisera 4 caractères hexadécimaux pour la représenter.
Pour convertir une adresse Hexadécimale en décimal on procède ainsi :
Decimal= hex3*4096+hex2*256+hex1*16+hex0Tableau d’exemples :
Enfin lorsque l’on détaille les bits que nous manipulons dans un octet, nous parlerons de b7, b6, b5, b4, b3, b2, b1, et b0 ou ce dernier est le bit le moins significatif b7 étant le bit le plus significatif.
Exemples :
$00 : B7 B6 B5 B4 B3 B2 B1 B0 0 0 0 0 0 0 0 0 $AA : B7 B6 B5 B4 B3 B2 B1 B0 1 0 1 0 1 0 1 0 $FF : B7 B6 B5 B4 B3 B2 B1 B0 1 1 1 1 1 1 1 1
Désolé de rabâcher, mais avec un Monitor, il nous faut vraiment apprendre à penser en hexadécimale.
Utilisation de SUPERMON
Revenons maintenant à notre monitor.
Au démarrage de SUPERMON apparait ceci :Nous y voyons en fait la valeur actuelle (toujours en hexadécimale) des registres du 6510.
PC représente le registre PC ( J) sur 2 octets. AC représente le registre A.
XR, YR respectivement les registres X et Y.
Enfin SR est le registre de statuts.
Nous reviendrons sur les registres SP et SR plus loin.Pour l’instant, pour se familiariser avec le Monitor, utilisons ce que nous avons déjà appris entrez A C000 LDA #$00. Nous indiquons ainsi que nous voulons assembler (A) en adresse $C000 l’instruction LDA #$00. Apres avoir ensuite appuyé sur « Enter », la ligne A C002 apparait automatiquement, l’instruction étant de longueur de 2 octets, le monitor à calculer pour nous l’adresse de la prochaine instruction.
Lorsque l’on saisit quelque chose de non conforme, Supermon affiche un point d’interrogation comme ci-dessous.
Il nous faut réutiliser la commande .A suivi de l’adresse et ressaisir l’instruction.
Entrons maintenant l’instruction BRK. Cette instruction est un peu particulière. On retiendra qu’elle va servir à rendre la main au Monitor ou bien plus simplement, pour terminer un programme. Une fois l’instruction entrée, apparait A C003 appuyons directement sur Entrée pour sortir du mode d’assemblage.
Avant d’exécuter le programme, entrez P C000 C002 pour visualiser le code assembleur ainsi le code machine généré par SUPERMON.
A9 00 représente le code machine en hexadécimal (169,0) de l’instruction LDA #$00
00 représente le code machine de l’instruction BRK.Maintenant tapez G C000. Le Monitor va forcer le processeur à exécuter à partir de l’adresse $C000 (49152) et ainsi exécuter notre petit (tout petit) programme. Nous devrions obtenir ceci :
On remarque que les valeurs des registres ont changé. Le registre A vaut maintenant 0 et le registre de statuts SR vaut $33 (0011 0011) au lieu de $31 (0011 0001) car le bit1 c’est-à-dire le drapeau ZERO a été allumé.
Le registre PC vaut maintenant $C002 c’est tout simplement l’adresse où notre programme a rendu la main au monitor grâce à l’instruction BRK.
Avec le monitor, nous avons la possibilité d’exécuter toutes les instructions du processeur et d’en observer les effets.Continuons notre familiarisation avec le monitor et saisissons notre boucle d’attente des 8 touches clavier de la colonne 0 (RUN/RESTORE, SPACE, Q, 1, 2, Back-Arrow, C= et Restaure) vue dans le dernier programme de la partie 1.
Maintenant, le paramètre de l’instruction BEQ sera l’adresse où nous voulons brancher et non plus le déplacement relatif : le Monitor calcul ce dernier à notre place.Terminons par l’instruction BRK. Et visualisons le désassemblage avec la commande P C000 C0008. Enfin pour exécuter notre bout de code utiliser la commande G C000.
Apres avoir appuyer notre bout de code est exécuté. Le curseur disparait jusqu’à ce qu’une touche Break ou Espace (ou bien 1, 2, Q, C=, Back-arrow et Restaure) soit pressée.
Vidéo de démonstration :
VISUALISATION ET MANIPULATION DE LA MEMOIRE
La commande .M de SUPERMON permet de visualiser la mémoire.
Par exemple si nous saisissons .M $0400 $04FF nous allons voir le contenue de la mémoire écran située par défaut entre $0400 et $7EF (1024 à 2047) représenté en hexadécimal défiler où par exemple pour la première ligne :0440 représente l’adresse et les 8 valeurs suivante (20 32 etc) la valeurs en hexadécimal des 8 cases mémoire de $0440 a $0447.Maintenant rentrer la commande .M 0400 0440
Ensuite faire monter le curseur jusqu’à la ligne 0400 et changer la valeur 2E par 00 et appuyer sur ENTER. Et constater que le caractère @ apparait en haut à gauche de l’écran.
En effet en plus de visualiser la mémoire, nous pouvons également la modifier.
Par exemple si nous remplaçons toutes les valeurs de 0400 à 0447 par la valeur de $20 on verra toute la partie haute de l’écran effacée.L’utilisation de SUPERMON résumé en un programme
Pour terminer de résumé l’utilisation de SUPERMON, saisissons le programme suivant qui met juste l’écran hors-service et affiche une petite ligne blanche au centre de l’écran et attend qu’une touche de colonne 0 soit pressée pour rendre la main.
Ce programme utilise l’instruction CPY mem qui effectue une soustraction interne entre le registre Y et la valeur située à l’adresse mem affectant ainsi les drapeaux. Ici on utilise l’adresse $D012 qui est un registre du contrôleur vidéo du C-64 (Le VIC-II) et qui indique la position vertical courante du canon à électron à l’écran. Ainsi la boucle suivante :
LDY #$60 CPY $D012 BNE -5
se termine lorsque le balayage horizontal atteints la ligne #$60 (ligne 96). On change, alors, rapidement la couleur de bord en blanc.
Ce petit bout de code sera par la suite très utile : il va permettre une synchronisation avec le rafraichissement de l’écran.
La boucle qui suit attend que la ligne horizontale #$60 se termineCPY $D012 BEQ -5
On change rapidement l’écran de bord en noire et ainsi créer un « Raster » (une ligne horizontale) blanc.
Si vous ne comprenez pas complètement le programme ci-dessous, ne vous inquiétez pas, la synchronisation et les rasters seront aborder dans une future partie. Contentez-vous de le saisir, il s’agit juste d’illustrer l’utilisation de SUPERMON.On peut désassembler notre programme avec P C000 C0022
Exécutons notre programme avec la commande G C000.
Nous devrions voir apparaitre une ligne blanche en haut de l’écran.Sauvons maintenant notre programme en utilisant la commande suivante .S«test.prg»,08,C000,C027
SUPERMON crée un fichier test.prg où sont contenues notre code machine que nous venons d’assembler de l’adresse C000 a C027. Le paramètre 08 indique que nous sauvons sur disquette.Effectuons une réinitialisation de notre C-64 et chargeons maintenant notre programme avec la commande LOAD «TEST.PRG»,8. Pour l’exécuter il nous faudra utiliser SYS49152.
On vérifie ainsi que notre programme fonctionne bien.
Nous aurions pu très bien charger depuis SUPERMON avec la commande .L« TEST.PRG »,08Vidéo de démonstration :
Résumé des commandes d’un MON :
.A Assemble ; exemple .A LDX #$00
.D Désassemble ; exemple .D C000
.P Dessassemble plus precis ; exemple .P C000 C020
.M Afficher la mémoire ; exemple .M C000 C020
.R Affiche l’état des registres
.F Remplissage mémoire ; exemples:- .F C100 C1FF AA remplit la mémoire de $C100 a $C1FF avec la valeur hexadécimale AA.
- .F C100 C100 FF écrit $FF dans la case mémoire $C100.
.G Exécuter ; exemple .G C000 exécuter à partir de $C000.
.X quitter
.L charger exemple .L « TEST.PRG »,08
.S sauver exemple .S«test.prg»,08,C000,C1FF
.T transfert exemple T C000 C0FF C100 transfert le contenue de $C000 a $C0FF en $C100
Attention lors de chargement ou de sauvegarde : pas d’espace.Nous avons résumé très rapidement l’utilisation de SUPERMON, poursuivons maintenant avec lui notre apprentissage du MOS6510.
Dorénavant, les listings seront représentés de deux façons :
- Fragments de code où nous omettrons d’indiquer l’adresse. Exemple :
ASM COMMENTAIRE LDA #$00 Charge 0 dans A STA $D020 Couleur noir pour l’écran de bord.
Le lecteur est encouragé à tester de lui-même ces fragments de codes.
- Programme complet.
ADRESSE ASM COMMENTAIRE C000 LDY $DC01 Lecture clavier dans Y C002 INY Incremente Y (si Y=#$FF, l’incremention produira 0) C003 BEQ $C000 Si 0 aucune touche presse : on boucle C005 BRK
Les programmes sont volontairement « minimalistes » pour que le lecteur puisse les tester, modifier et bien sur les embellir. :)
Lecture et écriture mémoire avec adressage indexée
Jusqu’à présent, nous n’avons utilisé que deux modes d’adressage : Direct comme LDA #$01 et absolue comme LDA $DC01 ou STA $D020.
Voyons maintenant un autre mode d’adressage très utile dit adressage indexé. Les instructions LDA mem,X ou bien STA mem,X utilisent ce mode d’adressage où le registres X joue le rôle index en ajoutant sa valeur à l’adresse absolue mem.
Par exemple, si on suppose que le registre X est égal à 1, dans ce case LDA $0400,X équivaut à LDA $0401. Si X= $09, LDA $0400, X équivaut à LDA $0409 etc.
A la place de X nous pouvons également utiliser le registre Y par exemple si Y= 1 LDA $0400,Y équivaut à LDA $0401.ASM COMMENTAIRE LDX #$00 X=0 LDA $0400,X A = valeur dans $0400 LDX #$02 X=0 LDA $0400,X A = valeur dans $0402 LDX #$24 X=0 LDA $0400,X A = valeur dans $0424
L’adressage indexée est redoutable dans une boucle où l’index (X ou Y) est incrémenté
Illustrons cela avec ce petit programme qui remplit la mémoire écran avec un caractère de dessin et attend une touche Break pour quitter.ADRESSE ASM COMMENTAIRE C000 LDX #$00 X = 0 C002 LDA #$E5 A = $e5 caractère avec des lignes verticales C004 STA $0400,X Ecriture du caractère en mémoire écran C007 STA $0500,X Ecriture du caractère en mémoire écran C00A STA $0600,X Ecriture du caractère en mémoire écran C00D STA $0700,X Ecriture du caractère en mémoire écran C010 INX Index suivant C011 BNE C002 Si X diffèrent de 0 on boucle C013 LDA $DC01 Lecture clavier C016 CMP #$FF Touche presse ? C018 BEQ $C013 Non on boucle C00B BRK Sinon on quitte
Si nous exécutons le programme, l’écran ci-dessous devrait apparaitre.
Pour rappel, la mémoire écran est par default située entre $0400 et $07EF (1024 et 2023). Une écriture dans cette zone dans l’une des 1000 cases (40 colonnes sur 25 lignes) provoque l’apparition d’un caractère en fonction de ce que l’on écrit. Par exemple l’écriture en $0400 d’une valeur 1 provoque l’apparition d’un A en haut à gauche.
Dans le programme ci-dessus et grâce à l’adressage indexé dans une boucle, on remplit toute la mémoire écran.
Amusez-vous à remplacer #$e5 par un autre caractère. On peut par exemple effacer l’écran en utilisant la valeur #$20.Grace à ce mode d’adressage on peut facilement copier des zones de mémoires.
Le fragment ci-dessous copie la zone $4000-$40FF dans $4100-$41FFASM COMMENTAIRE LDX #$00 X=0 *-9 LDA $4000,X Lecture $40xx STA $4100,X Que l’on copie dans $41xx INX Index suivant BNE *-9 Si diffèrent de 0 on boucle
La copie de blocs de mémoire vers d’autres zones est une opération élémentaire, dès-lors vous risquer de revoir très souvent le fragment de code ci-dessus qui trouve des applications dans diverses situations.
Apprendre de nouvelles instructions
Le monitor étant idéal pour l’apprentissage direct et pour tester les instructions du 6510.
Souvent nous disons que LDA est une instruction mais ce n’est pas tout à fait vrai car, comme nous l’avons vu, le processeur fait la distinction entre par exemple LDA #val ($A9) et LDA mem ($A5). Mais il est plus commode pour nous grouper les instructions par leur action qu’elles effectuent (LDA charge le registre A, STA écrit dans la mémoire avec le registre A, etc). Voilà pourquoi dans les références, les instructions sont groupées par mnémotechnique.
La liste complète du jeu d’instruction du MOS65xx se trouve par exemple sur le site de Idoc64.
Nous allons regarder comment lire cette référence.
Prenons par exemple le mnémotechnique LDA.LDA Load accumulator with memory Operation: M -> A N Z C I D V / / _ _ _ _ +----------------+-----------------------+---------+---------+----------+ | Addressing Mode| Assembly Language Form| OP CODE |No. Bytes|No. Cycles| +----------------+-----------------------+---------+---------+----------+ | Immediate | LDA #Oper | A9 | 2 | 2 | | Zero Page | LDA Oper | A5 | 2 | 3 | | Zero Page,X | LDA Oper,X | B5 | 2 | 4 | | Absolute | LDA Oper | AD | 3 | 4 | | Absolute,X | LDA Oper,X | BD | 3 | 4* | | Absolute,Y | LDA Oper,Y | B9 | 3 | 4* | | (Indirect,X) | LDA (Oper,X) | A1 | 2 | 6 | | (Indirect),Y | LDA (Oper),Y | B1 | 2 | 5* | +----------------+-----------------------+---------+---------+----------+ * Add 1 if page boundary is crossed.
Dans ce tableau, l’action de l’instruction est indiquée par M->A qui signifie : charger dans le registre A en fonction de mode d’adressage.
L’action sur les bits du registre d’état SR est indiquée dans NZCIDV. Ici nous voyons que pour LDA, seuls les bits N et Z sont affectés.
Chaque entrée correspond à un mode d’adressage dont le nom est indiqué dans la colonne « Addressing Mode ».
L’instruction machine correspondante est indiquée dans la colonne OP CODE en hexadécimal.
La colonne « Assmbly Language Form » contiendra la syntaxe en assembleur.
La colonne « No. Bytes » la taille de l’instruction machine.
Enfin « No. Cycles » nous donne le nombre de cycles machine que l’instruction prend pour être exécuté (le processeur du C-64 exécute environ 1 millions de cycles par seconde).
Par exemple l’instruction LDA #Val s’exécute en 2 cycles, l’instruction LDA mem en 4 cycles. En revanche, LDA mem,X s’exécutera en 4 cycles sauf si l’adresse correspondante tombe sur une page différente de mem. Une page mémoire est en fait une section mémoire définit par le premier octet de l’adresse haute. $0400 et $0480 appartiennent à la même page : la page $04. Mais l’adresse $0840 et $0940 appartiennent à des pages différentes ; respectivement la page $08 et la page $09.
Concrètement si X vaut $10, alors l’instruction LDA $0400,X lira en adresse $0410 et s’exécutera donc en 4 cycles. Par contre, LDA $04F8,X lira en adresse $0508 c’est-à-dire en page $05 alors que mem vaut $04F8 donc en page $04 : l’instruction prendra 5 cycles pour être exécuter.
Nous examinerons un peu plus loin les autres modes d’adressage non encore abordé.Prenons maintenant des instructions que nous n’avons pas encore vue TAX et TAY.
TAX Transfer accumulator to index X Operation: A -> X N Z C I D V / / _ _ _ _ (Ref: 7.11) +----------------+-----------------------+---------+---------+----------+ | Addressing Mode| Assembly Language Form| OP CODE |No. Bytes|No. Cycles| +----------------+-----------------------+---------+---------+----------+ | Implied | TAX | AA | 1 | 2 | +----------------+-----------------------+---------+---------+----------+ TAY Transfer accumulator to index Y Operation: A -> Y N Z C I D V / / _ _ _ _ (Ref: 7.13) +----------------+-----------------------+---------+---------+----------+ | Addressing Mode| Assembly Language Form| OP CODE |No. Bytes|No. Cycles| +----------------+-----------------------+---------+---------+----------+ | Implied | TAY | A8 | 1 | 2 | +----------------+-----------------------+---------+---------+----------+
Le label Opération nous indique que l’on charge dans X ou Y la valeur du registre A plus simplement, TAX et TAY transfère la valeur du registre A respectivement dans X et Y.
Ces instructions ne pèsent qu’un seul octet, n’ont pas de mode d’adressage et s’exécutent en 2 cycles.Avec Supermon, nous pouvons directement tester ces instructions par exemple comme ceci :
ADRESSE ASM COMMENTAIRE $C000 LDA #$91 Charge $91 dans A $C002 TAX Transfère la valeur de A dans X $C003 TAY Transfère la valeur de A dans Y $C004 BRK Fin
Après avoir exécuté ce programme, nous voyons bien que les registre X et Y valent $91 !
Essayez par vous-même de tester maintenant les instructions TXA et TYA et constater qu’elles servent bien à transférer les registres X ou Y dans le registre A respectivement.
Page Zéro
La page zéro est un endroit de la mémoire localise en $0000-$00FF. Toutes les instructions utilisant l’adressage en Page zéro prennent 1 cycle de moins et 1 octets de moins. C’est donc une zone privilégiée.
Les deux instructions suivantes font exactement la même chose : écrire la valeur de A à l’adresse $0025. Sauf que la deuxième instruction utilise la page 0 et prend donc un octet de moins et s’exécute en 3 cycles au lieu de 4 pour la première.ASM COMMENTAIRE STA $0025 écriture dans $25. Code machine : 141,37,0 STA $25 écriture dans $25. Code machine : 133,37
Dans certains vieux assembleurs, on rajoutait Z à l’instruction mnémotechnique pour indiquer explicitement un adressage en Page 0 : STAZ $25 LDAZ $25
En page Zéro se trouve aussi quelque variables intéressante remplit par le système d’exploitation du C-64.
Par exemple:
$A0-$A2 Horloge interne $22-$25 Espace temporaire pour le basic $26-$29 Espace temporaire pour la multiplication et division $2A Libre $C5 Buffer clavier $D3 Position curseur en X (Colonne ou COL) de 0 à 39. $D5 Position curseur en Y (Ligne ou ROW) de 0 à 24. $FB-$FE Espaces libres Opérations logique booléennes
Les opérations de logique booléens seront abondamment utilisées donc autant se familiariser avec tout de suite.
Voici les tableaux des opérateurs AND (Et) OR (Ou) et EOR(Ou exclusif).En colonne et en rangée nous avons la valeur des deux bits de paramètre et au milieu le résultat.
A quoi cela peut-il servir ? Principalement pour tester, allumer, inverser ou éteindre des bits (mais pas que !).Par exemple, le b4 du registre $D011 indique si l’affichage est actif. En éteignant ce bit on met une partie du VIC hors service comme nous l’avons déjà fait dans quelques programmes précédents. Mais nous l’avions fait d’une façon un peu sauvage en écrivant directement 0.
LDA #$00 STA $D011
Alors que l’on devrait plutôt procéder ainsi si on veut conserver l’état des autres bits de ce registre.
LDA $D011 AND #$EF STA $D011
Détaillons : par default le registre $D011 contient la valeur de $1B c’est-à-dire en binaire 0001 1011. Le bit 4 est allumé et nous souhaitons l’éteindre sans toucher aux autres bits.
On applique donc un AND (ET) logique avec la valeur 1110 1111 c’est-à-dire $EF où tous les bits sont allumée excepté celui que nous voulons éteindre, le bit 4.0001 1011 $1B AND 1110 1111 $EF = 0000 1011 $0B
De la même façon pour allumer un bit précis on effectuera un OR (OU) avec une valeur ou seul le(s) bit(s) que nous voulons allumer sera/ont allumé/s.
On rallume donc le bit 4 du registre $D011 de cette façon.LDA $D011 ORA #$10 STA $D011 0000 1011 $0B OR 0001 0000 $10 = 0001 1011 $1B
Un EOR (OU exclusif) est très utilisé pour inverser des bits.
Un programme d’exemple ci-dessous pour faire varier la couleur du fond sur deux valeurs.ADRESSE ASM COMMENTAIRE C000 LDA $D020 Lecture couleur de bord C003 EOR #$01 on inverse le bit 1 C006 STA $D020 On applique la nouvelle couleur C009 LDA $DC01 Lecture clavier C00C CMP #$FF Touche presse ? C00E BEQ $C000 Non -> on boucle C010 BRK Sinon on quitte
La Pile et le Registre SP
La pile est un espace qui se trouve en page 1 entre l’adresse $0100 et $01FF et qui est géré par le processeur en LIFO (dernier entré, premier sortie).
Le registre SP contient l’adresse de poids faible de la prochaine entrée valide de la pile.
Les instructions PHA et PLA empile A et dépilé dans A respectivement. Leur utilisation est idéale lorsque l’on veut sauvegarder des valeurs intermédiaires.Le programme ci-dessous illustre une utilisation de la pile en changeant la couleur de bord et en la restaurant en fin de programme.
ADRESSE ASM COMMENTAIRE C000 LDA $D020 Lecture couleur de bord C003 PHA Sauve cette valeur dans la pile C004 EOR #$0F on inverse les quarte derniers bits C006 STA $D020 On applique la nouvelle couleur C009 JSR $E4E0 Attend une touche clavier colonne 0 au moins 8 secondes C00C PLA Récupère la couleur d’origine C00D STA $D020 Applique la couleur d’origine C010 BRK Quitte
Notez également l’utilisation de la routine $E4E0 qui est très pratique pour les petits tests : elle attend au moins 8 secondes avant de rendre la main à moins qu’une touche de la colonne 0 du clavier ait été pressée.
Fonctionnement de la Pile en détail.
Pour les lecteurs curieux, on peut analyser en détails le fonctionnement de la pile avec Supermon.
Regardez l’exemple ci-dessous :ADRESSE ASM C000 LDA #$AA C002 PHA C003 LDA #$BB C005 PHA C006 BRK
Avant d’exécuter ce programme utilisons les commandes M 01F0 01FF pour vérifier l’état de la mémoire avant empilage.
Le programme ci-dessus va empiler les valeurs $AA ensuite $BB et rendre la main au monitor avec l’instruction BRK.
Avant l’exécution du programme le registre SP vaut F6 et les zones mémoires $01F6 et $01F5 valent respectivement $9D et $BA.
Apres exécution du programme, le registre SP vaut F4 et les zones mémoires $01F6 et $01F5 valent respectivement $AA et $BB.Ensuite on initialise le registre A avec 0 pour observer l’effet du dépilage :
Un premier PLA, le registre A reprends la valeur de $BB et le registre SP est incrémenté et passe à la valeur $F5.
Un deuxième PLA, le registre A prend la valeur $AA et le registre SP est incrémenté et passe à la valeur $F6.
Remarquez que la valeur des zones mémoire ne sont plus changer $01F6 et $01F5 valent toujours respectivement $AA et $BB.La pile est également utilisée lors d’un appel de routine par JSR ; l’adresse qui termine l’instruction JSR est placée dans la pile, l’instruction RTS ne fait que dépiler l’adresse pour l’appliquer au Registre PC (le processeur en interne rajoute ensuite 1).
Ci-dessus un exemple. L’adresse $C100 contient une routine qui initialise le registre X à la valeur 0 avant de « breaker » pour pouvoir examiner les registre.
L’adresse $C080 contient un JSR $C1000 qui va faire appel à la routine.
Avant l’appel, le registre SP vaut $F6 après exécution de JSR la pile vaut $F6 est l’adresse $0105 et $0106 valent $82 $C0 soit l’adresse $C082 vers laquelle l’instruction RTS de la routine doit rendre la main.Retour sur les routines
Dans la première partie nous avions appris à appeler une routine grâce à l’instruction JSR add. Nous pouvons également créer nos propres routines qui devront se terminer par l’instruction RTS.
Lorsque nous appelions notre programme machine avec la commande Basic SYS, nous appelions en fait notre routine en langage machine. Et une routine peut également appelez d’autre routines.Par exemple on veut créer une routine qui va émettre un son quelconque.
D’abord résumons rapidement comment emmètre un son en utilisant le fameux SID de notre Commodore 64.
Le SID contient trois voix programmable indépendamment. Chaque voix peut gérer quatre formes d’onde : Bruit blancs, Créneaux (Pulse avec contrôle du rapport cyclique), Dent de scie et Triangle. Nous n’utiliserons ici que la voix 0.Pour émettre un son avec la voix 0 il faut :
- Régler le volume général contrôler par les bits b3-b0 du registre $D418
- Configurer l’enveloppe (ADSR) (Attaque, pré-maintien, maintien et relâchement) de la voix 0. Chaque paramètre est contrôlé par 4 bits des registres $D404/$D405 : les bits b7-b4 de $D404 pour l’attaque A, b3-b0 de $D404 pour le pré-maintien D, b7-b4 de $D405 pour le maintien S et enfin les bits b3-b0 de $D405 pour le relâchement R.
- Régler la fréquence du son sur les registre $D400 et $D401.
- Et on écrit, dans le registre de contrôle de la Voix $D404, la forme d’onde voulue. On y allume le bit b0 et les bits b7-b4 sélectionne respectivement : le bruit blanc, le créneau, dent de scie et triangulaire.
- On fait démarrer la phase R en éteignant le bit 0 du registre $D404.
- On éteint complètement la voix en écrivant 0 dans ce même registre de contrôle.
On remarquera comme il est plus facile de configurer le SID avec l’hexadécimal qu’en décimal avec le Basic.
La routine suivant émet un bruit blanc. On la placera en adresse $C050 :ADRESSE ASM COMMENTAIRE C050 LDX #$10 Fréquence haute C052 STX $D401 Registre A dans fréquence haut C055 LDX #$09 Attaque = 0 Decay = 9 C057 STX $D405 AD C05A LDX #$F8 Sustain=$F release=$8 C05C STX $D406 SR C05F LDX #$0F VOLUME MAX C061 STX $D418 C064 LDX #$81 Bruit blanc gate = 1 C065 STX $D404 C068 LDX #$80 Bruit blanc gate = 0 C06A RTS
On peut utiliser maintenant cette routine très simplement par exemple dans le programme ci-dessous, chaque fois que la touche espace est pressée :
ADRESSE ASM COMMENTAIRE C000 LDA $C5 Lecture clavier C002 CMP #$3F Touche break ? C004 BEQ $C010 Oui on saute la boucle C006 CMP #$3E Touche Espace ? C008 BNE $C000 Non on boucle C00A JSR $C050 Sinon Appel de notre routine : on émet un son C00D JMP $C000 On Boucle C010 LDA #$00 A=0 C011 STA $D018 pour éteindre le SID C014 BRK Et quitte
Utilisation principale de la pile dans des routines.
Très souvent dans une routine on ne veut pas affecter la valeur des registres qui arrivent en entrée. On peut utiliser alors la pile pour sauver la valeur des registres en les empilant puis à la fin de la fonction, on restaure les valeurs d’origine en les dépilant.
ASM COMMENTAIRE PHA Sauve A dans la pile TXA Transfert X dans A PHA Pour le sauver dans la pile TYA Transfert Y dans A PHA Pour le sauver dans la pile ********************* notre routine PLA Récupère la dernière Entrée dans la pile TAY Retrouve Y PLA Récupère l’entrée suivant dans la pile TAX Retrouve X PLA Retrouve A RTS Quitte
Profitons-en pour voir quelques exemples de compromis entre la vitesse et la taille du code que l’on rencontre très souvent lorsque l’on programme en assembleur.
Si votre routine doit-être rapide il vaut mieux ne pas utiliser la pile et faire comme ci-dessous où nous nous servons des adresse $CFF0-$CFF2 pour sauver les valeurs en entrée.
ASM Cycles Taille STA $CFF0 4 - 4 3 - 3 STX $CFF1 4 – 8 3 - 6 STY $CFF2 4 – 12 3 - 9 ;------------------------------------------ LDA $CFF0 4 – 16 3 - 12 LDX $CFF1 4 – 20 3 - 15 LDY $CFF2 4 – 24 3 – 18
On peut faire encore mieux en utilisant une adresse de la page Zéro en utilisant cette fois ci les adresses $35-$36
ASM Cycles Taille STA $35 3 - 3 2 - 2 STX $36 3 – 6 2 - 4 STY $37 3 – 9 2 - 6 ;------------------------------------------ LDA $35 3 – 12 2 - 8 LDX $36 3 – 15 2 - 10 LDY $37 3 – 18 2 - 12
Tout sera une histoire de compromis :
L’utilisation de la pile rend le code plus petit avec 8 octets, mais elle prend 26 cycles.
La deuxième façon utilise 18 octets mais gagne 2 cycles.
Enfin la troisième est la plus rapide avec 18 cycles (8 cycles gagnée) et pèse 12 octets mais les espaces en Page zéro ne sont pas toujours disponible.Instructions INC/DEC
Les instructions INC et DEC incrémentent et décrémentent une case mémoire respectivement et agissent sur les flags Z et N.
ASM COMMENTAIRE LDA #$00 A = $00 STA $D020 $D020 = $00 INC $D020 $D020 = $01 INC $D020 $D020 = $02 DEC $D020 $D020 = $01
Ces instructions acceptent également l’adressage indexé.
Exemple : on incrémente chaque case de la zone $8000-$80FF.ASM COMMENTAIRE LDX #$00 INDEX X = 0 *-5 INC $8000,X INCREMENTE $80xx INX INDEX SUIVANT BNE *-5 SI X <> 0 on boucle
Dans la plupart des tutoriaux d’assembleurs, on retrouve ce programme très simple qui utilise l’instruction INC pour incrémenter la couleur de bord.
ADRESSE ASM COMMENTAIRE C000 INC $D020 Couleur d’écran de bord suivant C003 LDA $DC01 Lecture clavier colonne 0 C006 CMP #$FF Touche presse ? C008 BEQ $C000 Non on boucle C00A BRK Sinon Fin du programme
Programme de conclusion
Avant d’aborder la suite de cette partie sur le Monitor (qui sera un peu plus lourde), je vous propose ce petit programme qui va un peu résumer ce que nous avons vu.
Apres avoir dessiné des petits carres avec le caractère #$CF, nous allons utiliser un registre du VIC, le $D016, pour effectuer un scrolling horizontal.
Les 3 derniers bits de ce registre contrôlent le décalage horizontal de la mémoire écran pour un maximum de 7 pixels. Mais pour que cela marche, le bit 4 de ce registre doit être mis à 0. On remarquera qu’une fois fait, seul 38 caractères sont affichés au lieu de 40.
Seuls les 3 derniers bits de registre seront incrémentés et les 5 bits de poids fort (b7-b3) devront avoir une valeur de 0. Cette opération s’effectuera après rafraichissement d’écran provoquant ainsi une animation tout à fait sympathique (mais qui peut donner un petit mal de tête).Le fragment ci-dessous fait scroller horizontalement la mémoire écran.
ASM COMMENTAIRE DEC $D016 Incrémentation de $D016 LDA $D016 Lecture de $D016 AND #$07 Pour éteindre les bits7-4 STA $D016 Applique
On se sert de la pile pour sauver la valeur d’origine du registre $D016 que l’on restaurera à la fin du programme. On applique le scrolling à chaque rafraichissement mais vous pouvez vous amuser à faire sans. Enfin le programme utilise la routine $E544 qui efface la mémoire écran mais également la mémoire couleur (située en $D800-DFEF) voilà pourquoi elle est appelez au début de programme.
ADRESSE ASM COMMENTAIRE C000 JSR $E544 Efface l’écran et les couleurs C003 LDA $D016 Lecture couleur de bord C006 PHA Sauve la valeur de $D016 dans la pile C007 LDA #$E2 Ligne horizontale C009 LDX #$00 Index 0 C00B STA $0400,X écriture mémoire écran C00E STA $0500,X écriture mémoire écran C011 STA $0600,X écriture mémoire écran C014 STA $0700,X écriture mémoire écran C017 INX Index suivant C018 BNE $C008 boucle écriture C01A DEC $D016 Scroll : Décrémentation de $D016 C01D LDA $D016 dans A C020 AND #$07 Seul les bits b2-b0 sont préservés C022 STA $D016 Applique dans $D016 C025 LDY #$FF Y=255 pour la synchronisation C027 CPY $D012 On attend C02A BNE $C027 que le balayage ait atteint la ligne 255 C02C LDA $DC01 Lecture clavier colonne 0 C02F CMP #$FF Touche presse ? C031 BEQ $C01a Non on boucle sur le scroll C033 PLA Sinon récupère la valeur d’origine de la pile C034 STA $D016 Que l’on restaure C037 JSR $E544 Efface l’écran C03A BRK Fin
J’encourage le lecteur à modifier le programme précédent. Voilà quelques suggestions mais je dois en oublier un bon paquet: Vous pouvez utiliser un autre caractère mais pour que ça marche il faut évidements éviter les caractères type « ligne horizontale », sinon vous devriez utiliser le registre $D011 pour le scrolling vertical, mais il faudra, dans ce cas, impérativement préserver les valeurs d’origine des b7-b5. Vous pouvez également dupliquer la partie synchronisation pour ralentir l’animation ou carrément la supprimer.
Enfin ceux qui préfèrent partir de rien et qui sont ambitieux peuvent par exemple réécrire le programme du manuel utilisateur qui faisait voler une montgolfière complètement en assembleur mais en utilisant la synchronisation avec l’écran pour supprimer les scintillements que l’on avait avec le programme Basic.
Pzawa
Vous aimez Amiga France ? Alors aidez nous en partageant et en participant au forum. =)
- Vous devez être connecté pour répondre à ce sujet.