CODINGAMSTRAD CPC 464 - CRÉER DE NOUVELLES INSTRUCTIONS

Nouvelles Instructions 003

LE LANGAGE MACHINE

COMMENT IMPLANTER UN PROGRAMME EN LANGAGE MACHINE

Nous allons nous servir, pour illustrer cette section, du programme proposé dans l'avant-propos, et qui colorait l'écran (cette fois, pourtant, nous n'y inclurons pas la possibilité de faire varier X).

10 MODE 1 : MEMORY 40000
20 FOR 1 = 40001 TO 40016 : READ A : POKE l,A : NEXT 30 CALL40001
40 DATA &21, &0, &40, &11, &FF, &BF, &3E, &FF, &13, &12, &2B, &7C, &B5, &20, &F7, &C9

La ligne 10, outre qu'elle initialise l'ordinateur en model, nous intéresse surtout parce qu'elle protège une zone de mémoire, à partir de l'adresse 40000.
La ligne 20 écrit le programme dans une zone de 16 octets :

1. La boucle démarre en 40001.

2. La première donnée stockée en DATA est écrite dans cette case mémoire.

3. La deuxième boucle commence : la deuxième donnée stockée en DATA est écrite en 40002, et ainsi de suite.

Une fois le programme écrit en mémoire, il ne reste plus qu'à l'appeler grâce à l'instruction CALL, suivie de son adresse (c'est-à-dire l'adresse de la première de ses instructions, en l'occurrence 40001). Deux remarques s'imposent :

• La longueur de la zone à protéger dépend bien évidemment de la longueur du programme à y implanter (dans notre cas, un MEMORY 43887 aurait pu suffire, puisque notre programme ne fait que 16 octets).
• Il n'est nécessaire et suffisant que d'exécuter le programme de chargement une seule fois. Lorsqu'il est chargé, on peut l'appeler grâce à CALL autant de fois que l'on veut.
Une petite astuce nous évitera dorénavant d'avoir à mettre le sigle & devant chacune des données de la ligne de DATA. Il suffit de remplacer la ligne 20 par :

20 FOR I = 40001 TO 40016 : READ A$ : POKE I, VAL("&H" + A$) : NEXT

Un dernier conseil enfin, avant de clore le sujet : vous vous rendrez vite compte que rien ne se produit plus facilement, lorsqu'un programme est assez long, qu'une ou deux erreurs lors de la copie des lignes de DATA. Or, les conséquences d'une erreur dans un programme en langage machine sont parfois lourdes (nous y reviendrons). C'est pourquoi la ligne suivante, insérée juste après la boucle de chargement, permet en principe de signaler ce genre d'erreur :

25 W = 0 : FOR l = Adresse de départ TO adresse de fin: W = W + PEEK(I): NEXT: IF W< > Vérification THEN PRINT "Erreur de data" : END

Pour l'exemple précédent, adresse de départ = 40001, adresse d'arrivée =40016, et vérification = 1742.
La valeur de vérification varie bien sûr selon le programme, elle sera donnée pour chacun de ceux que nous étudierons.

LES PARAMÈTRES TRANSMISSIBLES

Si l'instruction CALL ne pouvait être utilisée que sous la forme que nous avons vue précédemment, il est bien évident qu'elle serait d'un emploi très limité.
Imaginons par exemple que nous fabriquions une routine chargée de dessiner des carrés. Nous aimerions certainement pouvoir indiquer que nous voulons un carré dont les côtés auront telle ou telle longueur, et qui sera situé à tel endroit de l'écran.
L'instruction CALL permet de transmettre ce genre d'indications (paramètres) sous la forme suivante :

CALL adresse du programme, X, X1, X2, X3,...

On peut ainsi transmettre jusqu'à 32 paramètres I Reprenons l'exemple du carré. L'appel de la routine pourrait se présenter ainsi (ne pas oublier les virgules) :

CALL adresse, X, Y, L

X et Y seraient les coordonnées du coin supérieur gauche de notre carré, et L la longueur des côtés.

Ainsi donc, avec un seul programme, nous pourrions dessiner n'importe quel carré.
Il ne faut pas être sorcier pour en déduire que nous devrons, pour pouvoir utiliser ces paramètres, être capables de localiser l'endroit où ils sont rangés en mémoire. C'est à cela que nous servira le registre IX.
Considérons d'abord le cas le plus simple, l'instruction CALL suivie d'un seul paramètre :

CALL adresse, X

Précisons tout de suite que l'ordinateur va systématiquement réserver deux cases mémoire pour ranger chaque paramètre, au cas où ils seraient supérieurs à 255.

Notre paramètre X se présentera donc quelque part en mémoire sous la forme :

A ce propos, il est important de noter que, lorsqu'un nombre est écrit en mémoire, l'octet faible est toujours écrit avant le fort.
Pour en revenir à ce paramètre X, le problème est donc de savoir où il se trouve, en d'autres termes, de trouver son adresse A.
Ce problème est résolu facilement quand on sait que cette adresse est automatiquement chargée dans le registre IX au moment de l'appel du programme (on dit que IX est pointé sur A) :

Cela peut être formulé de différentes manières :

* Octet faible de X = contenu de la case mémoire dont l'adresse est dans IX (on dit "adressée par IX").
* Octet fort de X = contenu de la case mémoire adressée par IX + 1.

Ou encore :

* Octet faible de X = (IX) et octet fort de X = (IX + 1).

