★ CODING ★ MICRONEWS - Z80 ASSEMBLEUR FACILE (2eme partie) ★ |
Cours et initiation du Magazine Micro News | Micro News n°07 : Z80 Assembleur Facile - Les boucles (2eme partie) |
Vos cheveux se dressent dès que l'on parle de boucles en assembleur ? Voici de quoi les recoiffer élégamment. Revenons donc à nos boucles du type for next : nous en étions resté à la boucle sur 256. Comment aller au-delà ? Les registres du Z80 qui ont des "chromosomes" communs, c'est-à-dire B et C, H et L, D et E, se marient et divorcent avec une facilité vraiment déconcertante. Puisque B ne suffit plus au delà de 256, nous allons tout simplement mettre en œuvre la paire BC, et ceci sans autre forme de procès ni précaution particulière. A partir du moment où vous nommez la paire, tout se passe comme si vous aviez affaire à un registre unique de 16 bits capable de mémoriser jusqu'à 65535 en valeur absolue. Rappelons encore une fois que B, C, D, E, H, L désignant des registres, c'est-à-dire des organes de calcul, et non pas des variables comme en Basic. LD BC, x : load BC,x : charger dans Faire ceci, cela DEC BC : Decrease BC : désincrémter Notez que DEC peut jouer aussi bien pour un registre pris isolément (DEC C, DEC A) que pour une paire (DEC BC, DEC DE). Notre boucle étant du genre step-1, il nous faut à présent vérifier si BC est à 0. C'est là que les choses se corsent I Nous ne pouvons directement comparer une paire de registres à une autre paire ou à une valeur absolue. Pire : toutes les comparaisons passent obligatoirement par A (accumulateur). Il va donc falloir ruser et trouver une formule quelconque, si possible simple, rapide et directe. Il n'est même pas interdit de trouver autre chose qu'une comparaison : seul compte le résultat, c'est à dire vérifier si BC=0. Il nous faut ici revenir aux jours lointains pour certains, où nous usions nos jeans à ingurgiter certaines théories relatives au calcul binaire. Une opération logique OR s'effectue selon la table de vérité suivante :
Voici un excellent moyen pour vérifier si le premier et le second terme sont à zéro. Si nous effectuons une opération OR entre B et C, il faut et il suffit que le résultat soit 0 pour pouvoir affirmer que B (premier terme) = 0, que C (deuxième terme) = 0 et donc que la paire BC=0. En assembleur Z80, une opération logique n'est possible qu'entre A (accumulateur) un registre, une valeur absolue ou une zone mémoire. Notez que le résultat est stocké dans A. Bref, pour effectuer notre boucle, nous allons transférer B dans A et faire une opération logique OR entre A et C. Suivant la nature du résultat, 0 ou pas 0, le drapeau Z ou NZ est automatiquement levé. En clair ça donne : LD A, B : load A à partir de B La séquence suivante est absolument équivalente : LD A,C : charger A à partir de C Voici donc la boucle complète : LD BC,x : initialisé la boucle à x P1 faire ceci, cela Une remarque s'impose. La formulation ci-dessus permet de vérifier si BC (ou DE ou HL) est égal à 0. Une comparaison avec une valeur absolue autre que 0 ou avec une autre paire nécessite la mise en œuvre d'un petit programme que nous étudierons le moment venu. Bien, me direz vous : et au delà de 65535 ? Il est facile d'écrire : "Faire ceci, faire cela". Mais précisément, "ceci, cela" correspond peut-être à des boucles, qui ont toutes besoin des registres B,C,D,E,H et L. Alors ? On sait imbriquer des boucles. En voici un exemple qui vous fera encore toucher du doigt combien il est facile d'associer ou de dissocier les paires. LD C,x : initialiser C à x DJNZ P2 : remonter à P2 si B pas 0 Faire autre chose Notez que le DEC C entraine un positionnaient automatique du drapeau Z ou NZ. Il n'en reste pas moins que les possibilités paraissent limitées car pour l'instant nous ne comptons que 6 registres, le cas de l'accumulateur A étant réservé. Nous allons multiplier ce chiffre par 2 : le Z80 possède 2 registres A (A et A'), 2 registres B (B et B'), etc. Une seule instructions permet de basc. er de BC vers B'C', de DE vers D'E', de HL vers H'L'. E e se nomme EXX et n'affecte pas les contenus de BC, DE, HL. Nous pouvons donc écrire la boucle précédente comme suit : LD B,x : initialiser B à x P2 Faire ceci, cela DJNZ P2 Faire autre chose EXX : revenir sur le premier jeu de registres DJNZ P1 Notez bien qu'il n'existe qu'une seule instruction de bascule pour passer d'un jeu de registres à l'autre. A vous de savoir où vous en êtes. Toutefois on ne fait appel à EXX que dans des circonstances bien précises. Le second EXX qui fait revenir au premier jeu se situe dans la plupart des cas très près du premier, car basculer BC, DE et HL peut être gênant. On préférera donc souvent trouver autre chose. La méthode la plus courante consiste à se servir de la "pile". Voici encore une nouveauté que nous examinerons plus à fond par la suite. Cette fameuse "pile*' sert à gérer les retours de sous programme. Accessoirement on l'utilise à d'autres fins, avec un réel succès. LD B, x DJNZ P2 Faire autre chose POP BC : Dépiler BC ce qui revient a retrouver l'ancienne valeur de B et de C DJNZ P1 On empilé et dépile obligatoirement une paire. Dans certains cas, cela pose problème, notamment si, comme dans notre exemple, C bouge entre le PUSH et le POP. Les manipulations avec la pile peuvent entraîner de véritables catastrophes si elles sont mai maitrisées : mettez vous face à une pile d'assiettes d'un mètre de haut et essayez de retirer celle qui se situe au bas de la pile I Comme on ne peut pas tout dire en une fois, notons déjà qu'il est indispensable de respecter la règle suivante : "premier entré, dernier sorti", ou "dernier entré, premier sorti", comme vous voulez. Mais trêve de long discours, le schéma ci-dessous résume parfaitement notre propos. PUSH HL : empiler HL Partir éventuellement en sous programme à la condition expresse d'en revenir, sinon patatras. POP BC : dépiler vers BC D'autres méthodes existent pour programmer une boucle. Elles nécessitent cependant une parfaite maitrise des opérations de lecture et d'écriture en mémoire. Nous en exposerons les principes prochainement.
|