CPC-POWER : CPC-SOFTS - CPCArchives 
Options de Recherche :
 
 
 

ARTICLES

40 / 74

Initiation à l'assembleur

Initiation
à
l'assembleur

 

Vous êtes fatigué d'attendre devant votre écran le résultat d'un tri ; la torpille nucléaire de votre dernière réalisation de jeu d'arcade se déplace à la vitesse foudroyante d'un escargot rhumatisant ; vous êtes excédé par la lenteur du Basic et l'absence de fonctions performantes...

Alors, pas de doute, vous êtes candidat à l'étude de l'assembleur. Il est évident que pour aborder cette matière, de bonnes notions de Basic et d'architecture interne de l'ordinateur sont nécessaires. Les notions de variable, de boucle, de saut ou de tableau (DIM) ne doivent pas être étrangères au candidat à l'étude de l'assembleur. Les prodiges réalisés par la programmation en assembleur valent largement l'effort consenti pour apprendre ce langage.

 

L'assembleur est considérablement plus complexe que le Basic. Par contre, il vous permet le contrôle total de votre système avec une flexibilité inégalée dans la manipulation des données, une vitesse d'exécution accrue, une réduction de la taille de certains programmes et enfin, la satisfaction de pouvoir dire à vos amis : non, ce n'est pas du Basic, je l'ai écris moi-même en assembleur.

 

Généralités

La démarche permettant d'écrire un programme en Assembleur est fondamentalement différente de celle entreprise en vue de réaliser un programme Basic. Dans votre micro-ordinateur, le langage Basic est dit : INTERPRETE.
Cela signifie que les lignes de programmes sont lues, analysées, transformées en code machine et exécutées les unes après les autres. Elles sont successivement interprêtées par la machine grâce à un programme interne appelé "interprêteur Basic". Pour travailler en Basic, il suffit donc d'écrire un programme dans la mémoire centrale et de donner l'ordre "RUN" à l'ordinateur.

Pour l'assembleur, les choses ne sont pas aussi simples. En effet, l'assembleur n'est pas un langage interprêté mais bien un langage compilé. Avant de lancer l'exécution d'un programme assembleur, il faut le compiler. Cette opération consiste à traduire l'entier du programme en code machine. Le résultat de la traduction en code machine devient un programme exécutable autant de fois que l'utilisateur le désire et appelé programme objet. Le programme écrit en langage assembleur et non encore compilé s'appelle programme source.

Le programme objet est uniquement composé d'une suite de codes machine et il est pratiquement impossible à déchiffrer. Par contre, le programme source peut être relu et modifié sans problèmes. Il suffira de recompiler ce dernier après modifications afin de créer un nouveau programme objet exécutable.

Pour écrire un programme source, on utilise un éditeur. Ensuite, il suffit de compiler le programme source à l'aide de l'assembleur afin d'obtenir le programme objet. Ces deux programmes (l'éditeur et l'assembleur) font souvent partie d'un même logiciel appelé éditeur-assembleur.

Il ne faut donc pas confondre le langage assembleur avec le programme permettant la compilation du programme source, également appelé assembleur.
 

 

 

Introduction

Pour commencer, examinons la démarche à suivre à l'aide d'un exemple simple : soit l'instruction Basic Z = B + C.
Pour l'écrire en assembleur, il sera nécessaire de :

  1. Pointer la valeur de B et la placer dans l'accumulateur. L'accumulateur constitue l'endroit privilégié de traitement de votre microprocesseur. On peut le considérer comme un "tiroir" dans lequel on dépose les objets à traiter.
  2. Positionner un pointeur sur la variable C.
  3. Additionner au contenu de l'accumulateur le contenu de l'endroit pointé (C).
  4. Sauver le nouveau contenu de l'accumulateur à l'adresse devant contenir la variable Z.

 

La lecture de ces quelques lignes montre à quel point le langage assembleur est proche de la fonction primaire de l'ordinateur. En effet, les différentes actions permises par ce langage sont élémentaires. C'est en ayant la possibilité de réaliser ses applications au niveau élémentaire que le programmeur pourra obtenir de sa machine les performances désirées et impossibles en Basic. Le petit exemple ci-dessus souffre d'ailleurs de grosses restrictions. En effet, si la précision de l'opération Basic Z=B+C ne dépend que du type de variable (entière ou flottante), en assembleur, le programme décrit ne fonctionne que pour des variables Z, B et C dont les valeurs sont comprises entre 0 et 255.

 

