CODING ★ MICRONEWS - Z80 ASSEMBLEUR FACILE ★

Cours et initiation du Magazine Micro NewsMicro News n°12 : Z80 Assembleur Facile
Additionnons...

Tout un chacun connaît la formule que des générations d'écoliers ont anonnée : "Je pose n et je retiens 1".
On retrouve exactement le même mécanisme dans une addition en base 2, à cette nuance près que l'opération "je pose n et je retiens 1" intervient bien plus tôt, dès que la valeur 2 est atteinte. Essayons, si vous voulez bien.

111 valeur en base 10:7
+ 10 valeur en base 10:2
-----
1001 valeur en base 10:9

On peut décomposer :

0 + 1 = 1 je pose 1
1 + 1 = 2 je pose 0 et je retiens 1
1 + 1 = 2 je pose 0 et je retiens 1
1 + 0 = 1 je pose 1

Les choses se compliquent légèrement au niveau de l'accumulateur du Z80 puisqu'il ne dispose que de 8 positions binaires et n'autorise donc que 8 colonnes. Voyons tout de même, en nous plaçant d'emblée dans une condition bien particulière.

11111111 valeur en fasse 10:255
+ 1
-----------
00000000 résultat C

L'accumulateur n'ayant que 8 positions, il est impossible d'y loger la retenue, qui tombe en dehors. Fort heureusement, la retenue ne tombe pas n'importe où, mais aux pieds d'un sémaphore qu'elle active. Il s'agit de l'indicateur "C. Ce nouveau-venu se comporte un peu comme l'indicateur "Z" que nous connaissons déjà. Attention ! L'indicateur "C" n'a rien à voir avec le registre "C" que l'on trouve dans la paire BC. Le "C" qui nous occupe vient du mot "Carry", report. On dit généralement que le bit qui ne trouve pas à se loger dans l'accumulateur (ou ailleurs comme nous le verrons plus bas) tombe dans "Carry".

Que se passe-t-il si nous additionnons dans l'accumulateur deux valeurs telles que 75 + 250, par exemple? Nous trouverons dans l'accumulateur une valeur juste, à 256 près. Carry sera levé, ce qui permet d'exploiter le résultat. On teste Carry comme on teste "Z", en déviant le programme.

JR C,Suite!
JR NC, Retour
JP NC,... Call
C, .. . etc.

Admettons qu'en sortie d'une addition entre accumulateur et une valeur absolue, nous désirions transférer le résultat dans une paire, comme DE. Voici la séquence.

