CHAPITRE 3REGISTRES DOUBLES ET MODES D'ADRESSAGE Jusque là nous avons pu seulement charger dans un registre un nombre a 8 bits. Le Z80 permet à certains registres d'être combinés en paires, permettant ainsi la mémorisation et la manipulation de nombres a 16 bits. Les registres suivants peuvent être couplés. B et C D et E H et L Nous avons déjà étudié les instructions qui nous permettent de charger une donnée de 8 bits dans des registres individuels. L'instruction qui permet le chargement de 16 bits est: LD dd-nn Charge dans le registre double dd la donnée de 16 bits nn. Ici ,dd est un des registres suivants: BC, DE, HL, ou SP. 'nn' est un nombre à 16 bits. NOTE: Le registre SP est un registre spécialisé, appelé pointeur de pile. Nous y reviendrons ultérieurement. Lorsque l'on charge un registre double de cette manière, on le charge immédiatement avec la valeur de donnée Indiquée, d'où le terme employé pour ce type d'adressage, MODE IMMEDIAT. Tous les programmes ont jusqu'ici mémorisé des donnée dans des registres. Tout cela va très bien tant que l'on n'a pas beaucoup de données à traiter. Mais dans des situations réelles, nous aurons besoin d'une mémorisation de données plus grande que les sept registres a 8 bits les trois registres à 16 bits qui sont disponibles. Nous avons donc besoin maintenant d'instructions pour charger dans la mémoire des données, et pour lire le contenu d'une case mémoire. Le Z80 permet aux contenus des registres d'être stockés en mémoire, et aux contenus des cases mémoire d'être recopiés dans des registres. Cette forme d'adressage est appelée MODE DIRECT, parce qu'elle utilise les contenus des cases mémoire et des registres directement, c'est à dire sans en faire quelque chose auparavant. LD (nn),dd Charge dans la case mémoire nn le contenu du registre double dd. Voici un exemple d'instruction : LD (200),BC Cela recopiera le contenu du registre double BC dans la case mémoire 200. Remarquez que la case mémoire doit être placée entre parenthèses. L'instruction opposée, pour recopier le contenu de la case mémoire dans un registre double est : LD dd,(nn) Charge dans le registre double dd le contenu de la case mémoire nn. Voici un exemple d'instruction : LD BC,(200) Qu'est-ce qui va se passer? Cela va charger le contenu de la case mémoire 200 dans BC. Bien, utilisons maintenant ces instructions. Jusqu'ici, les caractères ont été affichés sur l'écran avec une instruction CALL. Ce n'est pas la seule routine Incorporée disponible. La mémoire interne (ROM) contient aussi des routines de graphisme, qui entre autre chose nous permettent de dessiner des lignes sur l'écran. Pour le moment nous n'approfondirons pas comment cela est fait, mais nous nous en tiendrons à leur utilisation. Alors qu'en BASIC, pour dessiner une ligne allant Jusqu'au point 400,200 (en supposant que le curseur graphique soit situé à 0,0). Il faudrait taper la commande suivante: DRAW 100,200 Si vous l'essayez, assurez-vous de remettre le curseur graphique à 0,0 avec la commande: PLOT 0,0 En utilisant la routine graphique commençant en case mémoire 48118, nous pouvons aussi tracer une ligne Jusqu'à 400,200 en utilisant un code machine. En BASIC, les coordonnées sont tapées après l'instruction DRAW. Quand on utilise des routines code-machine, les données (ici, les coordonnées X,Y) sont transmises à travers les registres. Dans le registre DE est chargée la coordonnée X, dans HL est chargée la coordonnée Y. Résumons les éléments nécessaires à l'utilisation de cette routine : Adresse de départ 48118 Paramètres X,Y X mémorisé dans le registre double DE Y mémorisé dans le registre double HL Bien, traçons donc sur l'écran une ligne jusqu'au point 400,200. Voici le programme: PROGRAMME 3.1 ENT LD DE,400 LD (35000),DE LD HL,200 LD (35002),HL LD DE,(35000) LD HL,(35002) CALL 48118 RET Tapez-le et lancez-le ... Observons le programme. La Première chose à noter est que le contenu de DE est mémorisé en case mémoire 35000, mais le contenu de HL l'est en 35002. Pourquoi ne pas mémoriser le contenu de HL en 35001? Parce que toute case mémoire ne peut mémoriser qu'un nombre à 8 bits, alors que nous mémorisons le contenu d'un registre à 16 bits donc 16 bits. Ce qui se passe, c'est que le nombre à 16 bits est partagé en deux nombres à 8 bits, qui sont alors mémorisés simultanément. Par conséquent, la mémorisation d'un nombre à 16 bits demande deux cases mémoire. ; OCTET FORT ; OCTET FAIBLE Registre B ; C ; -------------------------------------------- ; ! 8 bits ! 8 bits ! ; -------------------------------------------- ; ! ; ! LD (3500),BC ;-------------------- ; ! ; !Mémoire ! Contenu ! ; ! ; !--------!---------- ; ! ; ! . ! . ! ; ! ; ! . ! . ! ; ! ; ! 35000 ! C ! ; -----------------! 35001 ! B ! ;! . ! . ! ;! . ! . ! ;--------------------- ; FIGURE 3.1L'octet faible 'Least Significant Byte' (LSB) est mémorisé en premier, suivi immédiatement de l'octet fort, 'Most Significant Byte' (MSB). EXERCICE 3.1 Ecrivez l'ordre dans lequel les registres seraient mémorisés si le sous-programme suivant était exécuté. LD (200),DE LD (202),HL Reportez-vous au chapitre solutions pour la réponse. Lorsqu'ils sont couplés, les registres C, E et L sont appelés octets faibles (Least Significant Bytes), et par conséquent les registres B, D et H sont appelés octets forts (Most Significant Bytes). Maintenant un autre exercice: EXERCICE 3.2 Ecrivez un programme pour charger 100 dans la case mémoire 35000 et 400 dans la case 35002 et ensuite tracez une ligne vers ces points. Notez que le curseur graphique devra être remis à 0,0. Sautez au BASIC en sélectionnant X pour le faire avec PLOT 0,0 ou pour les plus audacieux: l'Amstrad contient une routine machine pour placer un point, nous pourrions donc incorporer celle-ci au programme. Cela éviterait d'utiliser le BASIC pour restaurer le curseur graphique. Le format de cet appel est : Adresse d'appel 48106. DE = coordonnée X HL = coordonnée Y (Pratiquement identique à la routine de traçage de ligne.) Donc pour placer un point a 0,0 il nous faut charger 0 dans DE et dans HL, puis appeler 48106. Voir la réponse au chapitre solutions EXERCICE 3.3 Ecrivez un programme qui joindra par des lignes les points suivants : --------------- ! X ! Y ! --------------- ! 200 ! 300 ! ! 400 ! 200 ! ! 0 ! 0 ! --------------- N.B. Commencez avec 200/300, rappelez-vous que vous chargez dans DE la coordonnée X et dans HL la coordonnée Y. Les solutions possibles sont données au chapitre solutions. Le microprocesseur Z80 possède aussi d'autres modes d'adressage. Jusqu'ici, le mode Immédiat pour des données de 8 bits et de 16 bits, ainsi que le mode direct pour des données de 16 bits, ont été utilisés. Il en existe un autre : le mode INDIRECT. MODE D'ADRESSAGE INDIRECT Dans ce mode d'adressage, le contenu d'un registre est utilisé pour pointer sur une case mémoire. Ce mode est très pratique, puisque l'on peut charger dans un registre de 16 bits la case mémoire de départ de nos données. On peut également lire les données, puis incrémenter (soit ajouter 1) le registre double et accéder à la prochaine donnée. La famille d'instructions est la suivante : LD r,(HL) Charge dans le registre r le contenu de la case mémoire pointée par HL. (Cela signifie en fait que nous chargeons dans HL l'adresse mémoire). LD (HL),r Charge dans la case mémoire pointée par HL le contenu du registre r. LD A,(BC) Charge dans l'accumulateur le contenu de la case mémoire pointée par BC. LD A,(DE) Charge dans l'accumulateur le contenu de la case mémoire pointée par DE. LD (BC),A Charge dans la case mémoire pointée par DE le contenu de l'accumulateur. La table ci-dessus peut sembler redoutable au premier abord, mais heureusement elle ne l'est pas; nous expliquerons tout cela au fur et à mesure que les Instructions seront utilisées dans des exemples. Maintenant, pour Illustrer l'utilisation de quelques unes de ces commandes, nous allons stocker la représentation ASCII de trois A en mémoire, puis les afficher sur l'écran en utilisant le registre HL comme un 'pointeur'. Pour simplifier la mémorisation des trois A, nous utiliserons BC comme un pointeur variable. Ainsi, si l'accumulateur contient le code de A (65), nous pouvons, en utilisant LD (BC),A et INC BC, charger trois A dans les adresses mémoires consécutives, en commençant à l'adresse contenue dans BC, en incrémentant BC trois fois. Voici le programme: PROGRAMME 3.2 (ne l'assemblez pas pour le moment) ENT LD BC,35000 BC=début des données en mémoire LD A,65 ;A=65, le code ASCII de 'A' LD (BC),A Mémorise le premier A INC BC Incrémente le pointeur LD (BC),A Mémorise le second A INC BC Incrémente le pointeur LD (BC),A Mémorise le troisième A Maintenant, pour écrire le programme afin de lire la donnée, qui commence à 35000, et la sortir sur l'écran. LD HL,35000 HL=adresse départ LD A,(HL) A=contenu de la case mémoire adressée par HL. CALL 47962 Affiche le contenu de A sur l'écran INC HL Incrémente le pointeur LD A, (HL) Recharge A CALL 47962 Affiche le second caractère INC HL Incrémente le pointeur LD A, (HL) Recharge A CALL 47962 Affiche le troisième caractère RET ;Retour Assemblez et lancez ce programme maintenant. Ce programme atteint son but mais n'est pas très efficace. Voyons comment nous pouvons l'améliorer. Observons la première partie. Nous écrivons trois fois les commandes suivantes pour lire les données: LD (BC),A INC BC Pourquoi ne pas mettre une boucle? Si nous chargeons 3 dans un registre inutilisé, disons E, alors chaque fois que nous chargeons une case mémoire, nous décrémentons E et le testons pour voir si le résultat est zéro. Si oui, nous terminons la boucle, si non, nous revenons au début de la boucle par un saut. Cette méthode accomplit la même tâche de façon plus élégante et plus efficace. Voici la première partie de programme modifiée: PROGRAMME 3,3 (Ne l'assemblez pas pour l'instant) ENT LD BC, 35000 LD A,65 LD E,3 Charge le compteur de programme NXT: LD (BC),A INC BC DEC E Décrémente le compte JR NZ,NXT: Si pas zéro saut a NXT Notez l'utilisation de l'étiquette NXT pour simplifier le calcul de l'adresse de saut. On gagne peu de temps en tapant ce programme, mais imaginez que vous chargiez 200 A avec la méthode précédente ! La même technique peut être appliquée à la deuxième partie. EXERCICE 3.4 Ajoutez une deuxième partie au programme en utilisant une boucle pour afficher les trois A, puis assemblez-le et lancez-le. Une réponse possible est donnée dans le chapitre solutions. EXERCICE 3.5 Ecrivez un programme pour stocker l'alphabet en mémoire, puis extrayez-le de la mémoire pour le sortir sur l'écran. Voir le chapitre solutions pour les réponses possibles. Récapitulons brièvement les modes d'adressages utilisés jusqu'ici. Registre-registre ;Immédiat LD B,A ; LD A, 83 ou LD BC,300 Direct ;Indirect LD A, (200) LD B, (HL) Vous trouverez une liste complète des mnémoniques du Z80 dans les appendices. La plupart des groupes de chargement de 8 et 16 bits devraient être compréhensibles maintenant. ADRESSAGE INDEXE Dans le programme 3.3 nous avons utilisé un registre double pour accéder à un bloc de données stocké séquentiellement. Alors que dans certaines applications cette méthode est très efficace, le Z80 offre une alternative, En plus des registres déjà présentés, le Z80 contient deux registres d'index de 16 bits, IX et IY. Si vous cherchez le mot 'mémoire' dans un dictionnaire, vous commencerez par trouver le début des M, puis vous chercherez le mot 'mémoire'. En d'autres termes vous avez pris le début des M pour base et à partir de là vous avez commencé votre recherche. Ceci est tout à fait analogue à l'Adressage Indexé. Dans le registre IX ou IY est chargée une adresse de base. Ensuite, pour accéder à une information, un décalage est ajouté à cette base. Le format général de la partie indexée d'une instruction est représenté ci-dessous: (IX+d) ! ! ! !------ décalage ! ! Registre d'index (base), pourrait aussi être IY. Ici d est un nombre de -127 à +128. Voici un exemple d'instruction qui utilise le registre d'index IX: LD A,(IX+3) Qu'est-ce qui va se passer? Supposons que IX contienne 200. Quelle serait la valeur chargée dans A? ; !-------------------------! ; ! Adresse ! Contenu ! ; !-------------------------! LD A,(IX+3) ! 200 ! 1 ! ; ! 201 ! 2 ! ; ! 202 ! 3 ! LD A,(200+3) --> ! 203 ! 4 ! ; ! 203 ! 5 ! ; !-------------------------! FIGURE 3.2 L'accumulateur contiendra donc 4 après cette instruction. Quel décalage aurait-on eu à utiliser pour charger 3 dans A ? Réponse : (IX+2) Au lieu d'utiliser le registre IX comme base, nous aurions pu utiliser IY avec l'instruction : LD A,(IY+3) Revoyons maintenant les instructions de chargement qui utilisent soit IX soit IY. INSTRUCTIONS D'ADRESSAGE INDEXE Il existe une méthode rapide de décrire l'opération d'une instruction, que l'on appelle son opération symbolique. Voici un exemple : Instruction Opération symbolique LD r,(IX+d) r Cela charge dans le registre r le contenu de la case mémoire pointée par l'addition de IX et d. Les appendices contiennent une table complète des Instructions Z80 ainsi que des opérations symboliques. Voici les instructions de chargement indexé : !-------------------------------------! ! Instructions ! Opération symbolique ! !-------------------------------------! ! LD r, (IX+d) ! r ! LD r, UY+d) ! r ! LD (IX+d),r ! (IX+d) ! LD (IY+d),r ! (UY+d) ! LD (IX+d),n ! (IX+d) ! LD (IY+d),n ! (lY+d) !-------------------------------------! Maintenant voyons comment on peut charger les registres IX ou IY. Regardez la table du groupe de chargement de 16 bits, et essayez de repérer les instructions à utiliser. Les voici; le format devrait vous sembler familier. --------------------------------------- ! Instructions ! Opération symbolique ! --------------------------------------- ! LD IX, nn ! IX ! LD IY,nn ! IY ! LD IX, (nn) ! IX ! LD IY, (nn) ! IY ! LD (nn),IX ! (nn) ! LD (nn),IY ! (nn) --------------------------------------- Remarque : Il n'est pas possible de calculer la valeur de 'd', il faut absolument qu'elle soit donnée, c'est à dire comme une valeur immédiate. Pour illustrer l'utilisation des registres d'index, le Programme 3.2 a été réécrit. Remarque: Dorénavant les instructions ENT seront omises de tous les programmes nous considérerons que vous les insérerez automatiquement en première ligne. Voici le programme : PROGRAMME 3.4 LD IX,35000 IX=base LD A,65 LD (IX+0),A Premier 'A' stocké LD (IX+1),A Deuxième 'A' stocké LD (IX+2),A Troisième 'A' stocké
La seconde partie, qui affiche le contenu de la mémoire sur l'écran, se présente ainsi : LD A,(IX+O) CALL 47962 Afficher premier caractère LD A,(IX+1) CALL 47962 Afficher deuxième caractère LD A,(IX+2) CALL 47962 Afficher troisième caractère RET Maintenant essayez-le. Parce que le Z80 doit additionner le décalage à la base pour des instructions indexées, il demande plus de temps pour l'exécution qu'une instruction immédiate ou indirecte. D'autre part, comme 'd'doit être donné comme une valeur absolue, l'adressage indexé n'est pas très bon en boucle, puisque 'd'ne peut pas être incrémenté. Cependant, l'avantage principal de IX et IY est leur capacité d'accéder a une donnée, stockée en mémoire, relativement à des adresses mémoire connues (c'est-à-dire pour accéder aux tables de donnée), à l'endroit où diverses informations sont stockées en utilisant des décalages connus. EXERCICE 3.6 Ecrivez un programme en utilisant IX pour stocker cinq lettres, par exemple un nom. Ensuite affichez la troisième et la quatrième lettres sur l'écran. La table suivante vous aidera: --------------------------------- ! Adresse ! Lettre ! Code de la ! ! mémoire ! ;! lettre ! --------------------------------- ! 35000 ! S ! 83! ! 35001 ! U ! 85! ! 35002 ! S ! 83! ! 35003 ! A ! 65! ! 35004 ! N ! 78! --------------------------------- Une solution possible est donnée dans le chapitre solutions. Parfait, fin d'un autre chapitre! Tout ce qui reste maintenant c'est un résumé de ce que vous avez appris dans ce chapitre. Si vous vous sentez à la hauteur, écrivez vos propres programmes. Pourquoi ne pas afficher un caractère, l'effacer par l'affichage d'un espace, et l'afficher a une autre position. Cela pourrait être la base d'un jeu ! RESUME Vous devriez maintenant comprendre les termes suivants : 1. Registres doubles 2. Modes d'adressage
a. Registre-Registre b. Immédiat c. Direct d. Indirect e. Indexé 3. Octet fort et octet faible (M.S.B. et L.S.B.) 4. Opération Symbolique - Bien que les commandes suivantes n'aient pas été mentionnées de manière spécifique, vous les comprendrez sûrement (ss est un registre double).
INC ss DEC ss - Vous devriez désormais pouvoir comprendre ces trois instructions qui ont été mentionnées brièvement dans le chapitre 2.
DEC (HL) DEC (IX+d) DEC (IY+d) où ss est un des registres suivants (ignorez SP pour l'instant) BC,DE,HL,SP d est un nombre de -126 à +129.
CPCrulez[Content Management System] v8.732-desktop/c Page créée en 846 millisecondes et consultée 1505 foisL'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko. |
|
|