Chaque instruction décrite en langage assembleur est traduite en langage machine par un utilitaire spécialisé appelé ASSEMBLEUR. En langage machine, chaque instruction est composée d'une suite de 0 et de 1. Par exemple : 00111110. Si cette suite prend tout son sens pour un ordinateur, il faut avouer qu'elle n'est pas évidente pour le cerveau humain qui préfère globaliser les concepts sous forme de mots. C'est la raison d'être du langage assembleur. En effet, il permet au programmeur de remplacer les différentes instructions élémentaires par des abréviations. Ces abréviations portent le nom de mnémoniques.
 

Hélas, les premiers concepteurs de ce langage étant anglo-saxons, c'est dans cette langue que les mnémoniques ont été écrites. Par exemple, CHARGER se dit LOAD en anglais ; le mnémonique correspondant sera donc LD.
 

Pour terminer les généralités, rappelons que chaque ordinateur est équipé d'un coeur, c'est-à-dire d'un organe de calcul et de traitement. Ce dernier est constitué d'un circuit appelé microprocesseur.

Le microprocesseur est un composant électronique muni de 40 "pattes". Il se présente sous la forme d'un petit parallèlépidède rectangle très plat de 6 centimètres sur 2.

 

De nombreux types de microprocesseurs existent présentant chacun divers avantages et inconvénients. Le langage Assembleur étant très proche du microprocesseur, il sera différent suivant le type de microprocesseur utilisé. Celui que nous vous proposons d'étudier s'appelle Z80. Il équipe des ordinateurs aussi divers que l'AMSTRAD, les MSX, les TRS-80 de chez TANDY... C'est l'un des processeurs les plus célèbres et malgré son grand âge (8 ans), il est considéré comme l'un des meilleurs processeurs de sa catégorie.
 

Le Z80 est un microproceseur dit de 8 bits. Cela signifie qu'il est capable de traiter 8 états 0 ou 1 simultanément.
Une confusion règne dans les esprits même les plus éclairés depuis l'apparition des microprocesseur 16 bits.
Pour simplifer les choses, il faut savoir qu'il existe trois critères permettant de classifier les différents types de microprocesseur :

  1. Le nombre de bits de données que le microprocesseur est capable de lire simultanément;
  2. Le nombre de bits que le microprocesseur est capable de traiter simultanément;
  3. Le nombre de bits permettant d'adresser un endroit quelconque situé dans l'espace mémoire.


Le Z80 est un microprocesseur capable de lire et de traiter simultanément 8 bits de données (1 et 2).
Il est équipé d'un bus d'adresse de 16 bits permettant d'adresser 65536 emplacements mémoire différents (16 états 0 ou 1 permettant 65536 possibilités).

 

Et les variables ?

En assembleur, il n'exise pas d'identificateur de variable. En Basic, ou dans tout autre langage évolué, chaque variable porte un nom qui permet de retrouver son contenu. Le langage évolué s'occupe de placer le contenu de la variable à un emplacement mémoire et d'aller le récupèrer lorsque cela est nécessaire.

Considérons le programme Basic suivant:
10 A=4
20 B=5
30 C=A+B
40 PRINT C

 

En Basic, les différents emplacements mémoire où sont stockés les contenus des variables A, B et C ainsi que l'endroit où s'affectue l'addition n'ont aucune importance pour le programmeur. En Assembleur, ils sont au contraire très importants. En effet, l'assembleur n'utilise pas des variables. Les différentes valeurs utilisées par le programme doivent être écrites directement aux adresses mémoire adéquates. Autrement dit, tout doit être parfaitement localisé puisqu'on travaille directement dans la mémoire.


Quant au microprocesseur, il possède sa propre petite mémoire interne.
Les différents emplacements de sa mémoire interne portent le nom de registres et sont identifiées chacun par une lettre.
Ils servent à contenir les données sur lesquelles le programmeur désire effectuer différentes opérations et à effectuer ces dernières.


Le diagramme suivant représente les différents registres du Z80 :

 

