CODING ★ MICRONEWS - Z80 ASSEMBLEUR FACILE (4e partie : l'organisation de la mémoire) ★

Cours et initiation du Magazine Micro NewsMicro News n°09 : Z80 Assembleur Facile (4e partie : l'organisation de la mémoire)

Nous avons indiqué récemment que la directive d'assemblage ORG permet de situer l'endroit précis de la mémoire à partir duquel un programme doit s'implanter.

ENTRE NOUS, mettez le où vous voulez pourvu que ce soit dans la RAM et sans supprimer la table de communication par exemple. Pour autant, tout a-t-il été dit sur l'organisation de la mémoire ? Il faut ici retrouver notre virginité intellectuelle et oublier Basic. Ce langage évolué prête constamment main forte au programmeur et lui donne de désastreuses habitudes. Vous voulez une zone de stockage, A1 ou A1$ ? Faites comme si A1 ou A1$ étaient déjà définis, localisés. Moi, Basic, je prends à mon compte la gestion de ces zones, et d'ailleurs je les promène à ma guise du haut au bas de la mémoire, comme vous pouvez le voir par l'instruction VARPTR. Bien entendu il me faut du temps pour retrouver ces zones, les déplacer, mais on n'a rien sans rien I En assembleur, les choses vont bien différemment.

Dans tous les cas vous localisez très précisément vos zones de stockage dans des cases mémoire précises, à des adresses précises. Prenons un premier cas de figure, le plus simple.

On peut concevoir que vous envisagiez d'implanter votre programme en 9000H (ORG 9000H) en réservant au stockage les octets situés entre 8800H et 8FFFH.

Voyez que déjà nous parlons d'un secteur bien précis de la mémoire. Il faut vous assurer que rien ne viendra brouiller le contenu de ces octets, aucun Mister Basic ne le faisant à votre place.

Si votre module assembleur doit s'intégrer à un programme Basic par USER, l'instruction CLEAR n, &H8800 fera l'affaire. Si vous êtes exclusivement en langage machine, vous ne risquez rien, tout au moins dans la plage 8800H à 8FFFH.

Vient ensuite une autre précaution : les octets entre 8800H et 8FFFH peuvent contenir et contiennent même certainement des valeurs parasites. Si vous avez la certitude que dans tous les cas vous allez d'abord écrire ces octets avant de les lire, laissez les choses en l'état. Vous découvrirez cependant par la suite des instructions de manipulation des cases mémoire qui font que vous auriez intérêt à tout trouver à 0. Et puis, en cours de route, vous pouvez oublier la règle que vous vous êtes fixé : écrire d'abord. Voici donc une petite boucle qui met tout ce beau monde à 0 (il y a plus sophistiqué, sois patience).

LD BC,0800H : BC, compteur de
: boucle à 800H
LD HL,8800H : HL, pointeur, sur
: 8800H
P1 XOR A : met A , accumulateur
: à 0
LD (HL),A : transfère le contenu
: de A dans l'adresse : pointée par HL
INC HL : déplace HL d'un
: octet
DEC BC : décrémente BC
LD A, B
OR C
JR NZ,P1

Cette petite boucle apporte plusieurs notions nouvelles que nous préciserons plus bas. Remarquez surtout l'endroit précis du point de bouclage, P1. En effet vous savez déjà que A est utilisé plus bas pour tester la fin de boucle, et donc perd sa valeur. Il faut bien, à chaque itération, remettre A à 0, au niveau de P1.

Vous avez maintenant 900H octets à votre disposition, contenant tous la valeur 0. Vous pouvez par la suite les adresser en physique, 8800H, 8802H, etc.

Basic ne vous a guère habitué à prendre des gants vis à vis des zones de stockage. Tout juste si dans telle application vous avez défini quelques entiers en % pour ménager la mémoire. Quant aux zones en $, vogue la galère I En assembleur , vous ne perdrez pas un seul octet. Vous arrêterez très précisément les longueurs qui vous sont nécessaires, sans possibilité pour vous d'empiéter. Concrètement, pour vos débuts, vous aurez besoin : de zones à 1 octet pour ranger le contenu d'un registre, de zones à 2 octets pour ranger le contenu d'une paire, de zones plus longues pour vos données alphanumériques, à raison d'un octet par caractère.

Qu'est-ce qui distinguera les zones ainsi définies les unes des autres ? Rien, absolument et désespérément rien I Vous avez une suite d'octets qui ne sont séparés ou répertoriés par aucune indication d'aucune sorte. Tout se tient dans votre tête et uniquement là.

C'est si vrai que, prenant un octet quelconque et constatant qu'il contient, mettons la valeur 41 H, nous ne pouvons pas dire à priori :

  • s'il s'agit de la valeur absolue 65 en décimal,
  • s'il s'agit d'une valeur faisant partie d'un groupe,
  • s'il s'agit de la codification ASCII de la lettre A.
  • s'il s'agit de l'instruction LD B,C : transférer C dans B.

Cette ambiguité va nous obliger en particulier à prendre une précaution précise chaque fois que nous logerons une zone de stockage à l'intérieur de notre programme : il faut que le

programme enjambe ces zones par JR ou JP, ou encore qu'elles soient judicieusement placées entre deux sous-programmes, là où le programme ne "passe" jamais. A défaut le programme entre intempestivement dans les zones de stockage et bien entendu plus personne ne répond plus de rien. Dans un même ordre d'idées, si je me trompe de case en lecture, et que je lis 41H qui représente la valeur ASCII de A alors que je crois lire tout autre chose, par exemple la valeur d'un compteur, personne ne signalera l'ambiguité et, de nouveau, tout peut arriver au programme.

Nie levez pas les bras au ciel pour autant ! C'est à dessein que pour nos premiers essais j'ai logé les zones hors du programme. De cette manière nous sommes déjà garantis contre la confusion instructions-données. Ensuite pour ne pas vous perdre dans le détail des adresses faites appel aux équivalences :

CPT1 EQU 8800H ou bien CPT1 EQU 8800H
CPT2 EQU 8801H CPT2 EQU CPT1+1
CPT3 EQU 8803H CPT3 EQU CPT2+2
TXT1 EQU 8804H TXT1 EQU CPT3+1
TXT2 EQU 880AH TXT2 EQU TXT1+6
Etc.

Voyons à présent comment définir des zones à l'intérieur du programme. La terminologie change quelque peu d'un programme d'assemblage à l'autre, pour un résultat identique. Vous pouvez placer ces instructions n'importe où dans votre programme si vous tenez compte des restrictions énoncées plus haut.
  • Étiquette DEFB n : réserve 1 octet initialisé à n Étiquette DEFB "A" : réserve 1 octet initialisé à A ASCII (41 H)
  • Étiquette DEFW nn : réserve 2 octets initialisés à nn
  • Étiquette DEFS nn : réserve un bloc de nn octets
  • Étiquette DEFM 'ABCD' : réserve un bloc aussi long que la chaîne 'ABCD' et l'initialise à 'ABCD' ASCII
  • Étiquette n'est évidemment pas obligatoire, mais vous en aurez besoin pour l'adressage.

Puisque nous voilà au fait de la réservation de zones, commençons à nous pencher sur le problème de l'écriture et de la lecture de ces zones.

Certains assembleurs connaissent une notion très explicite de pointeurs qu'il convient de diriger vers la zone à lire ou à écrire avant de passer à l'opération elle-même. Ces pointeurs ne servent alors qu'à cette tâche spécifique : pointer. En assembleur Z80 ce genre de pointeur n'existe pas. Ce sont nos vieilles connaissance, HL, DE, BC et tout spécialement HL, qui vont faire office de pointeurs. HL vient d'ailleurs de High Low, que l'on retrouve dans "adresse partie Haute, adresse partie Basse".

Deux autres compères s'ajoutent à la liste : les registres d'index IY et IX.

En assembleur Z80, pour pointer une zone, on charge l'adresse de cette zone dans un registre double.

Différentes formules pratiques existent, qui reviennent toutes à réaliser finalement un LD HL,nn,-nn étant l'adresse.

LD HL,8800H : chargement en valeur absolue
LD HL,CPT1 : chargement de l'équivalence de CPT1, après définition
CPT1 EQU 8800H
LD HL,Z : Z1 représente l'adresse calculée par le programme d'assemblage dans une séquence qui pourrait être la suivante:

instruction JR SUIT1 (pour enjamber)

Z1 DEFB x

SUIT1 instruction
instruction

Sitôt le registre doubla initialisé comme pointeur, on l'associe à quelque autre opération. Mettons que la valeur à gérer doive transiter par A, accumulateur.

Nous aurons :

LD A,(HL) : charger A à partir de l'octet pointé par HL (on dit d'adresse indirecte HL)
LD (HL),A : charger l'octet pointé par HL à partir de A

Notez bien le formalisme de l'écriture : le destinataire est toujours écrit en premier.

Pour bien montrer que HL fait office de pointeur, a est écrit entre parenthèses.

Il n'y a aucune obligation d'employer un pointeur, mais bien souvent c'est la solution qui permet de programmer de manière condensée et efficace.

Si HL est initialisé à 8800H, donc "pointe" sur 8800H , les écritures suivantes sont strictement équivalentes.

LD A,(8800H) : charger A à partir de l'octet d'adresse 8800H
LD A , ( HL)
LD (8800H),A : transférer dans l'octet d'adresse 8800H le
LD (HL) , A : contenu de A


L'intérêt du "pointeur" réside dans la possibilité qu'il nous modifié par calcul. C'est exactement ce qui se passe dans notre boucle début. Par INC HL, nous ajoutons 1 à HL, c'est-à-dire que nous déplaçons le pointeur d'une position au fur et à mesure que la boucle se développe. A chaque fois nous rangeons 0 à la nouvelle position.

André Schmitt , MICRONEWS n°9

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

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

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

Lien(s):
» Coding » Micro News n°08 : Z80 Assembleur Facile (3e partie)
» Coding » Micro News n°06 : Z80 Assembleur Facile (1ere partie)
» Coding » Micro News n°11 : Z80 Assembleur Facile
» Coding » Micro News n°07 : Z80 Assembleur Facile - Les boucles (2eme partie)
» Coding » Micro News n°12 : Z80 Assembleur Facile
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
Page créée en 563 millisecondes et consultée 741 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.