CODINGAMSTRAD CPC 464 - CRÉER DE NOUVELLES INSTRUCTIONS

Nouvelles Instructions 006

EXEMPLES DE PROGRAMMES

3. DESSIN D'UN QUADRILATERE

Le programme que nous allons étudier maintenant est un peu plus ambitieux : il permettra en effet la réalisation de quadrilatères de tailles, couleurs et localisation différentes.
Il débute à l'adresse 43790, finit en 43902 (chiffre de vérification: 14746), n'est pas directement relogeable et son appel aura le format suivant :

CALL 43790,XC,YC,L,H,C,PV

XC et YC sont les coordonnées du coin supérieur gauche du quadrilatère, L détermine sa largeur, H sa hauteur, C sa couleur et PV indique s'il doit être plein ou vide (1 : plein, 0 : vide).
Pour qu'il n'y ait plus de doute quant à la situation de ces paramètres au moment de l'appel du programme, rappelons une dernière fois le pointage du registre IX :


Attention, la lecture de l'Annexe II sur les coordonnées est un préalable indispensable à l'étude de ce programme, dont voici le listing :

Comme vous le voyez sur le listing, le programme peut être divisé en quatre blocs :

  • Le premier n'est composé que de deux lignes et fixe la couleur.
  • Le deuxième va des lignes 3 à 18. Il dessine la première ligne du quadrilatère puis effectue le branchement à telle ou telle partie du programme selon que le quadrilatère doit être plein ou vide.
  • Le troisième va des lignes 19 à 35 et dessine un quadrilatère plein.
  • Le quatrième, enfin, dessine un quadrilatère vide.

Ligne 1 : Chargement de A avec l'octet faible du paramètre C (le numéro de couleur étant forcément compris entre 0 et 15, l'octet fort de sa représentation hexadécimale sera toujours égal à 0, et nous ne nous en préoccuperons pas. C'est d'ailleurs pour cela que nous pouvons utiliser un registre simple).

Ligne 2 : Appel de la routine du système d'exploitation d'adresse &BBDE. Cette routine fixe la couleur d'écriture graphique (avant l'appel de cette routine, A doit être chargé avec le numéro de couleur souhaitée, ce qui a bien été fait à la ligne précédente).
Notons que l'instruction &CD est tout à fait comparable à l'instruction BASIC GOSUB : il s'agit bien de l'appel d'un sous-programme. Une fois ce sous-programme terminé, le retour sera effectué, en l'occurrence à la ligne 3.

Lignes 3 et 4 : Chargement de HL avec l'ordonnée (YC) du coin supérieur gauche du quadrilatère désiré.

Lignes 5 et 6 : Chargement de DE avec l'abscisse (XC) du même point.

Ligne 7 : Empilement de DE. Nous aurons en effet à nous resservir de cette valeur XC, et il est plus facile de charger un registre à partir de la pile (1 octet suffit), qu'à partir de IX (6 octets sont nécessaires).

Ligne 8 : Empilement de HL pour la même raison. (La pile va être souvent sollicitée, et il est vivement conseillé de noter au fur et à mesure les dépilements et empilements).

Ligne 9 : Appel de la routine d'adresse &BBC0, qui fixe le curseur graphique à une position absolue dont les coordonnées doivent être, avant l'appel, dans DE pour l'abscisse et dans HL pour l'ordonnée. Le curseur est donc maintenant fixé sur le coin supérieur gauche de notre futur quadrilatère.
Avant de passer aux lignes suivantes, un dessin nous permettra d'avoir une vue plus claire du processus :

Nous avons, en ligne 9, fixé le curseur sur (XC,YC), et nous voulons maintenant tracer la ligne allant de (XC,YC) à (X1.Y1). Relativement au point (XQYC), X1 =0 et Y1 = -H.
Nous allons donc commencer par charger ces valeurs dans DE et HL.

Lignes 10 et 11 : Chargement de HL avec le paramètre H.

Ligne 12 : Sauvegarde de cette valeur par empilement.

Ligne 13 : Appel de la routine d'adresse &BDC7, qui a pour fonction d'inverser le signe du contenu de HL Ce dernier est donc maintenant chargé avec -H.

Ligne 14 : Chargement du registre DE avec 0 (n'oublions pas que, pour charger un registre double, il faut obligatoirement indiquer les deux octets de la valeur, le fort et le faible, même s'ils sont égaux à 0).

Ligne 15 : Appel de la routine d'adresse &BBF9, qui trace une ligne à partir de la position actuelle du curseur jusqu'à une position relative déterminée par DE (abscisse) et HL (ordonnée).
Voilà donc notre première ligne tracée (de plus, le curseur se trouve maintenant en X1,Y1).
Il est temps maintenant de tester le paramètre PV pour déterminer si le quadrilatère doit être plein ou vide.