Le registre A constitue la réponse à la question " Où l'addition a-t-elle lieu ? ". En effet, le registre A, appelé accumulateur, contient toujours une des deux opérandes dans les instructions d'addition, de soustraction, de fonction logique... Le résultat de l'opération effectuée se retrouve toujours dans ce registre.

Le registre F, ou FLAG (FLAG signifie drapeau en anglais), est un registre particulier où sont mémorisés les indicateurs de dépassement de capacité, de valeur 0, de valeur négative... Les autres registres sont généralement utilisés comme pointeurs vers les différentes adresses de la mémoire utilisées.

Remarque : Les registres B, C, D, E, H et L sont des registres 8 bits. Or, le bus d'adresse du Z80 est consituté de 16 bits. Un seul de ces registres ne peut donc suffire à adresses dictinctement un emplacement mémoire. Ils sont donc couplés pour former les trois registres de 16 bits suivants : BC, DE et HL.

Les registres PC et SP sont deux registres de 16 bits. Le PC, ou Program Counter (compteur de programme), pointe toujours vers une adresse mémoire. Cette adresse contient une indication permettant de connaître l'endroit précis où se déroule le programme à l'instant t. Le PC contient donc une adresse qui fonctionne de façon similaire au pointeur de la ligne Basic en cours d'exécution. le SP, ou Stack Pointer (pointeur de pile), est un registre très important. Il contient l'adresse de la pile (stack). Le programmeur peut positionner la pile là où il le désire mais il a tout intérêt à la disposer en haut de la mémoire.

A présent, voyons à quoi sert cette pile et ce qu'elle peut bien contenir:

