| ★ CODING ★ CHRONIQUE Jean-Pierre Richard pour l'Ordinateur Individuel ★ LANGAGE MACHINE ET ASSEMBLEUR : LES REGISTRES DU Z 80 ★ |
| L'Ordinateur individuel n°19 - Langage Machine et Assembleur : Les Registres du Z80 |
Le langage d'assemblage et par conséquent le langage machine dépend du «composant » microprocesseur et des fabricants d'ordinateurs individuels ; le programme assembleur peut légèrement différer (ponctuation, édition...) entre deux ordinateurs ayant le même composant de base. La carte mémoire (adresses réservées, adresses disponibles) est différente d'un matériel à un autre ; un programme devra y être adapté avant l'assemblage.Le langage d'assemblage est différent d'un langage évolué. La connaissance générale des éléments et de la structure interne de l'ordinateur (ou hardware, mot anglais ne possédant pas d'équivalent dans la langue française) est nécessaire pour une programmation efficace. Chaque microprocesseur a son propre langage d'assemblage mis à part quelques équivalences exceptionnelles. Les structures internes étant très différentes entre microprocesseurs il ne peut en être autrement. A titre d'exemple, le 6800 (Motorola) a deux accumulateurs et peu de registres internes, le Z80 (Zilog) a beaucoup de registres internes mais un seul accumulateur ; il existe également des microprocesseurs à 4, 8, 16 bits... Devant cette diversité, nous allons nous intéresser au microprocesseur Z 80 de Zilog. Ce microprocesseur, nec plus ultra des microprocesseurs huit bits est un prolongement du microprocesseur 8080 de Intel. Bien que plus complet que ce dernier sur le plan des instructions et également plus pratique par sa formule en un boitier, le Z 80 a gardé une compatibilité avec le 8080. Il existe une table d'équivalence entre les instructions 8080 et Z 80 (ex. : MOV R1, R2 = LD R1, R2). On dispose ainsi delà «programmathèque » du 8080, très importante étant donné que ce microprocesseur a été un des plus vendus.
Les exemples de programmes sont donnés assemblés. Les sceptiques du langage machine assembleur, ne voulant pas «investir» dans un programme assembleur, peuvent introduire les codes machines à l'aide d'un moniteur (TBUG, NAS-BUG...) ou des PEEK et POKE en BASIC. Il importe de faire tout d'abord un rapide rappel de la structure interne du Z80 et de son emplacement dans l'architecture d'un ordinateur (figure 1 ). Les registres huits bits B, C, D, E, H, L sont apairables en registres pairs de 1 6 bits BC, DE, HL. Les registres pairs AF et A'F' sont utilisés dans certaines opérations (piles). La structure d'un langage d'assemblage se décompose en cinq parties distinctes :
Face à cet univers nous pouvons maintenant étudier les instructions de transfert de données. Elles se présenteront toujours sous ce même format : LD destination, origine. LD : LOAD (charger en français) destination: registre, adresse, index, label. Origine : registre, adresse, index, label, donnée. Nous pouvons donc voir comment effectuer un transfert de données en huit bits avec l'exemple 1.
Tout ce qui est après un point virgule (;) est considéré comme étant «zone commentaires»; c'est le REM du BASIC. Les instructions ORG et END sont des directives d'assemblage. Ces instructions font partie des pseudo-instructions. Nous y reviendrons. ORG (ORiGine) a défini la première adresse mémoire du premier code machine du programme ; END indique la fin du programme. Ces deux instructions n'ont pas de code machine mais elles sont nécessaires (et obligatoires!) pour «placer» le programme dans la carte mémoire. Les valeurs des adresses mémoires sont donc à adapter à votre microprocesseur. Ligne 140 : elle met la donnée 20 hexadécimale dans le registre B. C'est un transfert de type LD registre, donnée. Le code machine obtenu, 0620, se décompose ainsi : 06 est le code spécifique de l'instruction : LD B, donnée. 20 est la valeur de cette donnée. A la ligne LD B,10Hcorres-pondra le code 0610. Si la donnée est décimale, le programme assembleur la convertira en hexadécimale (ex: LD B,16 donne 0610). Ligne 150: la valeur du registre B est copiée dans l'accumulateur A. Le registre B contient encore la valeur 20H. Un transfert d'origine (registre, adresse, index, label) vers la destination (registre, adresse, index, label) ne modifie jamais la valeur de l'origine. Ligne 160 : la valeur de A est copiée à l'adresse mémoire contenue dans le registre pair HL. C'est un autre principe de base que nous rencontrons.
Ligne 170: la valeur contenue dans l'emplacement mémoire pointé par HL est copiée dans le registre E. Ligne 190. la valeur contenue dans l'accumulateur est copiée à l'adresse mémoire 0108H. HL est utilisé comme pointeur d'adresse car son jeu d'instructions est très complet : nous le verrons au fur et à mesure.
L'adressage mémoire peut être direct. Les parenthèses permettent de distinguer cette adresse d'une simple valeur (ex : LD (0108H),A).
où n+ est l'octet haut, n— l'octet bas. L'adresse n+ n—, 0108H dans l'exemple, est composée de deux octets (le bus d'adresse du Z 80 est un bus 16 bits). L'octet 08 est appelé octet bas, c'est l'octet le moins significatif. L'octet 01 est appelé octet haut, c'est l'octet le plus significatif. En code machine, l'octet bas est toujours placé avant l'octet haut : ainsi LD (108H),A se traduit en code machine par 32 08 01. Cet exemple contient les transferts de données huit bits (sauf adresse indexée que nous verrons dans l'exemple 5). Ne cherchez pas de signification à ce programme ! Il peut à la rigueur faire partie de l'initialisation de registre dans un programme plus long, mais ce n'est pas le plus important. Etes-vous prêts pour un Transfert de données en 1 6 bits ? Allons-y avec l'exemple 2. Ce programme initialise les registres B et C avec les valeurs 05H et 02H. Le registre BC contiendra donc la valeur 0502H. Le Z 80 nous permet de charger directement une valeur 16 bits dans un registre pair. Dans Y exemple 3, cette instruction distribue automatiquement les deux octets à deux adresses consécutives. L'octet bas est placé avant l'octet haut comme on peut le voir dans l'exemple 4. Nous pouvons maintenant avec l'exemple 5 effectuer des transferts de données 8 et 16 bits. Ligne 130: le registre pair HL est chargé de la valeur 4D00H. Notez bien la distribution de l'octet haut et de l'octet bas de la valeur 4D00H dans le code machine. Ligne 140 : nous avons déjà eu cette forme d'adressage dans l'exemple 1. Une valeur ou un registre pair mis entre parenthèses pointe une adresse mémoire. Ici le registre HL mis entre parenthèses pointe l'adresse 4D00H. A la ligne 190 nous préciserons quelques restrictions d'utilisation. Ligne 150: la valeur contenue dans HL, deux octets, est copiée à l'adresse pointée par la valeur 4D02H (mise entre parenthèses) pour l'octet haut ; l'octet bas sera copié à l'a- Ligne 160: IX et IY sont des registres d'index (1 6 bits). Ligne 170: utilisation d'un registre d'index. L'ensemble (IX+ d) ou (IY + d) indexe une adresse. La valeur de cette adresse est la somme de la valeur contenue dans le registre d'index et du déplacement d. d est représenté en complément à deux : ainsi pour un déplacement de — 1 ,d sera égal à FFH (à suivre...). Ligne 190: la valeur de l'accumulation est copiée dans l'adresse pointée par BC. Attention ! Mis à part les registres IX, IY et SP, seul le registre pair HL adresse,ou est adressable par, tous les registres du Z 80.
C'est ce jeu d'instructions supplémentaires qui nous fera choisir le registre pair HL comme conteneur d'adresse dans nos programmes. Cet exemple nous a permis de programmer un échantillonnage de transferts de données 1 6 bits et 8 bits. Le registre SP sera traité quand nous aborderons les piles. Intéressons-nous tout d'abord à l'utilisation des labels et des pseudoinstructions. Maintenant que nous savons manipuler les données dans les registres et les mémoires, voyons une application pratique et simple qui va nous mener très loin, vous allez voir... Dans l'exemple 6 le premier pas de programme assigne au label ECRAN la valeur 3C00H. L'instruction EQU qui n'a pas de code opératoire est appelée pseudo-instruction. L'assembleur reconnait cette instruction et l'exécute. Ligne 140: l'adresse du début de l'écran vidéo est copié dans le registre HL par l'intermédiaire du label. C'est maintenant à vous, lecteurs, d'adapter votre programme à votre ordinateur (si ce n'est pas un TRS 80). Recherchez sur la carte mémoire l'adresse de la mémoire vidéo et remplacer 3C00H par cette valeur. Ligne 150: le code ASCII du caractère entre guillemets est copié dans l'accumulateur : * a pour code ASCII 2A. Cette conversion automatique va nous économiser un temps précieux ! Il existe d'autres pseudo-instructions dont les fonctions sont de définir un ou des octets, un caractère ASCII, un mot ou une chaîne alphanumérique. Elles permettent également de réserver une ou des adresses et d'assigner une valeur à un label ou un label à une adresse. Ce sont les pseudo-instructions suivantes :
NB : il est possible de faire des opérations simples sur les labels. Ex : ECRAN + 40H est la ligne suivante.
L'exemple 12 nous montre une application des pseudo-instructions. L'exécution de ce programme fait apparaître deux astérisques sur l'écran vidéo. Il existe un moyen plus performant d'afficher une suite de caractères : il suffit de réaliser des sauts conditionnels et inconditionnels comme dans l'exemple 13. La ligne 170 incrémente le registre pair HL, HLpointe la position suivante de la mémoire vidéo et l'instruction JP BOUCLE branche inconditionnellement le programme à l'adresse du label BOUCLE. L'écran n'ayant que 1 024 adresses, le programme va « se planter » à la 1024e fois. Il faut maîtriser cette boucle par un branchement conditionnel. Complétons l'exemple n° 13 avec les lignes qui apparaissent dans l'exemple 14 (nous y reviendrons). Ce branchement conditionnel sert de compteur au programme d'affichage d'astérisques et seule la première ligne sera adressée. Ligne 165: une ligne de l'écran vidéo ayant 64 adresses, B sera donc chargé de la valeur 64 (40H). Ligne 185: l'instruction DEC décroit la valeur du registre désigné, en l'occurrence le registre N. Ligne 190 : elle teste l'indicateur Z et branche le programme à l'adresse du label BOUCLE si la valeur n'est pas nulle. Il apparaît maintenant opportun de faire quelques rappels sur le registre indicateur d'état (ci-des-sous).
Les bits 3 et 5 ne sont pas utilisés Les bits 0,2, 6 et 7 sont utilisés dans les branchements conditionnels du type JP et CALL. Les bits 0 et 6 sont utilisés dans les branchements conditionnels du type JR.
L'organigramme 1 correspond à l'exemple 14. Si vous trouvez l'affichage de l'astérisque trop rapide ou si vous désirez afficher l'astérisque toutes les secondes, par exemple, il faut imbriquer une boucle « à vide »dans la 1re boucle (exemple 15). L'organigramme 1 devient l'organigramme 2. L'instruction DJNZ, nn permet de décrémenter la valeur du registre B et d'effectuer un branchement vers l'adresse ou le label tant que cette valeur ne sera pas nulle. Cette instruction ne s'applique qu'au registre B L'organigramme du programme 13 sera ainsi modifié pour donner l'organigramme 3.
Si la valeur maximum de FFH (256) ne donne pas un temps suffisamment long, nous pouvons utiliser un registre pair. La valeur du registre pair DE est contrôlée par une addition logique entre l'accumulateur, préalablement chargé de la valeur D, et le registre E (exemple 16). Le résultat qui se trouve dans l'accumulateur met à 1 l'indicateur d'état Z s'il est nul. L'instruction JR, n est un branchement relatif inconditionnel ou conditionnel.
L'instruction branche le programme, si la condition CC est remplie, à l'adresse contenue dans le pointeur de programme PC additionnée de la valeur du déplacement d. Ce branchement peut s'effectuer à une adresse en amont ou en aval de l'emplacement actuel (limite + 1 27, — 128 octets), d est soit une valeur en représentation complément à deux, soit un label. CC peut être Z, NZ, C, NC. L'instruction JR donne un code machine indépendant de l'emplacement actuel du programme dans la mémoire. Cette propriété rend le programme relogeable dans la carte mémoire et détermine souvent le choix de cette instruction (exemples 17 et 18). Vous avez en main plus d'une centaine d'opérations d'assemblage possibles, alors avant d'en apprendre d'autres, entraînez-vous ! Modifiez les exemples, créez d'autres programmes (caractèrequi clignote, qui se déplace...) et n'oubliez surtout pas cette morale : MILLE FOIS sur le clavier remettez votre programme...
Jean-Pierre Richard, L'Ordinateur individuel n°19
| |||||||||||||||||||||||||||||||||