★ CODING ★ CLASSEURS WEKA ★ Comment exploiter toutes les ressources et augmenter les performances de votre AMSTRAD CPC ★ |
4/1.6.2 - L'instruction CALL et les RSX en Basic | Coding Classeurs Weka |
4/0 - Langages du CPC4/1.6 - Basic approfondi 4/1.6.2 - L'instruction CALL et les RSX en Basic Introduction Nous allons, dans ce chapitre, nous consacrer à la réalisation d'instructions supplémentaires au Basic des AMSTRAD-CPC. Nous procéderons par étapes successives, qui vous permettront d'accéder à la personnalisation du jeu d'instructions, en y introduisant vos propres commandes, au nom que vous aurez choisi, et qui appellent bien sûr, des routines en langage machine permettant de les traiter. Quelques exemples vous permettront de créer vos premières instructions simples sans grandes connaissances en langage machine. Vous devrez, ensuite, connaître un minimum de programmation en assembleur, afin de créer des routines plus élaborées ; mais une lecture assidue de votre ouvrage, vous ouvrira les portes du microprocesseur Z80 (on se reportera avec intérêt à la Partie 4, chapitre 2). I - L'instruction CALL PREMIERS PAS AVEC L'INSTRUCTION CALL Vous aurez déjà remarqué dans certains programmes de votre ouvrage, l'appel à des routines en langage machine grâce à l'instruction Basic: CALL adresse Cette instruction lance l'exécution d'une routine en langage machine située à partir de l'adresse spécifiée, et, ce, en général, dans la mémoire vive de votre CPC. Cette adresse peut être décrite en décimal, signé ou non, (par exemple CALL 47878 ou CALL - 17658), éventuellement en binaire (CALL &X1011101100000110, mais trop complexe pour être utilisée), ou, le plus souvent, en hexadécimal (par exemple CALL &BB06). Il est même possible d'appeler une routine dont l'adresse est contenue dans une variable numérique (CALL A ; A contenant l'adresse de la routine à appeler). Dans les exemples indiqués ci-dessus, les adresses données sont rigoureusement identiques, et provoquent donc l'appel à une même routine, qui est un vecteur appelant une routine en ROM attendant l'appui sur une touche du clavier (voir Partie 4, chapitre 2.7 page 3). Les explications seront données de façon à ce que vous puissiez modifier le programme, et inscrire votre propre nom à la place de celui de WEKA. Il faut tout d'abord savoir que pour afficher des caractères sur l'écran, l'AMSTRAD ne comprend que les codes ASCII de ces caractères (codes hexadécimauxl. PRINT CHR$(&57) ; CHR$(&45) ;CHR$(&4B) ; CHR$(&41) |
Hexa | Décimal | Fonction |
00 | 0 | Caractère nul - aucune action. |
01 | 1 | Visualise sur l'écran les caractères de contrôle. Par exemple en Basic PRINT CHR$(1 );CHR$(10) affiche une flèche vers le bas. |
02 | 2 | Permet de ne pas visualiser le curseur en mode programme (lors d'un INPUT par exemple). |
03 | 3 | Rétablit le curseur. |
04 | 4 | Change le mode graphique, comme l'instruction MODE. Exemple : PRINT CHR$(4) ; CHR$(2) passe en MODE 2. |
05 | 5 | Ecrit un caractère à l'emplacement du curseur graphique. |
06 | 6 | Annule la commande de masquage sur écran (voir le code 21 décimal) |
07 | 7 | Emet le BIP de la cloche. |
08 | 8 | Effectue un déplacement d'un caractère vers la gauche. |
09 | 9 | Effectue un déplacement d'un caractère vers la droite. |
0A | 10 | Effectue un déplacement d'un caractère vers le bas. |
0B | 11 | Effectue un déplacement d'un caractère vers le haut. |
0C | 12 | Efface la fenêtre courante (équivalent de CLS du Basic). |
0D | 13 | Retour Chariot : place le curseur à la gauche de la ligne courante. |
0E | 14 | Equivalent à l'instruction PAPER PRINT CHR$(14);CHR$(2), place la couleur du fond de l'écran à la couleur de l'encre 2. |
0F | 15 | Equivalent à l'instruction PEN. |
10 | 16 | Equivalent de la fonction effectuée par la touche < CRL > : efface le caractère sous le curseur. |
11 | 17 | Efface tous les caractères précédant le curseur dans la ligne courante. |
12 | 18 | Efface tous les caractères suivant le curseur dans la ligne courante. |
13 | 19 | Efface tous les caractères depuis le début de la fenêtre courante jusqu'au curseur. |
14 | 20 | Efface tous les caractères depuis le curseur jusqu'à la fin de la fenêtre courante. |
15 | 21 | En relation avec le code 06 : interdit l'affichage à l'écran. |
16 | 22 | Permet d'écrire des caractères en mode transparence, c'est-à-dire d'écrire sur un caractère déjà affiché : PRINT CHR$(22);CHRS$1 : mode transparent, PRINT CHR$(22);CHR$(0) : mode normal. |
17 | 23 | Modifie le mode graphique (accompagné de CHR$(1 ) ; CHR$(2) ; CHR$(3) ; CHR$(4). |
18 | 24 | Fonctionne en bascule pour établir ou annuler l'inversion vidéo. |
19 | 25 | Equivalent de la commande SYMBOL en Basic. Ce code nécessite d'être suivi de 9 paramètres (le numéro du caractère puis les 8 valeurs le définissant). |
1A | 26 | Equivalent de la commande WINDOW en Basic, mais uniquement avec les quatre chiffres définissant la fenêtre. |
1B | 27 | Caractère d'échappement (ESCAPE), utile pour la communication, avec un Minitel par exemple, ou l'imprimante. |
1C | 28 | Equivalent à la fonction INK du Basic mais demande à être suivie obligatoirement des trois chiffres (numéro d'encre, couleur 1, couleur 2). |
1D | 29 | Equivalent à BORDER avec deux couleurs obligatoirement. |
1E | 30 | Place le curseur à la position originelle de la fenêtre. |
1F | 31 | Equivalent de LOCATE Basic, donc suivi de deux caractères. |
La méthode retenue est de déplacer tous les pixels un à un d'une position.
Il faut savoir que ces pixels sont inscrits en RAM ECRAN entre les adresses &C000 et &FFFF. Voici la carte de ta mémoire écran suite à une initialisation du CPC ou après une instruction MODE n:
Organisation des adresses écran des CPC après l'instruction MODE.
On trouvera donc les pixels de la dernière ligne de caractères entre les adresses &C780-&C7CF, &CF80-&CFCF.....&FF80-&FFCF. Lorsqu'on lira une de ces adresses (grâce à PEEK (adresse)) on obtiendra la valeur hexadécimale de huit pixels de cette adresse.
Notre méthode de décalage consistera à lire l'adresse la plus à droite d'une ligne de pixel, décaler ces pixels un à un, récupérer le pixel de gauche, l'inscrire en tant que pixel de droite lors du décalage des pixels de l'adresse immédiatement à gauche,... etc., jusqu'à l'adresse la plus à gauche. Il ne faudra pas oublier ensuite de replacer le pixel décalé le plus à gauche à la place du pixel le plus à droite 30us peine de perdre un pixel à chaque décalage, ce qui ferait disparaître notre message. Les décalages sur une ligne de pixels étant effectués, il faudra passer à la ligne suivante, et ainsi de suite.
Deux petits problèmes se posent tout de même : d'une part la mémoire écran ne contient pas seulement l'état allumé ou non des pixels, d'autre part elle ne se trouve pas toujours aux mêmes adresses. Certaines restrictions d'utilisation nous seront donc imposées : appeler toujours cette routine suite à une instruction MODE fi (car un scrolling décale toute la mémoire écran), de préférence en MODE 2 car dans les autres modes, les couleurs sont inscrites dans les adresses écran (bien que l'effet ne soit pas désagréable en MODE 1 : on obtient un passage dans les différentes couleurs du message).
Nous vous proposons maintenant l'ordinogramme du scrolling horizontal :
On remarquera dans cet ordinogramme l'appel de la routine &BB09 qui va contrôler si un caractère a été frappé sans l'attendre (équivalent de INKEY$ du Basic), pour nous permettre de quitter la routine de décalage.
Le programme assembleur commenté sera donc :
On retrouve la routine d'affichage de caractères aux adresses &A006-&A00F qui positionne le curseur en ligne 25 colonne 1, ainsi qu'aux adresses &A01D-&A022 pour afficher le message.
A l'adresse &A024, le nombre hexadécimal &800 chargé dans le double registre DE correspond au nombre d'adresses à ajouter pour passer à la ligne de pixels suivante.
A l'adresse &A02F, le chargement dans B de la valeur &50 correspond au nombre d'adresses d'une ligne (&50 = 80 decimal),
Pour ceux qui ne possèdent pas d'assembleur, mais que ce programme intéresse, nous vous soumettons le chargeur Basic des instructions ci-dessous :
L'appel de l'instruction se fera sous la forme :
si vous possédez un CPC-6128.
Les possesseurs d'un CPC-464 devront ruser pour faire digérer cette instruction à leur ordinateur. Ils devront en effet passer par l'intermédiaire d'une variable alphanumérique, la routine sera donc appelée en deux temps :
CALL &A000,@A$
Ce qui ne change rien aux explications données plus haut, c'est cette fois le pointeur de la variable A$ qui est transmis aux travers des adresses IX + OOH et IX + 01 H.
Tout comme pour le passage des variables numériques entières, il est possible de passer à la routine plusieurs chaînes de caractères par les instructions :
ou CALL &A000,@A1$,@2$, ... @An$
LA RECUPERATION DES VARIABLES NUMERIQUES
S'il est possible de transmettre à la routine des variables, il est inversement possible de récupérer des résultats suite à un traitement, dans une variable.
Il suffit en effet de passer à la routine le pointeur d'une variable pour qu'elle aille y sauvegarder des valeurs, que l'on pourra relire sous Basic dans la variable.
Pour passer le pointeur d'une variable numérique, il suffit qu'elle existe, elle sera donc créée par l'instruction VARIABLE% = 0 par exemple.
Lors de l'appel de la routine il suffira d'y adjoindre son pointeur @VARIABLE%, qui sera lu dans la pile pointée par IX, l'adresse sera ensuite connue et les éventuels résultats rangés à cette adresse.
LA RECUPERATION DES VARIABLES ALPHANUMERIQUES
Il est également possible de récupérer des chaînes de caractères traitées dans une routine en langage machine.
Pour une seule chaîne de caractères, il suffit de créer une variable par A$ = SPACES(n), n étant généralement le nombre de caractères maximal que pourra contenir la chaîne, puis on transmet le pointeur de cette chaîne par l'instruction :
CALL &adresse,@A$
Dans la routine il suffira de récupérer l'adresse de la variable à l'aide du pointeur, et de la traiter, en n'oubliant pas de spécifier le nombre de caractères la composant.
Nous allons prendre à titre d'exemple une routine permettant de convertir une chaîne de caractères contenant un message, en une autre chaîne contenant la conversion ASCII de tous ces caractères. Cette routine pourra vous être utile pour modifier le programme d'affichage d'un message.
Nous nous proposons d'appeler la routine sous la forme :
où A$ contient la chaîne à convertir, et B$ la conversion de tous les caractères.
Il faut d'abord savoir qu'une chaîne de caractères peut contenir au maximum 255 caractères, or, comme la conversion d'un caractère alphanumérique se traduit en deux chiffres hexadécimaux, 8$ ne pouvant ainsi contenir qu'au maximum 254 caractères, A n'en contiendra pas plus de 127.
Voici l'ordinogramme de conversion proposé :
L'ordinogramme d'affichage du message d'erreur n'est pas ici explicité car déjà vu précédemment.
On retrouve la lecture des deux pointeurs des variables qui sont traités afin de lire la chaîne de caractères et d'inscrire la chaîne convertie aux adresses correspondantes.
Le sous-programme de conversion est intéressant, car très rapide dans son exécution, et doit être retenu pour d'éventuelles utilisations ultérieures (procédures de communications, par exemple). Ce type de traitement provient d'une réflexion mathématique sur les différents codes ASCII des caractères. Il impose malheureusement une limitation aux caractères alphabétiques de A à F et aux chiffres de 0 à 9 (hexadécimal oblige).
Le programme en langage d'assemblage qui en découle est le suivant :
A l'adresse &A010 le test du nombre de caractères est effectué sur le bit le plus à gauche du nombre, car celui-ci passe à 1 dès que ce nombre est supérieur ou égal à 128.
On retiendra la partie de programme entre les adresses &A019 et &A01B qui consiste à mettre dans DE le contenu des adresses pointées par HL et HL+ 1. Si l'on y ajoute l'instruction EXG, DE, HL, on obtient un résultat correspondant à HL - (HL+1MLH).
Le listing du chargeur Basic est donné ci-après .
II - Les RSX
(Sur ce sujet reportez-vous également à la Partie 4, Chap. 2.9).
Après avoir étudié différentes façon de transmettre des paramètres à une routine en langage Machine, nous pouvons nous lancer dans la création des RSX.
Mot bien souvent magique, qui rebute beaucoup de programmeurs Basic, mais qui va être sans secret pour vous d'ici quelques instants.
RSX vient de la contraction du terme Résident System extension, qui, mot à mot veut dire extension résidente dans le système. Ces extensions sont dans notre cas des commandes Basic qui sont intégrées aux commandes déjà existantes, à la seule particularité qu'elles doivent être précédées du caractère ù (ou la barre verticale I) de code ASCII 124).
POURQUOI LES RSX ?
Oui, pourquoi créer de nouveaux noms d'instructions alors que pour appeler une routine en langage Machine, il suffit d'effectuer un appel à cette routine par CALL ?
Imaginez un Basic uniquement composé d'instructions CALL à différentes adresses, quelle mémoire devrez-vous posséder avant d'utiliser celle de votre ordinateur ! Il est bien plus simple de retenir une instruction par un nom que par un numéro, qui plus est hexadécimal !
COMMENT CREER UNE RSX ?
La création d'une RSX est très simple, maintenant que vous savez manier l'instruction CALL.
Un vecteur du système d'exploitation Basic est spécialement implanté pour cela :
(voir Partie 4, Chap. 2.7 page 54).
Ce vecteur s'utilise dans une petite routine en langage machine qui définit la ou les extensions à intégrer au Basic.
Il requiert différents paramètres qui sont :
La routine de liaison des RSX se présentera toujours sous la forme de l'algorithme suivant :
– DEBUT
– Charger HL avec l'adresse de la zone de quatre octets
– Charger BC avec l'adresse de la table des instructions
– PROCEDURE KL-LOG-EXT
– Placer le code de RET au début de la routine
– FIN
Ce qui nous donne en langage d'assemblage :
Le chargement du code RET à l'adresse de début de la routine de définition des instructions n'est pas obligatoire, mais il est vivement recommandé, car un deuxième appel à cette routine provoquerait un plantage du microprocesseur, et bien souvent l'obligation d'effectuer un RESET et de perdre toutes les données, pour reprendre la main.
Il faudra ensuite faire suivre cette routine des différents vecteurs et table
des instructions, de la façon suivante :
Nous trouvons dans cette partie de la routine à l'étiquette VECTEU la définition de l'adresse de la table des instructions, suivie de la table des sauts au traitement des instructions. Par exemple JP INSTRUCTION1, effectue un saut à la routine de traitement de l'instruction 1, ce traitement sera identique au traitement par l'instruction CALL.
Vient ensuite la table des instructions, qui doit être dans l'ordre de la table de saut des instructions. Dans cette table, les noms des instructions devront être obligatoirement écrits en MAJUSCULE, avec, de plus, le nombre hexadécimal &80 ajouté au dernier caractère, ceci pour que le moniteur reconnaisse ta fin de l'instruction.
On trouve en tout dernier la réservation de quatre octets pour la routine.
Il sera possible d'installer, après cette routine les différents traitements prévus.
Prenons un exemple simple : notre première instruction consistera à inscrire le nom de ùWEKA ou IWEKA, et à obtenir un message. Pour ceux qui ne posséderaient pas encore d'assembleur, nous vous donnerons le chargeur Basic, ainsi que toutes les explications pour modifier cette routine.
Le programme de traitement de cette instruction ne sera pas très différent du programme des premiers pas effectués avec l'instruction CALL, si ce n'est la définition de cette instruction. Aussi, nous vous donnons ci-dessous, directement, le listing assembleur ;
A l'adresse A014, nous trouvons les trois premières lettres de l'instruction WEK, puis, la lettre A à laquelle on ajoute &80 à l'adresse A017.
Le programme de traitement est identique à tous les programmes d'affichage de chaîne de caractères et de caractères de contrôle vus plus haut.
Après sauvegarde et assemblage, on procède à l'initialisation de l'instruction par les commandes :
Vous trouverez ci-dessous le listing Basic du chargeur de cette instruction :
Une fois sauvegardé, le programme sera exécuté par RUN, puis installé par :
Il sera ensuite possible d'effacer le chargeur Basic par NEW, et d'appeler l'instruction ùWEKA (ou |WEKA).
Ceux d'entre vous qui possèdent un assembleur n'auront aucun mal pour adapter l'instruction à leur nom par exemple, par contre voici les explications pour la modifier dans le chargeur Basic :
En lignes 390 à 410, il est réservé 21 octets pour le nom de l'instruction. Il vous suffira de modifier les quatre premiers octets, puis de remplacer les 00 par les codes ASCII de noms que vous désirez inscrire. Vous obtiendrez les codes ASCII du nom grâce à la table de conversion donnée plus haut, il vous suffira de frapper la commande :
PRINT HEX$ (&dernieroctet + &80) pour obtenir la valeur du dernier caractère du nom à inscrire.
Attention :
Le nombre d'octets de ces trois lignes doit impérativement être égal à 21 (les zéros compris).
Vous pourrez modifier ensuite le message entre les lignes 510 et 620. Vous pourrez cette fois-ci inscrire autant d'octets ASCII que vous désirez à la condition que les deux dernières valeurs en DATA (lignes 650 et 690) soient, dans l'ordre FF et XX.
Page précédente : 4/1.6.1 - SYMBOL et SYMBOL AFTER |
|
Page créée en 445 millisecondes et consultée 5636 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. |