Une pile (du verbe empiler, comparez à une pile d'assiettes) constitue une collection d'objets où des ajouts et des retraits peuvent être effectués. Il existe deux sorties de piles : la pile LIFO et la pile FIFO.

LIFO : de l'anglais Last In First Out, signifie "dernier entré, premier sorti". Cette pile peut se comparer à une pile d'assiettes. La dernière assiette ajoutée à la pile sera la première que l'on prendra lorsqu'un retrait sera nécessaire.

FIFO : de l'anglais First In First Out, signifie "premier entré, premier sorti". La meilleur comparaison pour cette pile est l'appareil qui tombe le premier dans les mains de l'acheteur.

La pile du Z80 est une pile LIFO. Seul son sommet est accessible (pour prendre la troisième assiette, il faut d'abord enlever les deux premières). Les autres registres sont plus particuliers et ne seront pas abordés au cours de ce premier article.
 

La syntaxe et la notation

En Basic, lorsque nous décrivons une variable, nous parlons de son contenu. L'endroit où elle est stockée n'a aucune importance puisqu'elle a un nom. Lorsqu'on donne le nom d'une variable Basic, c'est donc bien pour utiliser son contenu.

En assembleur, les variables n'ont pas de nom. Elles sont connues uniquement par leur adresse. Il faut donc faire la disctinction entre une adresse et la valeur qui s'y trouve stockée. Si ADR représente une adresse, nous indiquerons ADR pour parler de l'adresse et (ADR) pour parler de son contenu. Rappelons ici que ADR est un nombre 16 bits et que (ADR) est un nombre de 8 bits.

Pour le microprocesseur, une instruction est une suite de bits appelée code opératoire. Les valeurs des suites de bits représentant les différents codes opératoires sont généralement représentées en notation hexadécimale. Comme le cerveau humain n'aime pas beaucoup manipuler des chiffres, les codes opératoires seront représentés par des mnémoniques correspondant aux notations hexadécimales.

Pour chacune des instructions que nous allons décrire, nous donnerons le code opératoire en hexadécimal, la mnémonique (ou opérateur) correspondante et le format des ... Par convention, A, B, C, D, E, H, L et SP identifient les registres correspondants du microprocesseur ; adr signifie adresse ; (adr) identifie le contenu de l'adresse adr ; r signifie registre ; n signifie constante sur 8 bits ; (r) indique le contenu de l'adresse contenue dans le registre r.

 

Les instructions de base

Le microprocesseur peut recopier le contenu d'une de ses mémoires internes (registre) dans un autre. Cette opération s'appelle une copie de registre à registre. Le format général de cette opération est le suivant:

LD r, r'

où LD est la mnémonique ou opérateur et r et r', les opérandes.
r et r' peivent être n'importe quel registre parmi A, B, C, D, E, H et L.

L'instruction LD (load en anglais signifie charger) copie le contenu du registre r' dans le registre r. Chaque combinaison de l'instruction LD avec deux registres possède son propre code opératoire. Le code opératoire est consituté d'un simple octet (8 bits) représenté par une valeur hexadécimale à deux chiffres.

Le tableau suivant donne la liste des différents codes opératoires pour l'instruction LD:

   B  C  D  E  H  L    A
 B 40 41 42 43 44 45   47
 C 48 49 4A 4B 4C 4D   4F
 D 50 51 52 53 54 55   57
 E 58 59 5A 5B 5C 5D   5F
 H 60 61 62 63 64 65   67
 L 68 69 6A 6B 6C 6D   6F
                 
 A 78 79 7A 7B 7C 7D   7F

En observant ce tableau, nous constatons que les codes opératoires suivent une logique évidente. Le trou entre L et A sera comblé par la suite. Il est évident que les instructions de type A,A; LD H,H ..., correspondant à la diagonale 40 à 7F, ne présentent aucun intérêt.


Par exemple : copier le contenu du registre H dans l'accumulateur A s'écrira :

LD A,H

L'assembleur fournira le code opératoire 7C.
Autre exemple : copier le contenu de la paire de registre BC dans la paire de registres DE s'écrira :

LD D,B
LD E,C

L'assembleur fournira la suite de codes opératoires 50, 59.

Il existe une méthode plus courante permettant le copier les registres. Elle utilise la pile. Il suffit de "pousser" le contenu du registre BC dans la pile et d'ensuite retirer le contenu de la pile dans DE. Cette technique sera expliquée par la suite.

Les différents emplacements mémoire contiennent des valeurs d'une taille de 8 bits. Ces valeurs peuvent être chargées de la mémoire vers un registre et vice-versa.

Les mouvements entre la mémoire et les registres sont très limités. Le registre HL est le plus utilisé pour ce type d'opération. En effet, le jeu d'instruction de HL est plus riche que ceux de BC et de DE. Bien entendu, par l'intermédiaire de HL, on peut charger le contenu d'une mémoire dans n'importe quel registre et vice versa.

Les instructions utilisées à cet effet sont les suivantes:

LD r, (HL)
et
LD (HL), r

où r représente n'importe quel registre 8 bits (A, B, C, D, E, H et L).

Les codes opératoires correspondants sont fournis par le tableau suivant :

  B C D E H L A
r,(HL) 46 4E 56 5E 66 6E 7E
 (HL),r 70 71 72 73 74 75 77

Vous pouvez, à l'aide de ce tableau, compléter le trou du précédent.

Seule la case de croisement correspondant à :

LD (HL), (HL)

n'a pas été décrite. Son code opératoire est 76. Au lieu de recopier le contenu de l'adresse pointée par HL sur lui-même, le code opératoire 76 arrête le microprocesseur (HALT).

D'autres méthodes sont permises pour effectuer des mouvements entre l'accumulateur et la mémoire :

1) Mouvement entre A et un emplacement mémoire dont l'adresse est contenue dans une des paires de registres BC ou DE.

 Syntaxe code opératoire
 LD A,(BC) 0A
 LD A,(DE)  1A
 LD (BC),A 02
 LD (DE),A 12

 

2) Mouvement entre A et un emplacement mémoire indiqué par une adresse en clair :

 Syntaxe code opératoire
 LD A,(adr) 3A VW XY
 LD (adr),A  32 VW XY

 

où VW et XY sont les valeurs hexadécimales représentant l'adresse réelle de la mémoire avec la convention suivante:
VW représente l'octet de poids faible de l'adresse mémoire et XY représente l'octet de poids fort.

Exemple : LD A, (3B4C) charge dans l'accumulateur le contenu de la mémoire 3B4C et produit comme code opératoire 3A 4C 3B.

Cette inversion entre le poids fort et le poids faible de l'adresse à l'intérieur du code opératoire se retrouvera dans toutes les instructions portant sur une adresse directe mémoire.
 

Les chargements immédiats