ADD A,n Additiion
LD D,n Par sécurité, D pouvant contenir une valeur
LD E,A Accumulateur pase en E
JR NC, Suite Sauter si Carry pas positioné
LD D,1 D passe à 1 (inc D aurait fait l'affaire)

Deux remarques : LD D,0 et LD E,A n'influencent pas Carry. Le test sur Carry est donc bien placé. Ensuite, dans une addition 8 bits + 8 bits, le positionnement de Carry indique un (et un seul) multiple de 256.
Z80 dispose de toute une famille d'instructions d'addition sur 8 bits.

ADD A,A Addition de l'accumulateur à lui-même
ADD A,n Accumulateur plus une valeur absolue (255 maximum)
ADD A,... N'importe lequel des registres pris isolément et non en paire
ADD A,(HL) Addition de l'accumulateur à n'importe quai, octet pointé par HL

Cette dernière instruction est particulièrement intéressante, car elle permet de faire l'économie d'une lecture. Mais attention, le résultat se trouve en accumulateur et... en Carry.

ADD A, (IX+d) Addition de l'accumulateur à l'octet pointé par IX, avec éventuel déplacement. Voir IX+150 , IX-3
ADD A, (IX+d) Idem, mais en utilisant le registre IY comme pointeur

Une autre propriété remarquable de l'addition retient l'attention. Si, en sortie d'addition, l'accumulateur est à 0 (avec ou sans Carry), le drapeau Z se lève. En combinant les tests sur "C" et sur "Z" il est donc aisé de tester les valeurs stratégiques. Voici une application.

ADD A , n
JR C,Suit1
; Résultat supérieur à 255, carry positionné
JR Z,Suit2
; zéro absolu, Carry n'étant pas positinné
JR Suit3
; Résultat entre 1 et 255
Suit1 JR Z,Suit4
; Carry positionné mais Z, donc résultat 256
;Séquence.. ;Valeur entre 256+1 et 256+255
;...........
Suit2 ...........

Un autre groupe d'instructions porte également sur l'addition 8 bits + 8 bits : ADC addition à travers le report. Ou'est-ce à dire ? L'addition par ADC tient compte d'un report antérieur éventuel, pour l'incorporer dans le résultat. Pour voir exactement comment joue ADC, il suffit de positionner Carry (voir SCF plus bas), de mettre accumulateur à 0 et d'additionner 0. Le résultat est 1, montant du report incorporé. A quoi peut bien servir l'addition par ADC ? Revenons à la base 10. Pour additionner en base 10, vous traitez ensemble les chiffres de même poids, les unités, puis les dizaines, etc. De temps en temps vous avez un report. Il en va de même pour additionner deux chiffres stockés par exemple sur 5 octets. On additionnera les chiffres des deux cases les plus basses, dégageant un report si le résultat est supérieur à 255, puis les deux cases de rang 2, etc. Mettons qu'un chiffre de ce type soit stocké en 9000H, un autre en 9005H. On veut les additionner entre eux, avec résultat en 9005H.

LD DE,9000H
LD HL.9005H Pointer chaque série d'octets
LD A, (DE) Lire premier octet vers A
ADD A, (HL) Additionner accumulateur à l'octet pointé par HL.
; Attention ADD et non pas ADC
LD (HL),A Ranger le résultat dans l'octet pointé par HL
INC DE
INC HL ;Décaler les pointeurs
LD A,(DE) Lire l'octet suivant
ADC A,(HL) Cette fois c'est bien ADC pour tenir compte d'un éventuel report
INC DE
INC HL

On répétera le dernier bloc encore 2 fois et en sortie, on testera Carry, car il peut y avoir report après la 5e addition. L'important, ici, est de noter que la séquence commence par ADD et se poursuit par ADC.
Je vois d'ici le chahuteur de service suggérer que "pour une programmation soi-disant directe et rapide, c'est plutôt laborieux". Effectivement. Tout vient de l'obligation de commencer par ADD, pour être sûr de ne pas embarquer un éventuel "Carry" préexistant, Carry sert en effet à bien autre chose qu'à constater les reports, comme nous le verrons. Il s'en suit que, même si vous n'avez pas encore additionné dans votre programme, vous ne pouvez faire confiance à cet indicateur. La solution existe : il faut "faire tomber Carry". Aucune instruction directe ne permet de gommer "Carry". Par contre une opération OR entre l'accumulateur et lui-même effectue le travail, sans changer le contenu de l'accumulateur. A partir de là les choses se simplifient considérablement :

LD DE,9000H
LD HL,9005H
LD B,5
OR A
Pour faire tomber Carry
Bcl LD A,(DE)
ADC A, (HL)
Carry étant gommé, allons y pour ADC dès la première itération
LD (HL),A
INC DE
INC HL
DJNZ Bcl
; Test sur Carry en sortie

A nouveau, on trouve toute une série d'instructions, strictement parallèles aux instructions ADD citées plus haut. Il est donc inutile de les répéter.

Addition 16 bits + 16 bits

Tout ce qui vient d'être dit s'applique aux additions 16 bits + 16 bits, à quelques petites nuances près. Jne addition 16 bits + 16 bits admet comme opérantes une aaire de registres, l'accumulateur n'étant plus concerné, /oici les instructions disponibles.

ADD HL,BC..........DE...........HL..........SP, résultat en HL et carry éventuel.
IX,BC..........DE...........IX..........SP, résultat en IX
IY,BC..........DE...........IY..........SP, résultat en IY et Carry éventuel.

Les variantes énoncées ici sont les seules disponibles. ADD BC.DE par exemple, n'existe pas.
Pour ADC, la gamme est encore plus restreinte. On passe toujours par HL.

ADC HL,BC..........DE...........HL..........SP, résultat en HL et Carry éventuel.

Dans cette liste figure un nouveau venu, SP, le pointeur de pile.

On en discutera plus longuement sous le thème "gérer la pile". Mieux vaut, dans l'immédiat, ne pas faire appel à lui, car si vous faussez le contenu de SP, vous aurez les suprises les plus désagréables au niveau du déroulement de votre programme (retours de sous-programmes intempestifs).
S'agissant de registres 8 bits accolés, donc pratiquement de registres 16 bits, le maximum qu'il soit possible de stocker est représenté par 65535 soit FFFFH. Carry se positionne lorsque le résultat de l'addition vient à dépasser ce montant et indique donc un et un seul multiple de 65536, qu'on peut exprimer par 10000H.

Il faut surveiller particulièrement la signification du contenu de Carry. Après une addition 8 bits, Carry ne pèse que 256, alors qu'il pèse 65536 après une addition 16 bits. Il faut donc se méfier d'un passage intempestif de l'addition 8 bits à l'addition 16 bits, à travers Carry.

Pour finir, une instruction très intéressante, SCF. On va détourner Carry de son objet et s'en servir pour tout autre chose. Imaginez un sous-programme comportant un test et deux traitements différents selon le résultat de cet test. Revenu dans le programme principal, vous voulez suivre un chemin différent dans l'un et dans l'autre cas. En Basic, vous avez la solution de définir une zone en %, que vous lettrez à 0 ou à 1.

Revenu dans la programme principal, vous testerez cette zone et vous vous débrancherez en conséquence. La même technique peut être mise en œuvre en assembleur, mais vous perdez un octet ; vous aurez besoin de charger 0 ou 1 dans l'accumulateur, qui contient déjà une valeur signifiante, etc.
Vous pouvez très avantageusement jouer avec Carry, que vous positionnerez si vous sortez du sous-programme en X, et que vous ferez tomber si vous sortez en Y.

Call SousProg
SousProg Test quelconque qui vous fait
JH C,Suite continuer en séquence ou aller en SousProgl
Séquence
SCF
RET Retour X, carry positonné
SousProg1
OR A
RET Retour Y, carry gommé

Revenu dans le programme principal, il suffit de tester Carry.

MICRONEWS n°12 Julllet/Août 1988

★ REVUE: MICRONEWS
★ ANNÉE: 1988
★ AUTEUR: André Schmitt
 

Page précédente : Micro News n°11 : Z80 Assembleur Facile

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding » Micro News n°09 : Z80 Assembleur Facile (4e partie : l'organisation de la mémoire)
» Coding » Micro News n°11 : Z80 Assembleur Facile
» Coding » Micro News n°08 : Z80 Assembleur Facile (3e partie)
» Coding » Micro News n°06 : Z80 Assembleur Facile (1ere partie)
» Coding » Micro News n°07 : Z80 Assembleur Facile - Les boucles (2eme partie)
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 790 millisecondes et consultée 1849 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.