CODINGCLASSEURS WEKA ★ Comment exploiterr toutes les ressources et augmenter les performances de votre AMSTRAD CPC ★

4/2.5.1 Initiation au langage machine - IV. Vos outils de programmationCoding Classeurs Weka

4/2 - Assembleur Z80 : Définitions et rappels de base

4/2.5 - Cours de programmation

4/2.5.1 Initiation au langage machine

IV. Vos outils de programmation

Le microprocesseur Z 80 offre tant de possibilités que ce n est qu après plusieurs années de pratique que l'on peut prétendre en maîtriser vraiment la programmation.

Il est cependant possible de l'utiliser de façon déjà intéressante en se limitant à une partie seulement de ses fonctions.

Le tableau suivant rassemble une sélection de trente instructions, choisies en fonction de leur similitude avec le Basic. Nous vous conseillons de les utiliser en priorité dans l'écriture de vos premières routines personnelles. 

 
Table des 30 instructions machine « préférentielles »
MnémoniqueCodeEquivalent Basic

ADD A,B
ADD A,N
CALL NN
CALL NZ,NN 
CALL Z,NN
CP B
CP N
DEC A
DEC B
IN A,(N)
INC A 
INC B
JP NN
JP NZ,NN
JP Z,NN
LD A,B
LD A,N
LD A,(NN)
LD B,A
LD B,N
LD (NN),A
NOP
OUT(N),A 
RET
RET NZ
RET Z
SBC A,B
SBC A,N
SUB B
SUB N

128
198
205
196
204
184
254
061
005
219
060
004
195
194
202
120
062
058
071
006
050
000
211
201
192
200
152
222
144
214

LET A = A + B
LET A = A + OMS
GOSUB (OMS + 256 x OPS)
IF Z = 0 THEN GOSUB (OMS + 256 x OPS)
IF Z = 1 THEN GOSUB (OMS + 256 x OPS)
IF B = A THEN LET Z - 1
IF A = N THEN LET Z = 1
LET A = A - 1
LET B = B - 1
IN (N)
LET A = A + 1
LET B = B + 1
GOTO (OMS + 256 x OPS)
IF Z= 0 THEN GOTO (OMS + 256 x OPS)
IF Z = 1 THEN GOTO (OMS + 256 x OPS)
LET A = B
LET A = OMS
LET A = PEEK (OMS + 256 x OPS)
LET B = A
LET B = OMS
POKE (OMS + 256 x POS),A
(REM)
OUT N,A
RETURN
IF Z = 0 THEN RETURN
IF Z = 1 THEN RETURN
LET A = A - B - Cy
LET A = A - OMS - Cy
LET A = A - B
LET A = A - OMS

OMS = octet le moins significatif (poids 1)          d'une valeur comprise entre 0 et 65535
OPS = octet le plus significatif (poids 256)        /

Cela ne vous empêche évidemment pas de recourir à des instructions plus spécifiques, mais il vous faudra alors faire l'effort de comprendre leur fonctionnement dans le détail, ce qui n'est pas toujours simple !

La partie 4, chapitre 2.3 est là pour vous y aider, ainsi que le tableau suivant qui donne la signification des principales abréviations entrant dans la composition de mnémoniques d'assemblage.

Pour incorporer dans un programme les instructions que vous aurez choisies, vous devrez vous reporter à une table des codes opératoires donnant les octets à utiliser pour représenter, en mémoire, chaque instruction.
Signification des abréviations utilisées dans les mnémoniques
AbréviationSignificationEquivalence Basic
ADC
ADD
AND
BIT
CALL
CP
CC
DAA
DEC
DI
DJNZ
EI
EX
EXX
HALT
IM
IN
INC
IND
INI
JP ou JR
LD
LDD
LDI
NEG
NOP
OR
OTD
OTI
OUT
OUTD
OUTI
POP
PUSH
RES
RET
RL
RR
RST
SBC
SCF
SET
SLA
SRA
SRL
SUB
XOR
Addition avec retenue
Addition sans retenue
ET logique bit à bit
Lecture d'un bit spécifié d'un octet donné
Appel sous-programme
Comparaison
Complémentation
Conversion en BCD
Décrémentation
Annulation interruptions
Décrémenter B et brancher si B = 0
Autorisation interruptions
Echanger deux opérandes
Echange complexe
Arrêt machine
Choix mode interruption
Entrée par port
Incrémentation
Entrée + décrémentation
Entrée + incrémentation
Branchement
Chargement
Chargement + décrémentation
Chargement + incrémentation
Complémentation à 2
Pas d'opération
OU logique bit à bit
Sortie + décrémentation
Sortie + incrémentation
Sortie sur port
Sortie + décrémentation
Sortie + incrémentation
Récupérer données pile
Entrer données pile
Mettre bit spécifié à 0
Retour au prog principal
Permutation de bits à gauche
Permutation de bits à droite
Repartir à adresse spécifiée
Soustraction avec retenue
Forcer la retenue à 1
Mettre à 1 bit spécifié
Décalage de bits à gauche
Décalage de bits à droite
Décalage de bits à droite
Soustraction sans retenue
OU exclusif bit à bit
+
+
AND
spécial
GOSUB
IF-THEN
spécial
spécial
LET L = L - 1
spécial
LET B = B - 1 et GOTO
spécial
double LET
spécial
STOP
spécial
IN
LET L = L + 1
spécial
spécial
GOTO
LET
spécial
spécial
spécial
(REM)
OR
spécial
spécial
OUT
spécial
spécial
spécial
spécial
spécial (LET)
RETURN
spécial
spécial
spécial (RUN)
-
spécial (LET)
spécial (LET)
spécial
spécial
spécial
-
spécial

