Revenir au plan du site

Convention de lecture pour le jeu d'instructions


Préambule
La description du jeu d'instructions suit un ordre logique dans un but d'apprentissage, il ne doit pas être vu comme une documentation technique brute. Ainsi, les premières instructions décrites sont les instructions de chargement mémoire/registre, puis les instructions de comparaison et celles de sauts conditionnels. Enfin, les autres instructions réalisant des opérations ou calculs sur les registres. Voici un exemple simple de programme Z80 :

LD A,(variable1) ; charger dans A l'octet présent à l'adresse variable1
LD HL,variable2 ; charger dans HL l'adresse de variable2
CP A,(HL) ; comparer la valeur de A avec l'octet à l'adresse HL (soit variable2)
JR Z,egalite ; si la soustraction de A par (HL) vaut zéro, c'est que les deux valeurs sont égales, alors on réalise le saut vers egalite

Abréviations pour les opérandes
reg8 : registre 8 bits (sauf I ou R)
reg16 : registre 16 bits (sauf PC,SP,IR)
dep8 : déplacement relatif 8 bits (-128 à +127)
n : valeur immédiate 8 bits
nn : valeur immédiate 16 bits
(reg16): valeur en mémoire indexée par un registre 16 bits (sauf PC,SP,IR)
(nn) : valeur en mémoire indexée en absolu par une valeur 16 bits

L'utilisation des registres IX et IY en adressage peut toujours s'accompagner d'un déplacement de type dep8.

Valeurs littérales
Il est important de signaler que les valeurs littérales exprimées ici représentent un consensus global entre assembleurs Z80 mais les assembleurs les plus anciens ne supportent pas toutes les syntaxes.

12345 ; valeur décimale
#1234 ; valeur hexadécimale
0x1234 ; valeur hexadécimale
&1234 ; valeur hexadécimale héritée du Basic Locomotive (déconseillée pour confusion avec l'opérateur AND de certains assembleurs)
$1234 ; valeur hexadécimale héritée de Motorola (déconseillé pour éviter la confusion avec l'adresse courante qui est $)
%01010 ; valeur binaire
0b1010 ; valeur binaire
@4736 ; valeur octale
$ ; adresse de l'instruction en cours (utilisé principalement pour des sauts relatifs)

Si vous êtes déjà perdu avec les différentes bases (binaire : base 2, octal : base 8, ...) je vous recommande la lecture des 25 premières pages de "programmation en assembleur" de Sybex dont vous pourrez télécharger un exemplaire PDF sur [le site d'Amstrad CPC Mémoire écrite].

Valeurs remarquables
Le Z80 est conçu pour traiter des données 8 bits ou 16 bits. Afin d'appréhender plus facilement les retenues ou les bits susceptibles d'être décalées, il faut faire ses gammes avec les valeurs dîtes remarquables et les connaitre par cœur.

Valeur de chaque bit
Bit7 6 5 4 3 2 1 0
Valeur128 64 32 16 8 4 2 1

Comprendre le principe de la pile
La plupart des microprocesseurs possèdent un mécanisme de pile pour enregistrer (empiler) des informations et les restituer à la demande. Cette pile est une structure de donnée basée sur le principe de dernier arrivé, premier sorti (en anglais LIFO pour last in, first out). Sur le Z80, c'est le registre SP qui indique l'adresse en mémoire vive du dernier élément empilé. Les instructions PUSH et POP, mais aussi CALL et RET effectuent des sauvegardes et des restitutions depuis la pile.

Dans un langage évolué, l'utilisation de la pile est transparent et géré par le compilateur. En assembleur, toute fonction appelée par un CALL doit logiquement se terminer par un RET. Si on sauvegarde un certain nombre de registre dans la pile (pour pouvoir les modifier par exemple), il est impératif d'en restituer le même nombre pour ne pas faire déborder la pile.

Quand les interruptions sont actives, le programme en cours peut-être interrompu à tout moment. À cet instant, le processeur enregistre l'adresse courante (comme avec un CALL) dans la pile et exécute le programme défini pour les interruptions. Afin de ne pas corrompre l'exécution du programme interrompu, le programme sous interruption doit enregistrer tous les registres qu'il va modifier. La méthode la plus simple est d'utiliser la pile. En fin de routine, le programme sous interruption restituent un à un les registres. Ré-active les interruptions puis RET(ourne) au programme qui a été interrompu.

Dans le chapitre sur la programmation avancée, nous verrons des exemples détournés de l'utilisation de la pile. Tant pour écrire dans la mémoire plus rapidement que pour lire des paquets de données. Cette utilisation demande une désactivation des interruptions et une maitrise parfaite de ce qu'on fait.

Les préfixes
Dans les années 80, on a beaucoup parlé de préfixes étendus car les assembleurs de l'époque n'ont jamais été développés pour prendre en compte toutes les instructions du Z80. Cette situation perdure encore aujourd'hui et les assembleurs supportant les instructions étendues sont toujours rares (support partiel pour Winape et support complet pour Rasm et Sjasm) mais ils existent!

Ces préfixes étaient utilisés pour "débloquer" certaines fonctionnalités soit-disant cachées du Z80. En fait parfaitement documentées par Zilog au moment où ces assembleurs ont été créés.

Ainsi, pour adresser les 8 bits de poids faible de IX il fallait écrire

DEFB #DD : LD L,5

Ce qui est équivalent à

LD XL,5

Bien entendu la deuxième syntaxe est recommandée mais il faudra utiliser un assembleur moderne tel que Rasm ou Orgams.

À propos des flags
Cet ouvrage référence le comportement utile des flags après opération. Le comportement des bits 3 et 5 est beaucoup trop complexe pour être abordé dans un ouvrage de programmation. Ce comportement est néanmoins nécessaire à la programmation d'un émulateur Z80. Il faut savoir qu'il existe un registre interne au Z80, appelé MEMPTR ou WZ selon les documents disponibles et que ce registre est modifié par certaines instructions (incrémentation, recopie de BC ou PC, valeur de port ou de A, ...). Lorsque l'on utilise l'instruction BIT, les bits 11 et 13 de ce registre sont recopiés dans les bits 3 et 5 des flags. D'autres instructions réalisant des calculs recopient les bits de l'accumulateur dans ces fameux bits.

Référence : Baltazar Studios (copie en cache)