Il est évident qu'il est indispensable de pouvoir charger une constante directement dans l'accumulateur ou dans un registre 8 bits ainsi que de pouvoir charger une adresse directement dans une paire de registres (BC, DE et HL).

Syntaxe code opératoire
LD r,n voir tableau
LD (HL),n 36 n
LD HL,adr 21 VW XY
LD DE,adr  11 VW XY
LD BC,adr  01 VW XY

 

  B C D E H L A
LD r,n 06 n 0E n 16 n 1E n 26 n 2E n 3E n

 

Remarque: pour toutes les instructions vues jusqu'à présent, une seule mnémonique a été utilisée : LD. D'autres possibilités existent pour charger des registres de 16 bits ou pour la technique du chargement indexé. Elles dépassent le cadre de cet article.

En voici la syntaxe et les codes opératoires :

syntaxe des instructions indexées :
1- LD r,(IX+n)
2- LD r,(IY+n)
3- LD (IX+n),r
4- LD (IY+n),r

code opératoire :

  B C D E H L A
 1- DD 46 n DD 4E n DD 56 n DD 5E n DD 66 n DD 6E n DD 7E n
 2- FD 46 n FD 4E n FD 56 n FD 5E n FD 66 n FD 6E n FD 7E n
 3- DD 70 n DD 71 n DD 72 n DD 73 n DD 74 n DD 75 n DD 77 n
 4- FD 70 n FD 71 n FD 72 n FD 73 n FD 74 n FD 75 n FD 77 n

 

Instructions
16 bits

codes
opératoires
LD SP,HL F9
LD SP,IY DD F9
LD SP,IX FD F9
LD HL,(adr) 2A VW XY
LD (adr),HL 22 VW XY
LD BC,(adr) ED 4B VW XY
LD (adr),BC ED 43 VW XY
LD DE,(adr) ED 5B VW XY
LD (adr),DE ED 53 VW XY
LD SP,(adr) ED 7B VW XY
LD (adr),SP ED 73 VW XY
LD IX,(adr) DD 2A VW XY
LD (adr),IX DD 2A VW XY
LD IY,(adr) FD 2A VW XY
LD (adr),IY FD 22 VW XY

 

Les instructions de manipulation de pile

Pour manipuler la pile, deux instructions sont à notre disposition :

PUSH : permet de pousser une paire de registres dans la pile,

POP : permet de pousser le sommet de la pile dans une paire de registres.

A la suite d'un PUSH ou d'un POP, l'adresse de la pile contenue dans le registre SP est respectivement décrémentée ou incrémentée de deux octets. En effet, la pile se trouvant en haut de mémoire, chaque fois qu'on y ajoute quelque chose (PUSH), son adresse de début diminue.

  AF BC DE HL IX IY
PUSH F5 C5 D5 E5 DD E5 FD E5
 POP F1 C1 D1 E1 DD E1 FD E1

 

Comme nous l'avons laissé entrevoir précédemment, pour copier le contenu de BC dans DE, on peut remplacer :

LD D, B
LD E, C

par :

PUSH BC
POP DE

 

Pour terminer la liste des instructions portant sur les adresses et le chargement, voyons l'instruction permettant de permuter les contenus de certains registres : EX.

 

syntaxe code opératoire
EX DE,HL EB
EX (SP),HL E3
EX (SP),IX DD E3
EX (SP),IY FD E3

 

 

EXERCICES

1) Ecrivez le programme assembleur qui échange les contenus de B et C. Donnez les codes opératoires correspondants.

2) Si le contenu de la mémoire est le suivant:

adresse contenu
8036 00
8037 08
8038 10
8039 18
803A 20
803B 28
803C 30
803D 38
803E 40
803F 48

a) que contiendra l'accumulateur après la séquence suivante:

LD HL,803D

LD L,(HL)

LD A, (HL)

b) écrivez le programme objet correspondant (codes opératoires).

La solution des exercices se trouve en fin d'article.

 

 

Instructions arithmétiques et logiques

Après avoir examiné les différentes instructions de manipulation de données, voyons à présent les principales instructions arithmétiques et logiques.

Ces opérations portent toujours sur l'accumulateur et un autre registre ou une constante.