Ligne 16 : Chargement de A avec 1 (nous verrons pourquoi plus loin).

Ligne 17 : Comparaison de A et du contenu de l'emplacement d'adresse IX+ 0. La comparaison se passe de la manière suivante : le contenu de l'emplacement mémoire d'adresse IX + 0 est soustrait de A, et le résultat n'est pas conservé (ce qui revient à dire que A n'est pas modifié. C'est en quelque sorte une soustraction "de tête"). Néanmoins, les indicateurs Z et S sont modifiés en fonction : en particulier, Z est mis à 1 si la comparaison indique l'égalité (en l'occurrence, si (IX + 0)=A, ce dernier ayant été chargé avec 1).
Pour résumer, l'indicateur de 0 sera mis si le paramètre PV=1.

Ligne 18 : Saut relatif de 31 (en ligne 36), si l'indicateur de 0 n'est pas mis, donc s'il s'agit de dessiner un carré vide. Dans le cas contraire, le saut n'est pas fait et le programme continue en ligne 19, où commence l'exécution du quadrilatère plein.
La figure ci-après montre le principe adopté :

Il s'agit de dessiner une série de lignes les unes contre les autres, de manière à obtenir un quadrilatère plein. Chacune d'entre elles sera tracée exactement de la même manière que la première, à la seule différence que les abscisses de l'extrémité supérieure seront, pour chaque nouvelle ligne, décalées vers la droite. Comme vous le voyez, nous avons indiqué ces abscisses sous la forme : XC + 2, XC + 4, etc., ce qui signifie que ce décalage se fera de deux en deux. En voici la raison : de par le fonctionnement de l'écran graphique du CPC, une ligne verticale a obligatoirement une largeur de 1 pixel en mode 2, de 2 pixels en mode 1, et de 4 pixels en mode 0. Puisque nous avons choisi de travailler en mode 1, chaque décalage vers la droite pourra être de 2 pixels (nous pourrions faire des décalages de 1, mais le temps d'exécution serait alors doublé inutilement car nous écririons sur des lignes déjà tracées).
Pour en revenir à la figure, les coordonnées du point bas de chaque ligne sont bien sûr relatives au point haut de la même ligne. Puisque nous allons tracer toutes ces lignes en suivant le même processus, il va nous falloir une boucle. Or, qui dit boucle dit compteur.

C'est le paramètre L (largeur) qui va nous en tenir lieu : nous voulons un quadrilatère de largeur L (L étant exprimé en pixels); or, chaque fois que nous traçons une ligne, elle fait 2 pixels de large. Chaque fois, donc, nous enlèverons 2 à la largeur, jusqu'à ce que le résultat soit négatif (on ne peut pas dire : "jusqu'à ce que le résultat soit nul" car, si L est impair, le compteur passerait de 1 à –1 et ne serait donc

jamais nul : cas typique d'une boucle sans fin qui peut obliger à éteindre la machine).

Le compteur est constitué par les lignes 19 à 23 :

Lignes 19 et 20: HL est chargé avec le paramètre L.

Ligne 21 : Chargement de DE avec 2.

Ligne 22 : DE est soustrait de HL (le résultat est rangé dans HL).

Ligne 23 : Saut conditionnel à l'adresse 43854 (&AB4E, ligne 28) si le résultat est positif, c'est-à-dire si la boucle doit continuer.
Nous allons laisser de côté les lignes 24 à 37 pour le moment, et nous intéresser d'abord au cas où la boucle n'est pas terminée :

Lignes 28 et 29 : Le contenu de H est chargé dans l'emplacement mémoire d'adresse IX+ 7 et celui de L dans l'emplacement mémoire d'adresse IX+6. Le résultat est donc qu'à chaque tour de boucle la nouvelle valeur de L (qui, ne l'oublions pas, vient d'être décrémentée de 2 à la ligne 22) est rangée à la place de l'ancienne. A chaque tour également, elle sera reprise en lignes 18 et 19, puis diminuée de 2, puis rangée, et ainsi de suite jusqu'à ce qu'elle devienne négative.

Ligne 30 : Si vous avez bien suivi la pile, vous savez que, jusqu'à présent, il y avait le paramètre H sur son sommet. Nous n'aurons plus besoin de cette donnée, et nous la faisons disparaître de la pile en dépilant BC.

Ligne 31 : Sur le sommet de la pile se trouve maintenant l'ordonnée YC. Elle est chargée dans HL.

Ligne 32 : Chargement de l'abscisse XC (à partir de maintenant, nous considérerons que vous connaissez, à chaque instant, l'état de la pile).

Lignes 33 et 34 : Comme nous l'avons expliqué précédement, l'abscisse du point de départ de la ligne suivante doit être décalée de 2 vers la droite par rapport à celle qui vient d'être tracée. C'est pourquoi nous incrémentons (= ajoutons 1) deux fois DE. HL est donc maintenant chargé avec YC, et DE avec XC + 2 (tout au moins au deuxième tour de boucle. Au troisième tour ce sera XC + 4, au quatrième tour XC + 6, etc.).

Ligne 35 : Saut relatif de -59, c'est-à-dire en ligne 7. Là, les valeurs contenues actuellement dans DE et HL sont sauvegardées, puis le curseur est fixé, la ligne tracée, et ainsi de suite.
Lorsque la boucle est terminée, le saut de la ligne 23 ne se fait pas, et le programme passe à la ligne 24.

Lignes 24, 25 et 26 : Si le programme arrive à la ligne 24, c'est donc que le dessin du quadrilatère est terminé, et qu'il faut revenir au BASIC. Mais auparavant, il faut remettre la pile en état (revoir à ce sujet la Deuxième partie).
Nous avions empilé trois valeurs sur la pile, elles y sont encore pour l'instant. La pile est donc "nettoyée" par trois dépilements successifs de BC (nous aurions pu dépiler n'importe quel registre, mais dans ces cas-là, et pour des raisons qu'il serait trop long de développer, il faut mieux utiliser BC).
L'étude du bloc "Quadrilatère plein" étant terminé, passons au bloc "Quadrilatère vide".

Le processus de traçage sera le suivant :

Les lignes 2, 3 et 4 seront tracées les unes après les autres et dans cet ordre. Il faut remarquer que :

  • Les coordonnées du point (X2,Y2) relativement à (X1,Y1) sont (L,0).
  • Les coordonnées du point (X3,Y3) relativement à (X2.Y2) sont (0,H).
  • Les coordonnées du point (XC,YC) relativement à (X3,Y3) sont ( –L,0). (N'oublions pas que XC et YC sont des cordonnées absolues.)

Il est peut-être utile de rappeler la situation au moment où s'effectue le branchement de la ligne 18 :

La ligne 1 est tracée, le curseur est positionné en (X1,Y1) et il y a trois valeurs stockées sur la pile (H se trouve au sommet, YC juste en dessous et XC encore en dessous).

Lignes 36 et 37 : Chargement de DE avec le paramètre L.

Lignes 38, 39 et 40 : Il s'agit ici de sauvegarder le paramètre chargé dans DE, mais, pour des raisons pratiques qui s'expliqueront d'elles-mêmes plus loin, il faut que cette valeur ne soit pas sur le sommet de la pile, mais à l'avant-dernier étage. C'est pourquoi la ligne 38 "soulève" H, après quoi DE est empilé, puis H "reposé".

Ligne 41 : Chargement de HL avec 0.

Ligne 42 : Appel de la routine d'adresse &BBF9. La ligne 2 est maintenant tracée (par la même occasion, le curseur est en (X2,Y2)).

Lignes 43, 44 et 45 : Chargement de HL avec H, de DE avec 0, et tracé de la ligne 3.

Lignes 46 et 47 : Chargement de L dans HL, puis appel de la routine &BDC7 (déjà étudiée en ligne 13). HL est donc maintenant chargé avec -L.

Ligne 48 : 0 dans DE.

Ligne 49 : Une nouvelle instruction : les contenus de HL et DE sont échangés. Pour tracer la ligne 4, c'est en effet DE qui doit être chargé avec –L et HL avec 0.

Ligne 50 : Tracé de la ligne 4.

Lignes 51 et 52 : Remise en état de la pile.

Ligne 53 : Retour au BASIC. L'utilisation de ce programme ne pose en principe aucun problème, même si vous fournissez des paramètres erronés ou si vous en oubliez. Dans le pire des cas, rien ne se passera.
Voici un programme de démonstration :

100 MODE 0
110 FOR 1 = 1 TO 100 : GOSUB 180
120 CALL 43790,A,B,C,D,E,0
130 NEXT I
140 FOR 1 = 1 TO 100 : GOSUB 180
150 CALL 43790,A,B,C,D,E,1
160 NEXT I
170 END
180 A=INT(RND * 640) : B = INT(RND * 400) : C = INT(RND*300):D = INT(RND*300):E = INT(RND*16):RETURN

Essayez aussi en intercalant la ligne :

135 POKE 43863,&2B

Un bon exercice serait de chercher à comprendre la raison de l'étrange résultat provoqué par cette ligne...

★ ANNÉE: ???
★ AUTEUR: JEAN-CLAUDE DESPOINE

Page précédente : Nouvelles Instructions 005
Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop
Page créée en 136 millisecondes et consultée 1036 fois

L'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.