CODINGCHRONIQUE Jean-Pierre Richard pour l'Ordinateur Individuel ★ UNE INTRODUCTION COMMENÇONS PAR LE Z80 ★

L'Ordinateur individuel n°18 - Langage Machine et Assembleur : Une Introduction Commençons par le Z80
L'utilisateur de P.S.I. (petit système individuel) en langage BASIC désire tôt ou tard programmer sa machine sans interprète. L'achat du programme éditeur-assembleur et de sa notice (en anglais) nous permet de découvrir, pour le Z80, 700 codes machines, dix modes d'adressage, vingt-deux registres et six indicateurs d'état. Cette complexité semble effrayante, il faut beaucoup de persévérance pour ne pas abandonner. C'est à ceux qui ont commencé (ou qui hésitent) que nous proposons ces articles sur le langage machine et l'assembleur. Progressivement, ces articles illustrés par beaucoup d'exemples (tous expérimentés par l'auteur, comme on dit) nous permettront d'optimiser nos programmes. N'oubliez pas, en effet, que tout utilisateur de P.S.I. en BASIC qui fait « l'impasse » sur le langage machine se prive d'une grande partie des possibilités de son système (PEEK, POKE...)

J'espère que votre courrier pourra rompre le monologue et permettre d'ouvrir une rubrique commentée sur vos programmes et vos astuces.

Le microprocesseur présenté est ici le Z80. L'esprit de l'assembleur est le même pour la plupart des microprocesseurs, mais nous ne manquerons pas de donner les grandes différences entre tous les microprocesseurs (8080, 6502, 6800...).

Mais avant tout, pourquoi le langage machine alors que des langages évolués permettent de programmer en clair ? En gros, les principaux attraits du langage machine sont la rapidité d'exécution, la faible consommation de mémoire, la porte « ouverte »vers le monde extérieur. Et puis, il est disponible sur toutes les machines, et ça, pour un passionné (nous le sommes tous), c'est impardonnable de ne pas connaître...

La programmation en assembleur est essentiellement fonction du microprocesseur considéré. Les articles de Jean-Pierre Richard sont une première introduction à ce vaste sujet. Les approches du problème sont nombreuses et d'autres sont possibles, notamment en partant depuis le niveau du BASIC.

Développons. La vitesse d'exécution d'un ordre est environ trois cents fois plus rapide en langage machine qu'en BASIC : l'accès mémoire dure 0,45 microseconde ! Un programme de 24 K mémoire en langage BASIC ne prend souvent plus qu'une place de 4 K mémoire en langage machine.

Imaginez-vous devant un MicroChess en langage BASIC avec un affichage de l'échiquier ligne par ligne ; le temps de réponse sur les « coups » difficiles, avant de bouger une pièce, vous fera finir la partie dans environ un an. L'asservissement d'une machine (ou plus simplement, un réseau de train électrique miniature), le contrôle d'un processus et d'une façon générale l'action et la réaction entre un système et son «cerveau » doivent être immédiats (aiguillage, déclenchement de sécurité). Seul le langage machine nous offre la possibilité d'éviter l'intermédiaire entre le «cerveau » et le système extérieur.

La programmation en langage machine par accès direct au microprocesseur Z80 est possible par l'intermédiaire du TBUG pour le TRS80 (NASBUG pour Nascom, etc.). Ce programme moniteur permet de développer « à la main » mais avec une

recherche continuelle dans la liste des ordres du Z80. C'est lent, difficile, les erreurs sont fréquentes et les programmes qui tournent du premier coup sont rares.

Un exemple simple
de programmation

Pour illustrer cette difficulté, nous pouvons développer un programme consistant à charger le registre A', avec la valeur 15. Cherchons dans la liste Z80 l'instruction de chargement du registre A avec une valeur numérique : c'est 3 E. La valeur 1 5 en base 10 est égale à F en base 1 6 (hexadécimale).