L'opérande sera symbolisé par op. Elle peut prendre les formes suivantes:

  • Un des registres A, B, C, D, E, H, ou L.
  • Une constante n.
  • Le contenu de la mémoire pointée par HL -> (HL).
  • Un adressage indexé par rapport à IX/IY -> (IX+n) / (IY+n).

Il est très important d'analyser l'effet de ces instructions sur le registre F. Le registre F contient 5 bits importants. Ils sont identifiés par une lettre:

  • C = bit de report (Carry).
  • Z = bit de Zéro.
  • V = bit de dépassement (oVerflow).
  • S = bit de Signe.
  • P = bit de Parité (nombre de bits à 1 pair ou impair).

 

Addition sans report (retenue)

Syntaxe : ADD A, op

Codes opératoires:

B C D E H L (HL) A n (IX+n) (IY+n)
80 81 82 83 84 85 86 87 C6 n DD 86 n FD 86 n

 Après l'exécution de l'instruction, A contient la somme de l'ancienne valeur de A et du contenu de l'opérande spécifiée.

 

Addition avec report (retenue)

Syntaxe : ADC A, op

Codes opératoires:

B C D E H L (HL) A n (IX+n) (IY+n)
88 89 8A 8B 8C 8D 8E 8F CE n DD 8E n FD 8E n

Après cette instruction, le contenu de A vaut la somme de l'ancien contenu de A, du contenu de l'opérande spécifiée et du bit de report de l'opération précédente s'il y en a un.

Dans les deux instructions précédentes, les indicateurs C, Z, V et S sont positionnés en fonction du résultat de l'opération.

 

Soustraction avec et sans report

La soustraction fonctionne selon le même principe que l'addition.

Syntaxe :

  • SUB op (soustraction sans report)
  • SBC A, op (avec report)

Codes opératoires:

  B C D E H L (HL) A n (IX+n) (IY+n)
 SUB 90 91 92 93 94 95 96 97 D6 n DD 96 n FD 96 n
 SBC 98 99 9A 9B 9C 9D 9E 9F DE n DD 9E n FD 9E n

 

Remarque: La multiplication et la division ne font pas partie des instructions de base du Z80, elles doivent être simulées par une série d'additions ou de soustractions ou de manipulations de bits.

 

Les opérations logiques AND, OR et XOR

L'action de ces instructions qui portent sur l'accumulateur et une opérande identique à celles décrites pour l'addition est similaire à celles des fonctions BASIC correspondantes. Le résultat de l'opération se retrouve dans l'accumulateur.

Table de vérité:

A opérande AND OR XOR
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

 

Les indicateurs C, Z, P et S sont affectés par ces opérations. L'indicateur C est systèmatiquement remis à 0.

Syntaxe:

  • AND op
  • OR op
  • XOR op

Codes opératoires:

  B C D E H L (HL) A n (IX+n) (IY+n)
AND A0 A1 A2 A3 A4 A5 A6 A7 E6 n DD A6 n FD A6 n
XOR A8 A9 AA AB AC AD AE AF EE n DD AE n FD AE n
OR B0 B1 B2 B3 B4 B5 B6 B7 F6 n DD B6 n FD B6 n

 

L'instruction de comparaison

L'opération de comparaison est une simple soustraction mais l'accumulateur n'est pas modifié.

Si les 8 bits sont en format non signé, on a la table suivante:

relation Z C
A < op 0 1
A = op 1 0
A > op 0 0

Syntaxe : CP op

Codes opératoires:

B C D E H L (HL) A n (IX+n) (IY+n)
B8 B9 BA BB BC BD BE BF FE n DD BE n FD BE n

 

Il existe d'autres opérations arithmétiques et logiques. En voici une brève description:

  • INCREMENTATION (ajouter 1) : INC
  • DECREMENTATION (soustraire 1) : DEC
  B C D E H L (HL) A (IX+n) (IY+n)