Comme il est obligatoire d'utiliser IX avec ce qu'il est convenu d'appeler un déplacement, nous écrirons (IX + 0) au lieu de (IX), ce qui revient exactement au même.
Voyons maintenant un cas plus complexe avec, par exemple, trois paramètres :

CALL adresse, X, X1, X2

Ils seront rangés en mémoire de la manière suivante :

On remarquera que le dernier paramètre est rangé le premier dans la mémoire.
Imaginons maintenant qu'au cours d'un programme nous voulions charger le paramètre X1 dans le registre HL. Il nous suffirait de charger (IX + 3) dans H et (IX + 2) dans L. Bien entendu, il existe des instructions pour cela.
Une bonne compréhension du processus étant importante, voici un exemple concret avec quatre paramètres :

CALL adresse, 300, 120, 5000, 0

(Rappelons que HEX$(300) = 12C, HEX$(120) = 78, HEX$(5000) = 1388 et que HEX$(0) = 0.)
Ces paramètres se présenteront ainsi en mémoire :

Si nous voulons par exemple charger le registre DE avec le troisième paramètre, en l'occurrence 5000 (&1388), il nous faut charger l'octet fort dans D et l'octet faible dans E :

(IX + 3) dans D et (IX + 2) dans E

Précisons enfin que le nombre de paramètres transmis est chargé, lui, dans le registre A (accumulateur) au moment de l'appel du programme. Nous verrons que cela peut être très utile.

LES PRÉCAUTIONS INDISPENSABLES

Le langage machine n'est pas d'un maniement aussi aisé que le BASIC, et si vous ne voulez pas être rapidement et à tout jamais découragé, vous ferez bien de tenir compte des conseils suivants :

* N'oubliez pas de protéger votre zone d'implantation grâce à l'instruction MEMORY. De plus, faites bien attention que votre programme ne "déborde" pas de l'adresse 43903. Évitez également d'implanter vos programmes dans des zones inférieures à 16384, cela vous épargnera des désagréments dont il serait trop long de parler ici.

* Enregistrez systématiquement vos programmes avant de les essayer.
Le langage machine réagit parfois extrêmement mal aux erreurs. Une seule petite faute, et vous risquez de voir le programme que vous avez mis deux heures à rentrer s'atomiser et se perdre définitivement dans les entrailles de la machine (en tout état de cause, et quoi que vous fassiez, sachez quand même que vous ne risquez en aucun cas de détraquer votre ordinateur).

Il arrive souvent, lorsqu'un programme se "plante", que rien ne se passe et que le clavier ne réagisse plus. Dites-vous bien qu'il s'agit toujours d'une erreur de conception (inutile d'accuser la machine, elle ne fait jamais d'erreur), et que l'ordinateur doit être branché sur une boucle malsaine dont il ne peut plus sortir. Dans ce cas-là, une seule solution : éteindre et rallumer.

* Tenez la pile sous haute surveillance. Comme il a été dit précédemment, la pile est souvent un moyen- commode pour stocker des données. Mais n'oubliez pas que l'ordinateur s'en sert également de son côté, et voici de quelle manière :

Nous avons déjà comparé l'instruction CALL à l'instruction GOSUB, la seule différence étant que la première appelle un sous-programme en langage machine, et la seconde un sous-programme en BASIC.
De la même manière qu'un sous-programme en BASIC doit toujours se terminer par un RETURN, un programme en langage machine doit toujours se terminer par une instruction de retour. Dès qu'une telle instruction est rencontrée, l'ordinateur quitte le langage machine et retourne exécuter l'instruction située immédiatement derrière l'instruction CALL, puis poursuit normalement le programme BASIC. Cela n'est possible que parce que, au moment où il a rencontré l'instruction CALL, il a stocké l'adresse de la suivante sur la pile, en prévision du retour.

Cette adresse, il s'attend donc à la retrouver sur la pile au moment du retour. Si un "tripotage" intempestif de la pile l'a entre-temps dénaturée sans la remettre en état, l'ordinateur récupérera une donnée fausse et le programme va sauter n'importe où. La règle d'or est donc: Au moment du retour d'un sous-programme en langage machine, la pile doit être dans le même état qu'au moment de l'appel de ce sous-programme.

Vous verrez que cette règle n'est pas très difficile à appliquer pour peu que l'on fasse preuve d'un minimum de rigueur et de minutie.

Lorsque j'utilise beaucoup la pile, je me sers pour ma part d'un petit "truc" aussi simple qu'efficace : je manipule physiquement une pile faite de petits cartons que j'entasse les uns sur les autres, ou au contraire que j'enlève de la pile en même temps que mon programme. Le premier carton à être systématiquement déposé est bien sûr intitulé "adresse de retour du programme". Quand le programme s'achève, c'est-à-dire au moment où l'instruction de retour au BASIC est rencontrée, il ne doit plus rester d'autre carton au-dessus de celui-là. Si c'est le cas, je rajoute, avant l'instruction de retour, les instructions nécessaires pour les faire disparaître.

Cette histoire de pile est réellement très importante. Combien de débutants se sont arraché les cheveux devant des programmes qui se plantaient, alors qu'il s'agissait tout simplement d'un problème de pile !
C'est sur ce dernier conseil que s'achèvent les deux premières parties. Vous en savez maintenant assez pour vous attaquer au premier programme.

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

Page précédente : Nouvelles Instructions 002
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/c
Page créée en 733 millisecondes et consultée 1323 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.