La ligne LOAD A, FH s'écrira donc 3E0F

  • LOAD signifie en anglais : chargement.
  • H spécifie la base hexadécimale de la valeur.

Ce n'est pas simple pour un ordre simple et alors quand ça se complique...

L'idéal, évidemment, et si vous êtes un passionné vous y avez pensé, est de créer un programme qui nous traduira une instruction « logique » du type : LOAD A, 15 en son code machine, avec traduction (si néces-saire)de la valeuren base hexadécimale.

1. Les registres sont des mémoires internes du microprocesseur.

Le fait de traduire implique l'idée d'un langage. Le programme de traduction existe et Assembleur est le nom de ce programme. L'exemple précédent s'écrira ainsi :
emplacement code , A .

emplacement
mémoire

code
machine
adresseinstructioncommentaires
YYY3E 0FXXXLD A,15; charge la valeur décimale 15 dans le registre A

Cette ligne constitue la ligne source : en voici la description :

Numéro de ligne : par exemple, XXX sera la ligne 100 (en base décimale). Cette numérotation aide la programmation mais n'est pas prise en compte lors de l'assemblage.

Etiquette : ce sera en quelque sorte la nom de la ligne. Cette étiquette, appelée aussi label ou adresse, sera utilisée —si nécessaire— comme destination de branchement dans le cas de boucles ou de sous-programmes. Son format est de six caractères alphanumériques au maximum, avec l'obligation d'avoir un premier caractère alphabétique.

Instruction : appelée aussi mnémonique, elle se présente sous la forme d'un code symbolique. C'est un ordre (ex : LD pour LOAD)ou bien un renseignement (ex: «origine» ou «fin» du programme); pour le Z80, la quantité de ces codes est d'environ 50. Un peu de pratique permet de manier les plus courants sans problèmes.

Les opérandes 1 et 2 : ils sont les suites logiques de l'instruction ; ce sera une adresse (étiquette) ou une valeur (si la lettre H suit cette valeur celle-ci est en base hexadécimale, sinon en base décimale)

La zone commentaire: elle permet de noter des informations relatives à l'étiquette ou/et à l'opération faite sur cette ligne. Elle n'est pas obligatoire, puisque lors de l'assemblage elle n'est pas prise en compte, mais fortement conseillée car elle facilite la relecture des programmes.

L'assemblage de cette ligne source donnera le programme objet suivant :

n° de ligne

étiquette instruction

1re opérande

2e opérande

commentaires
XXXLDA,15; charge la valeur décimale 15 dans le registre A

la mémoire 4A00H contiendra le code 3E

la mémoire 4A01 H contiendra le code 0F

On dispose de 3 codes maximum par ligne. Le code machine 3E0F, nous l'avons vu, est le code de l'instruction LDA.15 pour le microprocesseur Z 80.

L'assemblage permet donc de produire un programme en langage machine (programme objet) à l'aide de symboles, d'instructions et de déclarations dont la liste constitue le programme source.

Un programme en langage évolué sera lui aussi finalement traduit en code machine mais l'exécution de la traduction sera plus longue.