INC 04 0C 14 1C 24 2C 34 3C DD 34 n FD 34 n
DEC 05 0D 15 1D 25 2D 35 3D DD 35 n FD 35 n

 

  • Complémentation de l'accumulateur (inversion des bits) :
    • CPL ED 44
  • Complémentation et mise à 1 de l'indicateur de report (CARRY): 
    • CCF (clear carry flag) 3F
    • SCF (set carry flag)37
  • Instruction sans effet : NOP 00
  • On trouve également des instructions d'addition, d'incrémentation et décrémentation entre les registres 16 bits:

 

  BC DE HL SP IX IY
 ADD HL, 09 19 29 39 - -
 INC 03 13 23 33 DD 23 FD 23
 DEC 0B 1B 2B 3B DD 2B FD 2B

 

 

EXERCICES

Si la mémoire contient :

adresse contenu
8000 12
8001 24
8002 28

Ecrire un programme qui sauve à l'adresse 8003 la somme des contenus des deux premières mémoires (8000 et 8001) moins le contenu de la troisième. Utiliser HL pour pointer sur la mémoire.

Ensuite, écrivez le code objet produit par le programme.

 

 

Sauts et sous-routines

L'assembleur ne possède pas d'instructions équivalente au IF...THEN...ELSE et au FOR...NEXT du Basic. il est par contre doté d'instructions équivalentes aux GOTO et GOSUB.

Un IF...THEN sera simulé en assembleur par une instruction de comparaison (CP) suivie d'une instruction de saut.

Une instruction FOR...NEXT sera simulée par une instruction d'incrémentation ou décrémentation suivie d'un test (CP) et d'un saut.

 

Les sauts

Il existe quatre types de saut. On distingue des sauts ABSOLUS et RELATIFS; CONDITIONNELS et INCONDITIONNELS.

1. Saut absolu inconditionnel

Syntaxe : JP adr

Code opératoire :  C3 VW XY

A la suite de l'instruction JP adr, le PC se retrouve à l'adresse adr. Le programme continuera donc à cette adresse.

 

2. Saut absolu conditionnel

  syntaxe code opératoire
 saut si non zéro JP NZ,adr C2 VW XY
saut si zéro  JP Z,adr CA VW XY
 saut si report  JP C,adr DA VW XY
 saut si non report  JP NC,adr D2 VW XY
 saut si négatif  JP M,adr FA VW XY
saut si positif  JP P,adr F2 VW XY
saut si parité paire  JP PE,adr EA VW XY
 saut si parité impaire  JP PO,adr E2 VW XY

 

3-4. Sauts relatifs conditionnels et inconditionnels

Au lieu d'indiquer une adresse de saut absolue, on peut indiquer un déplacement en nombre d'octets par rapport à la position courante du PC. Ce type d'opération est appelé saut relatif.

Les déplacements peuvent être compris entre 0 et 127 octets plus loin (00-7F) ou 1 et 128 octets avant la position courante du PC (FF à 80). Cela signifie que le huitième bit de l'octet indiquant le déplacement est un bit de signe.

Cette opération est l'une des plus fastidieuse à calculer à la main. C'est dans le calcul des déplacements que l'utilité d'un ASSEMBLEUR se fait sentir.

L'utilisateur d'un assembleur indique simplement l'endroit où il désire sauter par une étiquette (LABEL). Il fait alors figurer cette étiquette à la place de l'opérande. Ainsi un programme qui additionne les 10 premiers nombres d'une table pointée par HL s'écrira de la façon suivante:

  LD HL,TABLE
  LD B,10
SUITE: ADD A,(HL)
  INC HL
  DEC B
  JR NZ,SUITE
  .  
  .  
  .  

L'assemblage manuel se calculera comme suit:

  LD HL,TABLE 21 XX XX
  LD B,10 06 0A
SUITE: ADD A,(HL) 86
  INC HL 23
  DEC B 05
  JR NZ,SUITE 20 YY

 Le problème consiste à déterminer la valeur de YY. Après avoir rencontré l'octet 20 suivi de l'octet YY, le PC se trouve déjà à l'adresse suivante. Pour revenir à YY, il faut faire -1 et afin de pointer sur le 20, il faut faire -2 et ainsi de suite jusqu'à remonter à 86. Au total, cela fait -5. En binaire signé, -5 vaut FB.

JR NZ,SUITE sera traduit par 20 FB

Syntaxes des différents sauts relatifs avec leur code opératoire:

 JR déplacement 18 XX
 JR Z,déplacement 28 XX
 JR NZ,déplacement 20 XX

 JR C, déplacement

