Le chapitre précédent bien que d'une grande utilité pour la suite n'a pas été des plus facile ni pour moi à vous l'expliquer, ni pour vous à le comprendre.
Cependant il fait parti des étapes obligatoires à toute personne voulant faire quelque chose sur la machine.
Maintenant que nous savons calculer l'adresse de la ligne inférieure, il serait aussi très utile de pouvoir calculer l'adresse d'une ligne en fonction de son numéro.
En effet, si nous devons placer un sprite à l'écran, nous ne voudrons pas forcément le mettre à la ligne 0.
Une coordonnée Y pourrait par exemple nous permettre de décider ou notre sprite sera sur l'écran.
Hors pour faire cela, il nous faut bien faire une routine de calcul.
En vérité ce n'est pas forcément obligatoire car on pourrait simplement précalculer une table d'adresse et pointer dessus.
Nous verrons ce principe plus tard.
Afin de calculer l'adresse d'une ligne, je vais vous montrer ici comment est "codée" l'adresse d'une ligne.
Voici donc un schéma explicatif.
Comme vous pouvez le voir ce schéma traduit bien ce que nous avons vu dans le cours précédent.
L'octet de poids fort (celui de gauche sur le schéma), possède en bits 0 à 2 les coordonnées "fines" de la ligne.
Ce sont ces bits qui permettent dans un bloc de ligne (ou ligne de caractère) de descendre en incrémentant le poids fort.
On retrouve ensuite les bits 3 à 5 sur l'octet de poids faible.
Ceux-ci correspondent au changement de bloc de ligne et comme par magie, le premier bit est bien sur la valeur 32... Celle là même qui est ajoutée pour changer de bloc de ligne.
Enfin on retrouve sur le poids fort en position 3 et 4 les derniers bits (Y6 et Y7) correspondants au changement de bloc écran.
Pour calculer l'adresse d'une ligne en fonction de son numéro, il va donc falloir remettre ces bits dans le bon ordre.
Pour cela nous allons utiliser des opérations logiques comme nous les avons déjà vues, mais aussi des rotations sur les octets.
Le but est de prendre une valeur correspondant au numéro de ligne et de remettre les bits dans l'ordre voulu.
Prenons n'importe quelle valeur 8 bits de 0 à 191 (puisque sur spectrum nous avons 192 lignes maximum à l'écran).
Cette valeur est donc une valeur 8 bits donc nous numéroterons les bits de façon habituelle.
Nos numéros de bits correspondront au numéro Yn notés sur le précédent schéma. Nous voulons donc les mettre à la bonne place.
Commençons par récupérer les bits 0 à 2 qui correspondent donc à Y0 à Y2.
Pour cela rien de plus simple, un simple AND isolera ces bits.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2
Comme nous devrons mettre ces bits à la même place sur le poids fort de l'adresse, nous n'avons pas besoin de les déplacer puisqu'ils sont à la bonne place.
On va se contenter de sauvegarder le resultat pour le moment.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat
Puisqu'on a les premiers bits de l'octet de poids fort, autant continuer à travailler sur celui-ci.
Il nous faut donc récupérer les bits 6 et 7.
Là encore un AND suffira.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat LD D,A ;On reprend notre valeur de départ AND %11000000 ;On garde les bits 6 et 7
Nous devons maintenant déplacer ces bits pour les mettre en position des bits 3 et 4 de notre octet d'adresse.
Pour cela nous avons besoin de décaler nos bits. Ceci n'est pas un problème puisque le Z80 possède les instructions nécessaires.
Nous devons donc décaler 3 fois notre octet vers la droite pour le mettre à la bonne place:
Pour faire des décalages vers la droite nous avons plusieurs solutions que voici:
RR r8 : Rotation Right - Rotation vers la droite d'un registre 8 bits.
RR (HL) : Rotation vers la droite de l'octet à l'adresse HL.
RR (IX+disp) : Rotation vers la droite de l'octet à l'adresse IX+disp.
RRA : Rotation vers la droite de l'accumulateur.
RRC r8 : Rotation Right Carry - Rotation vers la droite d'un registre 8 bits et envois du bit 0 dans la Carry.
RRC (HL) : Rotation vers la droite de l'octet à l'adresse HL et envois du bit 0 dans la Carry.
RRC (IX+disp) : Rotation vers la droite de l'octet à l'adresse IX+disp et envois du bit 0 dans la Carry.
RRC (IY+disp) : Rotation vers la droite de l'octet à l'adresse IY+disp et envois du bit 0 dans la Carry.
RRCA : Rotation vers la droite dde l'accumulateur et envois du bit 0 dans la Carry.
SRA r8 : Scroll Right Arithmetic - Décalage arithmétique d'un registre 8 bits vers la droite. Le bit 7 est inchangé. Le bit 0 va dans la Carry.
SRA (HL) : Décalage arithmétique de l'octet à l'adresse HL vers la droite. Le bit 7 est inchangé. Le bit 0 va dans la Carry.
SRA (IX+disp) : Décalage arithmétique de l'octet à l'adresse IX+disp vers la droite. Le bit 7 est inchangé. Le bit 0 va dans la Carry.
SRA (IY+disp) : Décalage arithmétique de l'octet à l'adresse IY+disp vers la droite. Le bit 7 est inchangé. Le bit 0 va dans la Carry.
SRL r8 : Scroll Right Logic - Décalage logique d'un registre 8 bits vers la droite. Un 0 est injecté en bit 7. Le bit 0 va dans la Carry.
SRL (HL) : Décalage logique de l'octet contenu à l'adresse HL vers la droite. Un 0 est injecté en bit 7. Le bit 0 va dans la Carry.
SRL (IX+disp) : Décalage logique de l'octet contenu à l'adresse IX+disp vers la droite. Un 0 est injecté en bit 7. Le bit 0 va dans la Carry.
SRL (IY+disp) : Décalage logique de l'octet contenu à l'adresse IY+disp vers la droite. Un 0 est injecté en bit 7. Le bit 0 va dans la Carry.
Nous pourrons ici utiliser l'instruction RRCA (cela fonctionnait aussi avec SRL A mais prend plus de cpu)
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat LD D,A ;On reprend notre valeur de départ AND %11000000 ;On garde les bits 6 et 7 RRCA ;On décale une fois RRCA ;On décale une seconde fois RRCA ;Dernier décalage
Nos bits Y7 et Y6 sont donc au bon endroit dans l'octet.
Notre octet de poids fort est maintenant complet, nous avons dans E les bits Y0 à Y2 et dans A nos bits Y6 et Y7.
Nous pouvons donc regrouper tout cela dans le même octet. Pour cela nous utiliserons un OR.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat LD D,A ;On reprend notre valeur de départ AND %11000000 ;On garde les bits 6 et 7 RRCA ;On décale une fois RRCA ;On décale une seconde fois RRCA ;Dernier décalage OR E ;On regroupe tout dans le même octet
Si vous retournez voir notre schéma, il nous faut aussi mettre le bit 6 à 1. On utilisera la encore un OR pour l'ajouter à notre octet.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat LD D,A ;On reprend notre valeur de départ AND %11000000 ;On garde les bits 6 et 7 RRCA ;On décale une fois RRCA ;On décale une seconde fois RRCA ;Dernier décalage OR E ;On regroupe tout dans le même octet OR %01000000 ;On ajoute le bit 6
Nous en avons terminé avec notre octet de poids fort.
Sauvegardons notre octet dans un autre registre afin de pouvoir utiliser A.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat LD D,A ;On reprend notre valeur de départ AND %11000000 ;On garde les bits 6 et 7 RRCA ;On décale une fois RRCA ;On décale une seconde fois RRCA ;Dernier décalage OR E ;On regroupe tout dans le même octet OR %01000000 ;On ajoute le bit 6 LD H,A ;On sauvegarde notre poids fort
Nous avons presque terminé. Reste à s'occuper du poids faible.
Pour cela rien de bien compliqué puisqu'il s'agit la encore de récupérer Y3 à Y5 avec un AND.
On devra cette fois-ci faire le décalage vers la gauche pour mettre les bits à leur place.
Nous utiliserons RLCA qui est la même chose que RRCA mais vers la gauche (L signifiant Left).
Enfin nous mettrons le résultat dans L. De cette façon HL contiendra notre adresse directement.
;D contient le numéro de ligne LD A,D ;On copie la valeur dans A pour travailler dessus AND %00000111 ;On garde les bits 0 à 2 LD E,A ;On sauvegarde le resultat LD D,A ;On reprend notre valeur de départ AND %11000000 ;On garde les bits 6 et 7 RRCA ;On décale une fois RRCA ;On décale une seconde fois RRCA ;Dernier décalage OR E ;On regroupe tout dans le même octet OR %01000000 ;On ajoute le bit 6 LD H,A ;On sauvegarde notre poids fort LD A,D ;On reprend notre numéro de ligne RLCA ;On décale vers la gauche RLCA ;On décale à nouveau ;Nos bits sont maintenant au bon endroit LD L,A ;On copie dans L RET ;HL contient l'adresse de la ligne
Voila qui est fait.
Comme vous l'avez constaté, ce genre d'opération n'est pas bien compliquée.
Nous manipulons simplement des bits en les replaçants à l'endroit voulu pour créer nos données.
Ce principe pourra être réutilisé pour bien des choses, à vous de bien concevoir vos programmes.
On peut par exemple imaginer stocker dans un seul octet plusieurs informations qui seront facilement lisibles de cette façon.