La suite démontrera (je l'espère), qu'en plus de la rapidité, la programmation en assembleur a bien d'autres possibilités.

Et tout d'abord, le matériel

Une description détaillée, mais illisible car trop rébarbative, n'est pas nécessaire. Cependant, l'«esprit» d'assemblage ne peut être complet si un premier niveau de connaissance de la structure de votre ordinateur et de son microprocesseur n'est pas assimilé. Le fonctionnement interne de tout outil complexe doit être compris par l'utilisateur, car cette connaissance accroît l'esprit d'innovation et de perfection.

Considérons tout d'abord le schéma de l'architecture de base d'un microcalculateur (figure 1). La partie gauche du microcalculateur représente l'horloge et son quartz de référence. Nous reviendrons en détail sur cette partie compliquée (rafraîchissement, séquence-ment...). Elle est reliée au microprocesseur, lui-même relié aux bus.

• Les microprocesseurs les plus courants (Z 80, 8080, 6800) possèdent trois types de bus (voir aussi L'O.I. nos 1 et 2) :

— Le bus d'adresse : c'est la liaison monodirectionnelle entre les registres spéciaux du microprocesseur et les mémoires dites «extérieures » (ou les périphériques). Ce bus transporte les adresses des mémoires qui seront à lire ou à écrire. Les adresses sont codées sur seize bits (soit 16 pattes sur le composant) : la plus grande adresse sera donc 1111 1111 1111 1111 soit FFFFH ou 65535. En d'autres termes cela signifie qu'un microprocesseur de ce type ne peut gérer plus de 64 K mémoires (64 x 1024) (en adressage direct). Un octet est constitué de huit bits, et chaque octet possède une adresse bien définie dans la carte mémoire.

— Le bus de données : c'est la liaison bidirectionnelle entre le microprocesseur et les mémoires ou les périphériques. Ce bus transporte la valeur lue ou à écrire dans la mémoire dont la localisation est spécifiée par le bus d'adresse. La valeur est exprimée en huit bits 11111111 soit FFH ou 255. Un état spécial de ce bus existe lors d'un accès direct mémoire (DMA = Direct Memory Access).

— Le bus de commande : c'est une liaison bidirectionnelle entre le microprocesseur et les mémoires ou les périphériques. Ce bus transporte les signaux de synchronisation entre une valeur et son adresse mémoire. Il transmet aussi les signaux de lecture,'d'écriture et d'interruption.

  • La détermination des priorités : elle régit l'ordre des données sur le bus lors d'un accès direct mémoire.
  • La mémoire morte MEM (en anglais ROM = Read Only Memory). Elle est constituée des mémoires qui ne peuvent qu'être lues. Le contenu non volatile de ces mémoires est fixé par le fabricant. Les programmes de base, tels que le BASIC ou un générateur de caractères, figurent sous cette forme.
  • La mémoire vive MEV (en anglais RAM = Random Access Memory), mémoire pouvant être lue ou écrite ; le contenu de ces mémoires se volatilise si la tension d'alimentation est coupée (batterie...).
  • E/S (1/0 — input/output) : ce sont les Entrées et les Sorties — cartes d'interface avec les périphériques tels que clavier ASCII, imprimante, disquettes, contrôle et gestion d'une machine.
  • Un microprocesseur est un circuit intégré à grande échelle (LSI = Large Scale Intégration) composé de milliers de transistors. Des techniques de pointe permettent sa construction sur une pastille de silicium de quelques millimètres carrés. Le tout est «coulé «dans un boîtier en plastique ou en céramique, deux rangées de 20 ou 21 pattes connectant cette «puce » avec l'extérieur. La fonction principale d'un microprocesseur est de manœuvrer toutes les données de la machine (en binaire) d'un registre à l'autre, ceci d'une manière pré-program-mée pour chaque opération (le chef dirige son équipe d'après des directives).


Figure 1


Figure 2


Figure 3

Structure
schématique
d'un microprocesseur

La structure simplifiée d'un microprocesseur Z 80 (figure 2) ou d'un microprocesseur 6800 (figure 3) fait apparaître les mêmes bus que précédemment. Ces bus « internes » sont reliés aux bus «externes» par un tampon (Buffer). Ces tampons sont des registres de 8 bits qui permettront un stockage d'une courte durée lors de l'attente sur une ligne.

  • Les registres : ce sont les mémoires internes du microprocesseur. Chacun d'eux peut contenirun mot de huit bits.

— Les registres B, C, D, E, H, L peuvent se coupler en paires de registres BC, DE, HL contenant chacun deux mots de huit bits (1 6 bits).

— Les registres d'index IX, IY (16 bits) permettent l'adressage mémoire dans le cas de tableaux, leur utilité est aisément démontrée en programmation; à suivre...

— Le registre pointeur de pile (1 6 bits) fStack Pointer)contient l'adresse du sommet de la pile dite pile LIFO (dernier entré, premier sorti : last in first out) : utilisé dans le cas de sous-programmes ou de stockage temporaire de données (utilisationdes instructions PUSH et POP que nous verrons plus loin).