Les premières lettres des mnémoniques des instructions Z 80 sont l'abréviation de mots anglais décrivant la fonction réalisée. Il suffit d'en connaître la signification, ainsi que les conventions de notation des opérandes (registres, cellules mémoire, ports) pour comprendre l'essentiel du fonctionnement de l'instruction. Pour les détails, il faudra bien sûr consulter le recueil complet des instructions Z 80 (chapitre 4/2.3 de cet ouvrage).
AbréviationSignification

( )
A
B
C
D
E
H
L
N

IX
IY
HL
BC
DE
SP
d

NN
Z
NZ
C
NC
M
P
AF
AF'
NC
P0
PE
0
...
7
10H
18H
20H
28H
30H
38H
8
( )
'

Cellule mémoire dont l'adresse est stockée, sous la forme OMS OPS, dans les deux registres ou les deux nombres mentionnés entre les parenthèses
Registre A (accumulateur)
Registre B
Registre C
Registre D
Registre E
Registre H
Registre L
Valeur numérique (octet) contenue dans l'instruction après le code opératoire

Registre d'index IX (à deux octets)
Registre d'index IY (à deux octets)
Paire de registres H et L utilisés ensemble
Paire de registres B et C utilisés ensemble
Paire de registres D et E utilisés ensemble
Registre SP (pointeur de pile)
Déplacement (quantité contenue, sous forme d'un octet, dans une instruction et intervenant selon des modalités diverses, dans le calcul d'une adresse (à étudier cas par cas).

Paire de valeurs numériques (2 octets OMS et OPS)
Si drapeau Z à 1 (résultat nul ou égalité)
Si drapeau Z à 0 (résultat 0 ou inégalité)
Si drapeau C à 1 (retenue)
Si drapeau C à 0 (pas de retenue)
Si drapeau S à 1 (résultat négatif)
Si drapeau S à 0 (résultat positif)
Paire de registres A et F
Paire de reaistres A' et F'
Si drapeau C à 0 (pas de retenue)
Si drapeau P à 0 (résultat pair ou pas de dépassement)
Si drapeau P à 1 (résultat impair ou dépassement)
Bit N° 0 de l'octet spécifié (registre)
Bit N° 7 de l'octet spécifié (registre)
Adresse 16 (après RST)
Adresse 24
Adresse 32
Adresse 40
Adresse 48
Adresse 56
Adresse 8
Numéro d'un port d'entrée-sortie
Indique un registre du second groupe

Ces abréviations sont employées dans la suite des mnémoniques pour en préciser le sens, ou pour désigner les opérandes (registres ou cellules mémoire sur lesquels agit l'instruction).

 

Une telle table existe en annexe 2 (partie 11 ), un classement alphabétique facilitant la recherche d'après les mnémoniques.

Les codes opératoires y sont cependant présentés en hexadécimal, forme universellement adoptée par les programmeurs avertis mais qui risque de dérouter encore un peu plus le débutant en langage machine !

La table de conversion de la page suivante est donc là pour permettre d'opérer rapidement une conversion entre des octets exprimés en décimal ou en « hexa » : vérifiez par exemple que 124 en décimal correspond à 7C en hexa, et vice-versa.

Une petite table annexe permet les conversions entre « chiffres » hexa, et « nibbles » ou demi-octets de quatre bits : sachant que 7 correspond à 0111 et C à 1100, on déduit immédiatement que 7C (ou 124) vaut 01111100 en binaire !

Si vous décidez de travailler en décimal, vous devrez calculer la valeur des 2 octets représentant l'adresse. Prenons l'exemple de l'adresse 40000 : cherchez le multiple de 256 immédiatement inférieur à 40000, soit 39936 = 156 x 256. Soustrayez 39936 à 40000, ce qui donne 64: codée sur deux octets, l'adresse 40000 se compose donc de 64 (octet le moins significatif, de « poids » 1) et de 156 (octet le plus significatif, de « poids » 256).

Convertis en hexadécimal, ces deux octets s'écrivent respectivement 40 et 9C, ce qui permet d'écrire l'adresse 40000 sous la forme hexadécimale 9C40.

Table de conversion décimal - hexadécimal

L'adresse suivante, 40001 en décimal, s'écrirait donc 9D40 en hexadécimal : à vous de choisir ce qui vous semble le plus pratique, mais vous viendrez sûrement tôt ou tard à l'hexa !

Un autre exemple :

Le programme suivant est un autre exemple de la facilité avec laquelle un programme Basic peut faire exécuter une tâche par une routine écrite en langage machine et incorporée dans son listing.

Il s'agit d'un petit logiciel de codage et décodage de messages secrets, très simplifié mais dont le principe est intéressant à étudier car il peut être largement extrapolé.

Un texte est entré en machine sous la forme d'une chaîne m$: chaque caractère de cette chaîne est représenté en mémoire par un octet, c'est-à-dire huit bits. L'idée consiste à modifier la position de ces bits dans l'octet grâce à une « permutation circulaire ». Une telle opération serait extrêmement lourde et lente en Basic, mais ne pose aucun problème en assembleur, des instructions machine existant tout spécialement à cet effet.

3 REM MESSAGES
10 MEMORY 39999
20 DATA 62,0,15,50,65,156,201
30 FOR a=40000 TO 40006
40 READ d
50 POKE a,d
60 NEXT a
100 INPUT m$
110 FOR f=1 TO LEN(m$)
120 c$=MID$(m$,f,1)
130 c=ASC(c$)
140 POKE 40001,c
150 CALL 40000
160 c=PEEK(40001)
170 PRINT c;*;";
180 NEXT f
190 PRINT
200 m$=""
210 POKE 40002,7
220 INPUT c
230 IF c=0 THEN 290
240 POKE 40001,c
250 CALL 40000
260 c=PEEK(40001)
270 m$=m$+CHR$(c)
230 GOTO 220
290 PRINT m$
300 REM (c)1988 Patrick GUEULLE

Les lignes 10 à 60 installent en mémoire la routine détaillée qui se limite à sept octets !

           40000 LD A,0 62 0
           40002  RRC A 15 (codage)
           40003  LD 40001,A 50 65 156
           40006  RET 201

variante : 40002 RLC A 7 (décodage)

Avant de la lancer par un CALL 40000, on POKE à l'adresse 40001 (c'est-à-dire à la place du 2éro d'origine) l'octet qu'il s'agit de transformer.

L'instruction machine de l'adresse 40000 charge donc cet octet dans l'accumulateur du Z 80, et l'instruction suivante, RRC A, effectue une rotation à droite de ses bits. Vous avez compris qu'au décodage, il faudra faire l'inverse c'est-à-dire une rotation à gauche par l'instruction RLC A (rotate left circular A).

En 40003, on recharge le résultat contenu dans A à l'adresse 40001, puis on revient au Basic. Celui-ci va alors chercher le résultat du traitement à l'adresse 40001 par un PEEK.

Chaque caractère de m$ est traité de ta sorte, et il s'affiche une liste de valeurs inférieures à 256 qui forment le message codé proprement dit.

Après avoir été noté et éventuellement transmis par tout moyen approprié, le message peut être décodé grâce aux lignes 200 à 300 : en chargeant un 7 à la place du 15 à l'adresse 40002, le POKE de la ligne 210 transforme la routine de codage en une routine de décodage !

Il est donc bien sûr nécessaire que la routine de codage soit présente en mémoire, c'est-à-dire que les lignes 10 à 190 aient été exécutées au moins une fois, même « à vide ».

La liste de codes peut alors être frappée octet par octet, et sera traduite au fur et à mesure, le texte décodé étant stocké dans m$, préalablement vidée. Il suffira de donner la valeur zéro au dernier octet de la liste pour que le texte décodé s'affiche à l'écran.

Pour améliorer la sécurité de ce codage finalement assez naïf, on pourrait songer à effectuer des rotations tantôt à droite et tantôt à gauche, dans un ordre fixé par une liste incluse dans les programmes de codage comme de décodage, et qui serait la « clef du code », à changer évidemment assez fréquemment...

★ NOTE: 9e Complément

Page précédente : 4/2.5.1 Initiation au langage machine - III. Un programme machine plus utile

CPCrulez[Content Management System] v8.7-desktop/cache
Page créée en 097 millisecondes et consultée 65 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.