38 XX
 JR NC,déplacement 30 XX

 Le grand avantage des sauts relatifs par rapport aux sauts obsolus est que les programmes qui les utilisent sont indépendants de leur adresse d'implantation dans la mémoire.

 

Les sous-routines

La notion de sous-routines en assembleur est très proche de celle utilisée en Basic. L'appel d'une sous-routine et son retour peuvent être conditionnel ou inconditionnel.

APPEL

syntaxe   code opératoire
CALL adr   CD VW XY
CALL Z,adr   CC VW XY
CALL NZ,adr   C4 VW XY
CALL C,adr   DC VW XY
CALL NC,adr   D4 VW XY
CALL M,adr   FC VW XY
CALL P,adr   F4 VW XY
CALL PE,adr   EC VW XY
CALL PO,adr   E4 VW XY

RETOUR

syntaxe   code opératoire
RET   C9
RET Z   C8
RET NZ   C0
RET C   D8
RET NC   D0
RET M   F8
RET P   F0
RET PE   E8
RET PO   E0

Lors de l'appel d'une sous-routine, l'adresse de retour est pousée dans la PILE, la plus grand prudence s'impose donc lors de la manipulation de la pile (PUSH POP).

 

 

EXERCICES

Si l'adresse ADR contient une constante N et l'adresse ADR+1 contient une constante M, faite un programme qui appelle la sous-routine POSIT si N>M et NEGAT si N

 

 

En guise de conclusion provisoire

Les différentes notions vue jusqu'ici doivent vous permettre si pas d'écrire, au moins de comprendre les programmes simples écrits en assembleur.

Au cours de cet article, nous n'avons fait que découvrir le sommet de l'iceberg. Il reste encore un bon nombre d'instructions à étudier.

Pour bien programmer en assembleur, une bonne connaissance de l'EDITEUR/ASSEMBLEUR utilisé est indispensable.

Pour celui qui n'en possède pas encore et désire en faire l'acquisition prochainement, nous vous conseillons vivement l'achat de DEVPAC. En effet, il présente des caractéristiques exceptionnelles tout en étant d'une grande simplicité à utiliser.

Enfin, pour bien maîtriser l'assembleur, une connaissance parfaite du logiciel interne de votre ordinateur est indispensable. A ce propos, les ouvrages de la série "CLEFS POUR..." (PSI Editions) semblent particulièrement indiqués. Les ouvrages intitulés "LE LIVRE DU..." (BCM éditions, PSI diffusion) vous fourniront tous les renseignements concernant l'architecture interne de votre machine accompagnés de nombreux exemples de programmes assembleur abondamment commentés.

 

Amstrad Magazine N°3

 

Articles

Clefs pour Amstrad - 1. Système de base (Mémento P.S.I.)

Clefs pour Amstrad - 2. Système disque (Mémento P.S.I.)

le livre de l'Amstrad CPC464 - CPC664 (BCM 1985)

 

 

Solution des exercices

1) 

 79 LD A,C
 48 LD C,B
 47 LD B,A

 

2)

21 3D 80 LD HL,803D
6E LD L,(HL)
7E LD A,(HL)

Au départ, 803D contient 38. Après LD L,(HL), L contient aussi 38. Le contenu de HL devient donc 8038. LD A,(HL) a pour effet de mettre dans A le contenu de l'adresse pointée par HL, c'est-à-dire le contenu de l'adresse 8038 qui est 10.

 

3)

21 00 80 LD HL,8000
86 ADD A,(HL)
23 INC HL
86 ADD A,(HL)
23 INC HL
96 SUB (HL)
23 INC HL
77 LD (HL),A

 

4)

 

LD HL,ADR
LD A,(HL)
INC HL
CP (HL)
JP Z,ADR+2
CALL NC,POSIT
CALL NEGAT

 

 

Article créé le : Vendredi 31 Décembre 2010 à 09 h 41
Dernière mise à jour le : Mardi 28 Février 2012 à 21 h 30
 
 

CPC-POWER/CPCArchives, projet maintenu par Fredouille.
Programmation par Kukulcan © 2007-2024 tous droits réservés.
Reproduction sans autorisation interdite. Tous les titres utilisées appartiennent à leurs propriétaires respectifs.