— Le registre pointeur de programme (16 bits) (Program Counter). Ce registre contient l'adresse de l'instruction qui suit dans l'exécution du programme. Il est en communication avec les mémoires par le bus d'adresse. Il est interne, donc non utilisé par le programmeur. (Les figures 2 et 3 nous permettent de comparer le microprocesseur Z80 de Zilog et le microprocesseur 6800 de Motorola. Le pointeur de programme PC, le pointeur de pile SPet le registre d'index ont les mêmes fonctions. C'est l'absence de registres B, Cf D, E, H, Ldans le 6800qui rendra les méthodes de programmation complètement différentes.)

— Le registre A ou accumulateur s'utilise pour les opérations arithmétiques ou logiques. Il sert aussi comme registre tampon des données à traiter. C'est le registre le plus utilisé.

— Le registre - indicateur d'état : Ftags Register du Z 80 ou CCR (Condition Code Register) du 6800 : il indique les modifications d'état lors de l'exécution d'une opération. L'exemple suivant éclaircit cette définition : si le résultat d'une opération devient nul ou inférieur à zéro, l'indicateur d'état correspondant (Z-bit 6 ou N-bit 1 ) changera de valeur. Ce registre 8 bits apparaît sous la forme suivante :

Le bit 7 : S (signes) S = 1 si le résultat obtenu est négatif (abréviation M comme moins)

S = 0 si le résultat obtenu est positif (abréviation P comme plus).

Le bit 6 : Z(zéro)Z = 1 si le résultat d'une opération est nul, sert aussi lors de comparaison entre deux valeurs.

. Le bit 4 : H (Half-Carry)demi-retenue. En fonctionnement DCB (décimal codé en binaire), ce qui n'est pas le cas de nos systèmes, le registre de huit bits est séparé en deux groupes de quatre bits : H devient égal à 1 si, pendant une opération, il y a une retenue entre le premier groupe et le second groupe de quatre bits.

Le bit 2 : P/V (Parity/Overflow) parité/débordement. Il indique si, par erreur, le contenu d'un bit change d'état lors des opérations de transmission (avec le magnétophone, par exemple). Il indique aussi — la modification du bit 7 d'un registre par une retenue (ce bit 7 est dit « bit le plus significatif »d'un mot de huits bits (MSB = Most Signifiant Bit)car il indique le signe de la valeur (1 = — ; 0 = +)).

Le bit 1 : si N = 0, le résultat de l'opération est positif ; si N = 1, le résultat de l'opération est négatif (il s'agit en fait du MSB du résultat).

Le bit 0: C = 1 si le résultat de l'opération ne peut être contenu dans un mot de huit bits. Cet indicateur
est aussi utilisé dans les opérations de décalage et de rotation (à suivre aussi...).

  • UAL: unité arithmétique et logique ; elle exécute les opérations arithmétiques (addition et soustraction) et les opérations logiques (et, ou, négation). La fonction de cette unité est semblable à une petite machine à calculs.
  • Le registre RI (IR = Instruction Register): registre d'instruction; reçoit l'instruction à exécuter du bus de données.
  • Le registre décodeur (Decoder)eX le registre contrôleur-séquenceur permettent à cette instruction de devenir commande.

Dans un prochain article, nous parlerons logiciel : l'adressage et les instructions du Z 80 et les méthodes de programmation en langage d'assemblage. Ce logiciel est bien évidemment strictement fonction de la structure que nous venons de décrire.

Jean-Pierre Richard , L'Ordinateur Individuel n°18

★ REVUE: L'Ordinateur Individuel
★ ANNÉE: ???
★ AUTEUR: Jean-Pierre RICHARD

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.732-desktop/c
Page créée en 418 millisecondes et consultée 221 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.