★ CODING ★ AMSTRAD CPC 464 - CRÉER DE NOUVELLES INSTRUCTIONS ★ |
Nouvelles Instructions 010 |
EXEMPLES DE PROGRAMMES 7. DÉPLACEMENT D'UN MOBILE (4 DIRECTIONS) Ceux d'entre vous qui s'y sont déjà essayé ont certainement pu se rendre compte des problèmes que pose la réalisation d'animations graphiques en BASIC. Dans beaucoup de cas, elles sont même impossibles à réaliser sans lenteurs excessives et phénomènes optiques désagréables, en particulier si le mobile couvre une surface d'écran importante. Ce septième progamme est donc particulièrement intéressant puisqu'il permet le déplacement dans les quatre directions, avec une excellente qualité de mouvement, d'un objet couvrant une surface de 64 octets (pour comparaison, un caractère en mode 1 est défini sur 16 octets). Le programme peut facilement être adapté pour un objet plus grand ou pour effectuer des déplacements dans d'autres directions (huit directions, par exemple). Il est le plus long de tous ceux que présente cet ouvrage, et je vous conseillerai d'une part de procéder "lentement mais sûrement", et d'autre part de relire rapidement l'Annexe III traitant de la mémoire écran. CALL 43650,D Le paramètre D détermine la direction du mouvement : 1 - haut Ensuite, nous aurons besoin de deux placards de 2 octets chacun, pour y stocker deux valeurs que nous nommerons Y et Y1. Les adresses de ces placards sont respectivement 43898 (&AB7A) et 43900 (&AB7C). Bloc 1 (lignes 2 à 9) : Il réalise les branchements à telle ou telle partie du programme en fonction du sens de déplacement. Bloc 2 (lignes 10 à 26) : Déplacement vers le bas. Bloc 3 (lignes 27 à 43) : Déplacement vers le haut. Bloc 4 (lignes 44 à 68) : Déplacement vers la droite. Bloc 5 (lignes 69 à 94) : Déplacement vers la gauche. Blocs 6, 7, 8, 9 (respectivement lignes 95 à 105, 106 à 116, 117 à 126. 127 à 136): Il s'agit là de quatre sous-programmes internes qui seront expliqués plus loin. Voici le listing de ce programme :
La ligne 1 se passe de commentaires puisqu'il s'agit de l'appel de la routine de synchronisation avec le rayon (déjà étudiée). Nous commencerons donc par le blod, mais auparavant, lancez sur votre machine le petit programme suivant: 10 FOR I = 1 T0 4 : PRINT I,BIN$(I,8) : PRINT : NEXT Ce qui apparaît sur l'écran après lancement est la représentation en code binaire des nombres 1, 2, 3 et 4 : Rassurez-vous, il ne nous est pas indispensable de comprendre la théorie de l'arithmétique binaire. Il suffit de savoir que la représentation en binaire d'un nombre compris entre 0 et 255 s'effectue sur ce que l'on appelle des bits, numérotés de 0 à 7 en partant de la droite et qui n'ont que deux états possibles : 0 ou 1. Notons que si l'on se contente d'écrire dans le programme "BIN$(I)" au lieu de "BIN$(I,8)", la machine ne prend pas la peine de noter les 0 situés à gauche du dernier 1 (BIN$(4) donnerait par exemple 101). C'est pourquoi nous ajoutons le 8 qui force la machine à écrire les 8 bits. * Si le bit n°2 de D est à 1, c'est que D vaut 4, et le programme doit sauter au bloc "Déplacement vers la gauche". Dans le cas contraire : * Si le bit n°1 est mis à 0, il y a deux possibilités : D vaut 4 ou 1. Mais comme nous avons vu plus haut que D ne valait pas 4, D vaut donc 1 et le programme doit sauter au bloc "Déplacement vers le haut". Dans le cas contraire : * Si le bit 0 de D est à 1, D peut valoir 1 ou 3. Nous avons vu précédemment que D ne valait pas 1, D vaut donc 3 et le programme doit sauter au bloc "Déplacement vers le bas". Dans le cas contraire : * Si D ne vaut ni 4, ni 3, ni 1, c'est que D vaut 2 et le programme doit sauter au bloc "Déplacement vers la droite". On peut remarquer que cette méthode permet en même temps une protection implicite puisqu'un des quatre sauts se fera obligatoirement, même si le paramètre D fourni est erroné. Nous n'aurons pas à nous préoccuper de transformer D en binaire. Celui-ci est en effet le langage naturel de l'ordinateur, et il ne travaille qu'avec lui lorsque nous employons l'hexadécimal, c'est par simple commodité. La première chose que fait donc l'ordinateur, c'est de traduire l'hexadécimal en binaire. Pour tester les bits d'une valeur, nous utiliserons l'instruction "Test le bit numéro tant de tel registre". En l'occurrence, nous chargerons n dans le registre B. Il faut enfin savoir que cette instruction met l'indicateur de 0 si le bit testé vaut 0, et met l'indicateur de "non 0" si le bit testé vaut 1. Après ces explications, les lignes 2 à 9 se passent presque de commentaires : Ligne 2 Chargement de B avec le paramètre D. Ligne 3 Test du bit 2 de B. Ligne 4 Saut de +120 (ligne 69 : déplacement gauche) si non nul. Ligne 5 Test du bit 1 de B. Ligne 6 Saut de +40 (ligne 27 : déplacement haut) si nul. Ligne 7 Test du bit 0 de B. Ligne 8 Saut de +2 (ligne 10 : déplacement bas) si non nul. Ligne 9 Saut de +68 (ligne 44 : déplacement droit). Nous allons maintenant étudier le bloc de lignes 10 à 26 qui effectue le déplacement vers le bas. Pour suivre les explications, référez-vous systématiquement à la figure suivante. Sur cette figure, la position initiale du mobile, choisie arbitrairement, est indiquée par la zone hachurée. Les lignes et colonnes indiquées (qui ne sont vraies que pour le mode 1), ainsi que les numéros d'octets correspondants, ne servent que d'exemple et le raisonnement est valable quelle que soit la position initiale du mobile. D'autre part, et pour éviter la surcharge du dessin, seuls les premiers et huitième traits de chaque ligne ont été représentés. Enfin, l'ensemble est divisé en 16 blocs de 16 octets chacun, qui représentent en fait l'intersection d'une ligne et d'une colonne ou, si l'on préfère, une position de caractère en model. Notre mobile s'inscrivant initialement en VI, VII, IX et X, le déplacer vers le bas revient à effectuer les opérations suivantes : 1. Transférer X dans XIV Le sous-bloc constitué des lignes 10 à 18 réalise les deux premières opérations. Ligne 10 Y1 est chargé dans HL. Ligne 11 80 est chargé dans DE. Ligne 12 Sauvegarde de Y1. Ligne 13 Addition de HL et DE. Le résultat se retrouve dans HL. Ligne 14 Échange de HL et DE. Ce dernier est donc maintenant chargé avec Y1+80. Rappelons (voir Annexe III) que pour passer d'un octet d'une ligne à l'octet de même situation mais une ligne plus bas, il suffit d'ajouter 80 au premier. Puisque DE est chargé avec Y1+80, il est donc pointé sur l'obg de XIV (63732 sur la figure). Ligne 15 Y1 est remis dans HL. Ligne 16 Ou "l'art d'être prévoyant" ; quand le mobile aura été déplacé d'une ligne vers le bas, à la fin du programme, Y et Y1 devront également être descendus d'une ligne pour suivre le mouvement. Sur notre exemple, Ligne 17 Même chose, mais pour la future valeur de Y qui se trouve actuellement chargée dans HL. Remarquons que cette future valeur de Y est égale à la valeur actuelle de Y1. Ligne 18 Appel du sous-programme interne d'adresse 43824 (ligne 95). Voyons ce sous-programme : Lignes 95 et 96 Chargement de 8 dans A et de 4 dans BC. Ce sont là deux compteurs qui vont nous servir pour le transfert (pour transférer X et XI dans XIV et XV), il faut en effet transférer les huit traits de 4 octets chacun qui les composent. Ligne 97 Transfert répétitif avec incrémentation (cette instruction a déjà été étudiée plusieurs fois). Lignes 98 et 99 Décrémentation de A, puis retour de sous-programme si nul. Avant de passer au septième trait, nous vérifions, grâce au compteur, combien de traits ont déjà été transférés. Si les huit l'ont été, le retour en ligne 19 est effectué, sinon le sous-programme continue en séquence. Pour transférer le trait suivant, nous devons au préalable pointer HL sur l'octet situé immédiatement au-dessus de l'obg de X. Il n'est pas représenté, mais son adresse est 63652–2048 = 61604 (là encore, voir l'Annexe III). De même, DE doit être pointé sur l'octet immédiatement au-dessus de l'obg de XIV ( = 63732-2048 = 61684). On se rend compte que cela est possible en enlevant 2052 à la valeur actuelle de HL et DE (63656-2052 = 61604 et 63736-2052 = 61684). C'est ce que vont faire les cinq lignes qui suivent : Ligne 100 Chargement de 2052 dans BC. Ligne 101 BC est soustrait de HL (le résultat est dans HL et BC reste inchangé). Ligne 102 Échange de HL et DE. Ligne 103 BC est soustrait de HL. Ligne 104 Échange de HL et DE qui sont donc maintenant correctement pointés au début du septième trait de X et XIV. Ligne 105 Saut relatif de -18 (ligne 96). Là, le compteur de transfert répétitif est à nouveau chargé avec 4, puis le transfert a lieu, A est décrémenté, et ainsi de suite. Après huit tours de boucle, au terme desquels les huit traits de X et XI auront été transférés, le retour de sous-programme sera effectué (en ligne 19). Ligne 24 Appel du même sous-programme interne que précédemment. Au retour de ce sous-programme, VI et VII auront été transférés dans X et XI, HL sera pointé sur 49240 et DE sur 49320. Il reste à effacer VI et VII. Ligne 25 Le sous-programme interne d'adresse 43864 qui est appelé ici va se charger de cet effacement. Ligne 117 Chargement de DE avec 2052. Nous verrons pourquoi plus loin. Chargement de 8 dans A et de 4 dans B. Ils serviront de compteurs : il y a huit traits de 4 octets chacun Ligne 120 Décrémentation de HL. Comme ce dernier était pointé sur 49240, il l'est maintenant sur 49239. Ligne 121 La valeur 0 est chargée dans l'emplacement mémoire adressé par HL (ou si l'on veut, l'emplacement 49239 de la mémoire écran est mis à 0, donc effacé). Ligne 122 Décrémentation de B et saut de –5 (ligne 120) si non nul. Les lignes 120 et 121 vont donc être exécutées quatre fois, HL pointant successivement sur 49239, 49238, 49237 et 49236 et les effaçant. Cela fait, B vaudra 0 et le sous-programme se poursuivra en séquence. Lignes 123 et 124 Décrémentation de A et retour si nul. Nous vérifions le nombre de traits effacés. Si les huit ne l'ont pas été, le sous-programme se poursuit. Ligne 125 Addition de HL et DE (le résultat est dans HL et DE reste inchangé). HL est maintenant correctement pointé. Ligne 126 Saut relatif de –12 (ligne 119). Ainsi la boucle va tourner tant que les huit traits de VI et VII n'auront pas été effacés. Cette ligne est la dernière du sous-programme d'effaçage. Le retour se fait en ligne 26. Ligne 26 Le bloc "Déplacement vers le bas" étant terminé, retour au BASIC. Le bloc "Déplacement vers le haut", qui va des lignes 27 à 43, effectue les opérations suivantes : 1. Transférer VI et VII dans II et III. Sans être tout à fait identique, il suit la même démarche que le bloc précédent, et vous ne devriez pas avoir de difficulté à l'étudier seul, pour peu que vous y alliez lentement et en prenant le temps de réfléchir. Nous nous contenterons donc de donner la traduction en clair de chaque ligne : Ligne 27 Y est chargé dans HL. Ligne 28 80 est chargé dans DE. Ligne 29 Empilement de Y. Ligne 30 HL moins DE. Ligne 31 Échange de HL et DE. Ligne 32 Empilement de HL. Ligne 33 Chargement de l'emplacement mémoire 43900 avec DE. Ligne 34 Chargement de l'emplacement mémoire 43898 avec HL. Ligne 35 Appel du sous-programme d'adresse 43824. Ligne 36 Chargement de BC avec 14412. Ligne 37 HL plus BC. Ligne 38 Échange de HL et DE. Ligne 39 HL plus BC. Ligne 40 Échange de HL et DE. Ligne 41 Appel du sous-programme d'adresse 43824. Ligne 42 Appel du sous-programme d'adresse 43864. Ligne 43 Retour de sous-programme. Passons maintenant au bloc "Déplacement vers la droite" (lignes 44 à 68). L'ordre des opérations qu'il convient de faire, indiqué ci-dessous, est un peu différent de celui des blocs précédents : 1. Transférer X et XI dans XI et XII. Les lignes 44 à 56 réalisent les deux premières opérations : Ligne 44 HL est pointé sur Y1. Lignes 45 et 46 Deux incrémentations successives qui ont pour effet de pointer HL sur l'obg de XI (63654 sur notre exemple). Ligne 47 Rangement de la future valeur de Y1 dans son placard. Ligne 48 Pointage de HL sur l'obd (octet bas droit) de XI (63655 sur notre exemple). Lignes 49 et 50 Une manière rapide de charger DE avec la même valeur que HL. Ils sont maintenant tous deux pointés sur l'obd de XI. Lignes 51 et 52 DE est pointé sur l'obd de XII. Ligne 53 Appel du sous-programme interne d'adresse 43844 (&AB44). Voyons ce sous-programme : Lignes 106 et 107 Chargement de 8 dans A, puis de 4 dans BC. Vous avez compris qu'il s'agit là de l'initialisation des compteurs (pour transférer les blocs X et XI, il faut transférer les huit traits de 4 octets chacun qui les composent). Ligne 108 Transfert répétitif avec décrémentation. Après l'exécution de cette ligne, le trait concerné a été décalé de deux positions vers la droite. Sur notre exemple, et après le premier tour de boucle concernant le huitième trait, HL se retrouve pointé sur 63651 et DE sur 63653. Il faut maintenant transférer le trait suivant, situé juste au-dessus de celui-là, après avoir vérifié, grâce aux lignes 109 (décrémentation de A) et 110 (retour si nul), que les huit traits n'ont pas été transférés. Lorsque les huit traits sont transférés, le retour de sous-programme est effectué et l'on revient à la ligne 54. A ce moment précis, HL est pointé sur l'ohd (octet haut droit) de IX (49315 sur notre exemple), et DE sur l'ohd de X (49317 sur l'exemple). Lignes 54 et 55 Nous aurons besoin ultérieurement des valeurs contenues dans HL et DE, et nous les sauvegardons par empilement. Ligne 56 Appel du sous-programme interne d'adresse 43881 (&AB69), ligne 127. C'est lui qui va se charger de l'effaçage du bloc X. Ligne 127 Chargement de DE avec 2046. Nous verrons pourquoi plus loin. Lignes 128 et 129 Chargement de 8 dans A et de 4 dans 8 : les compteurs sont initialisés (il y aura huit traits de 2 octets chacun à effacer). Ligne 130 Incrémentation de HL. Rappelons que ce dernier était toujours pointé sur l'ohd de IX. Il l'est maintenant sur l'ohg de X (49236 sur l'exemple). Ligne 131 Chargement de 0 dans l'emplacement mémoire adressé par HL ou, si l'on veut, effacement de cet emplacement. Ligne 132 Décrémentation de B et saut relatif de –5 (en ligne 129) si non nul. Les lignes 129 et 130 vont donc être exécutées deux fois, HL pointant d'abord sur l'ohg puis l'ohd de X (49316 et 49317 sur notre exemple). Lorsque cela est terminé, donc lorsque le premier trait est effacé, le sous-programme continue en séquence. Lignes 133 et 134 Décrémentation de A et retour si nul. Le nombre de traits déjà effacés est vérifié. Si les huit l'ont été, le retour est effectué (en ligne 57), sinon le sous-programme continue en séquence. Pour effacer le trait suivant, HL doit être pointé comme précédemment, mais un trait plus bas. Il suffit pour cela d'ajouter 2046 à sa valeur actuelle (49317 + 2046 = 51363). Or DE avait justement été chargé avec 2046 en ligne 127, et il l'est toujours. Il suffit donc d'ajouter DE et HL, comme le fait cette ligne (rappelons que le résultat se retrouve dans HL et que DE reste inchangé). Ligne 136 Saut relatif de –12 (en ligne 129). Là, le compteur B est réinitialisé, HL est incrémenté, l'emplacement qu'il adresse effacé, etc. Lignes 57 et 58 Dépilement des registres DE puis HL qui se retrouvent donc respectivement pointés sur l'ohd de X et l'ohd de IX. Mais ce que nous voulons obtenir, c'est leur pointage sur l'obd de VIII et l'obd de VII. On atteint ce résultat en leur ajoutant 14260 (49317 + 14260 = 63577 et 49315 + 14260 = 63575). Cette opération est réalisée par les lignes 59 à 63. Leur principe vous est maintenant familier, et nous n'y reviendrons pas. La ligne 64 appelle ensuite le sous-programme d'adresse 43844, déjà étudié, et qui réalise le transfert. La ligne 65 appelle le sous-programme d'adresse 43881 qui efface le bloc VI. Ligne 66 Incrémentation de HL qui contient donc maintenant l'adresse de l'obg de VII, c'est-à-dire la valeur de Y après le déplacement du mobile. Ligne 67 Cette valeur est rangée dans son placard. Ligne 68 Le déplacement vers la droite étant terminé, le retour au BASIC est effectué. Avant d'en avoir tout à fait terminé, il nous faut encore élucider l'énigme des adresses Y et Y1. Regardez à nouveau la figure : le mobile est situé au départ sur quatre emplacements dont les coordonnées sont (3,2), (4,2), (3,3) et (4,3). Or, l'adresse de l'obg d'un emplacement donné peut fort bien être calculée en fonction des coordonnées de cet emplacement: obg d'un emplacement Soit, dans notre cas : Y = 63406 + (80 * 2) + (3 * 2) = 63572 et Y1 = 63406 + (80 * 3) + (3 * 2) = 63652 Une fois ces adresses calculées, rien n'est plus facile que de les ranger dans leurs placards. Convertissons-les d'abord en hexadécimal : HEX$(63572) = F854 HEX$(63652) = F8A4 Rappelons que, lorsque l'on range un nombre en mémoire, l'octet faible est toujours rangé en premier. Voici donc la ligne BASIC qui range Y et Y1 : POKE 43898.&A4 : POKE 43899,&F8 : POKE 43900,&54 : POKE 43901,&F8Il n'est nécessaire d'exécuter cette ligne qu'une seule fois avant de pouvoir faire appel au programme de déplacement, puisque Y et Y1 sont sauvegardés au fur et à mesure que le mobile se déplace. Ce programme n'a maintenant plus de secrets pour vous et, fidèles à la coutume, nous vous proposons ci-dessous deux exemples de son utilisation : 100 POKE 43898,&A4 : POKE 43899.&F8 : POKE 43900.&54 : POKE 43901,&F8 |
|
Page précédente : Nouvelles Instructions 009 |
|
Page créée en 413 millisecondes et consultée 1101 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. |