# Programmation Assembleur Z80/Jeu d instructions
### 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:

#### Abréviations pour les opérandes

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.

#### 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.
* L’intervalle des valeurs en 8 bits signé est de -128 à +127 (soit 256 valeurs avec le zéro)
* L'intervalle des valeurs en 8 bits non signé est de 0 à 255 (soit toujours 256 valeurs)
* L’intervalle des valeurs en 16 bits signé est de -32768 à +32767 (soit 65536 valeurs avec le zéro)
* L'intervalle des valeurs en 16 bits non signé est de 0 à 65535 (soit toujours 65536 valeurs)
Valeur de chaque bit
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| Valeur | 128 | 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
Ce qui est équivalent à
Bien entendu la deuxième syntaxe est recommandée mais il faudra utiliser un assembleur moderne tel que Rasm ou Sjasm.

#### À 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: https://baltazarstudios.com/webshare/A-Z80/memptr_eng.txt

### Instructions de chargement de données
#### LD

L'instruction de base pour charger une valeur est LD (contraction de LOAD). Les instructions de chargement ne modifient jamais les flags.
On peut utiliser différente combinaisons de LD (cette liste est indicative)
Il n'est pas possible de charger un registre 16 bits dans un autre mais on peut utiliser presque toutes les combinaisons possibles avec les registres 8 bits. Ainsi, pour charger HL dans BC:
Il n'est pas possible d'effectuer des combinaisons de chargement LD reg8,reg8 entre les registres XH,XL et YH,YL et encore H,L car ils utilisent une racine commune d'opcode en interne. Les opcodes qui utilisent XH,XL,YH,YL sont préfixés par #DD ou #FD et suivis de l'opcode utilisé pour les registres H et L. Ce préfixe indique au Z80 de basculer sur les registres IX ou IY au lieu de HL.

### Instructions d'échange de registres ou mémoire

Le Z80 permet la permutation de certains registres, notamment pour accéder aux registres secondaires. Beaucoup de systèmes d'exploitation ont été conçus en n'utilisant qu'un seul des deux jeux de registre du Z80. Ainsi, l'utilisateur peut modifier les registres courants à loisir sans se soucier de les sauvegarder avant utilisation. Le système d'exploitation n'ayant qu'à exécuter un EXX pour retrouver "ses" registres.

#### EXX

L'instruction EXX permute les registres BC, DE et HL avec les registres secondaires BC', DE' et HL'. L'instruction s'utilise sans paramètre. Pour rappel, les registres secondaires ne peuvent pas être accédés directement.

#### EX

L'instruction EX sert à échanger deux registres, ou un registre avec une valeur en mémoire. Les combinaisons suivantes sont:

### Instructions de comparaison
#### CP

L'instruction CP est en logique interne une soustraction du registre A qui ne met pas le registre A à jour. Seuls les flags sont positionnés en fonction du résultat de cette soustraction.
Interprétation des flags (avec N qui est reg8, im8 ou (reg16) )
* Si A=N alors Z=1
* Si A!=N alors Z=0
* Si A<N alors C=1
* Si A>=N alors C=0
* Si A-N<0 alors S=1 (bit 7 du résultat copié dans S)
* Si A-N>=0 alors S=0

#### alternatives à CP

Pour certaines comparaisons simples (-1, 0 ou 1) il est possible d'utiliser des instructions plus rapides dont l'usage premier n'est pas la comparaison

#### comparaison 16 bits

Interprétation des flags
* Si HL=DE alors Z=1
* Si HL!=DE alors Z=0
* Si HL<DE alors C=1
* Si HL>=DE alors C=0
* Si HL-DE<0 alors S=1
* Si HL-DE>=0 alors S=0

#### CPI

Cette instruction est une instruction de comparaison groupée. L'instruction est équivalente au pseudo-code suivant:
Si BC=0 après exécution de l'instruction, alors le flag P/V est mis à 0.

#### CPIR

Cette instruction est une répétition de l'instruction CPI tant que BC est plus grand que zéro ou que le registre A est différente de la valeur pointée par HL. Par exemple, pour trouver la première occurrence de A en mémoire, on peut écrire.
* Après exécution le flag P/V est à 0 si on n'a trouvé aucune valeur OU que la valeur est la dernière du tableau. Il faut donc la tester!

#### CPD

Cette instruction est le pendant de l'instruction CPI mais avec une décrémentation de HL.

#### CPDR

Cette instruction est le pendant de l'instruction CPIR mais avec une décrémentation de HL.

### Instructions de saut non conditionnel

sauts inconditionnels sans retour

#### JR

Cette instruction permet d'effectuer un saut relatif, en avant ou en arrière avec une amplitude 8 bits, soit de -128 à 127. Il n'existe pas de version 16 bits de ce saut relatif. Certains assembleurs pourront automatiquement le remplacer par un saut 16 bits absolu mais comme le saut ne sera plus relatif, le code ne pourra s'exécuter correctement que de l'emplacement mémoire prévu à l'assemblage. Les autres assembleurs afficheront une erreur de saut relatif trop long.
* Il existe des versions conditionnelles de ce saut
* Le saut relatif présente l'intérêt d'avoir un micro-code plus compact (2 octets au lieu de 3 pour JP) et de pouvoir charger le programme qui n'utilise que des sauts relatifs, n'importe où en mémoire.

#### JP

Cette instruction permet d'effectuer un saut absolu dans l'espace d'adressage 16 bits. On peut donner en argument un label ou des trois registres suivants: HL,IX,IY
Attention, contrairement à ce que la syntaxe suivante suggère, on utilise bien la valeur du registre et non celle pointée par le registre!
* Il existe des versions conditionnelles du saut JP label
* Avec l'utilisation de saut absolu, l'adresse de chargement et d'exécution d'un programme ne peut pas être modifiée.

#### CALL

Cette instruction effectue un saut absolu dans l'espace d'adressage 16 bits. L'adresse de l'instruction suivante est enregistrée dans la pile. Ainsi le programme appelant peut revenir où il en était avec un RET.
* Il existe des versions conditionnelles de ce saut.

#### RET

L'instruction RET (abréviation de return) effectue un saut à l'adresse lue et retirée du haut de la pile. L'adresse aura été placée auparavant sur la pile typiquement par une instruction d'appel à une sous-routine.
* Il existe des versions conditionnelles de ce saut
sauts inconditionnels avec retour
Équivalentes à un appel de fonction, ces instructions de saut enregistrent dans la pile l'adresse d'appel. Ainsi, le programme appelé peut retourner à l'appelant quand il se termine.

#### RST

Cette instruction est un saut absolu spécifique qui ne peut s'utiliser qu'avec les adresses #00,#08,#10,#18,#20,#28,#30 ou #38. L'adresse de l'instruction suivante est enregistrée dans la pile. Ainsi le programme appelant peut revenir où il en était avec un RET.
* L'instruction RST est essentiellement utilisée pour des appels systèmes, celui-ci étant généralement situé en début de mémoire.
* L'instruction RST est l'instruction de saut la plus compacte et la plus rapide qui soit car elle ne prend qu'un seul octet.

### Instructions de saut conditionnel

Les sauts conditionnels n'effectuent le saut que si la condition est respectée.
sauts sans retour

#### RET

Les instructions de retour de fonction sont des sauts sans retour.
sauts avec retour

#### CALL
#### hack d'instruction: RST #38 conditionnel

Il est possible de réaliser l'équivalent d'un RST Z,#38, d'un RST NZ,#38, d'un RST C,#38 ou enfin d'un RST NC,#38
En effet, l'opcode du RST #38 est #FF
On peut donc faire un RST Z,#38 (les syntaxes conditionnelles du RST #38 sont supportées par Rasm) en écrivant JR Z,$+1 Et par analogie, JR NZ,$+1 ou JR C,$+1 ou JR NC,$+1
Explications: - Si la condition n'est pas remplie, on passe à l'instruction suivante (en 2 nops ou 7 cycles) - Si la condition est remplie, on saute dans l'opcode lui même, sur la donnée qui permet de coder le saut relatif, ici #FF qui est l'opcode du RST #38
L'intérêt est évident, on est plus compact qu'un CALL Z,#38 et surtout beaucoup plus rapide!

### Instructions de sauvegarde des registres dans la pile

Lorsqu'on appelle une sous-routine, on peut avoir besoin de sauvegarder certains registres. Cette sauvegarde peut se faire indifféremment avant l'appel ou après l'appel même si la logique académique veut que ce soit l'appelé qui protège les registres qu'il va modifier.

#### POP l'ordre est inversé par rapport a push

Il n'est pas possible d'écrire ou de lire le registre de pile dans la pile. Mais on peut le faire de façon indirecte (voir chapitre programmation avancée).
Il existe des instructions pour le registre PC mais on leur a donné d'autres noms

#### pour aller plus loin

Le Z80 ayant un bus de donnée 8 bits, il ne peut réaliser l'écriture ou la lecture mémoire 16 bits qu'en deux fois. Lors du PUSH, on descend dans la mémoire c'est donc logiquement l'octet de poids faible qui est écrit en premier, suivi de l'octet de poids fort. À l'opposé, lors d'une lecture mémoire 16 bits avec le POP, c'est l'octet de poids fort qui est lu en premier, suivi de l'octet de poids faible. Ceci peut avoir une incidence sur le matériel qui décode des valeurs 16 bits.

### Instructions de modification de bit

On peut tester, effacer ou positionner chaque bit individuellement d'un registre ou d'un octet en mémoire avec ces opérations.

#### SET

L'instruction SET sert à positionner à 1 n'importe quel bit d'un registre ou d'un octet en mémoire.
* n est le numéro de bit à traiter, valeur de 0 à 7 avec 0 pour le bit le moins significatif.
* L'instruction ne modifie pas les flags

#### RES

L'instruction RES (abréviation de reset) sert à effacer n'importe quel bit d'un registre ou d'un octet en mémoire.
* n est le numéro de bit à traiter, valeur de 0 à 7 avec 0 pour le bit le moins significatif.
* L'instruction ne modifie pas les flags

#### BIT

L'instruction BIT sert à tester n'importe quel bit d'un registre ou d'un octet en mémoire. La valeur du bit est copié dans le flag Z, qui peut ensuite être utilisé dans une instruction conditionnelle.
* n est le numéro de bit à traiter, valeur de 0 à 7 avec 0 pour le bit le moins significatif.
* Si le bit testé est à zéro, alors le flag Z=1
* Si le bit testé est à un, alors le flag Z=0

#### super instruction avec copie du résultat dans un autre registre

Cette instruction possède un mode d'exécution qui copie le résultat dans un autre registre. La syntaxe a alors besoin de deux opérandes. Seuls les assembleurs Rasm et Sjasm les supportent.
Les combinaisons possibles de registres sont:
On retrouve les mêmes combinaisons pour le registre IY, les instructions SET et RES.

### Instructions de décalage et rotations de bit

Pour faciliter la navigation dans les instructions de décalage, voici un petit récapitulatif visuel des instructions de décalage les plus courantes.
De façon générale, toutes ces instructions modifient les flags de la façon suivante:
* flag S si le résultat est négatif (supérieur à 127)
* flag Z si le résultat est zéro
* flag P qui contient la parité des bits du résultat
* flag C qui contient le bit "sorti" du résultat
* flag H et N remis à zéro

#### SLL (SL1)

* L'instruction SLL réalise un décalage de l'opérande vers la gauche d'un bit et injecte la valeur 1 dans le bit 0. On peut la trouver aussi sous la syntaxe SL1.
* Cette instruction fait partie des instructions qui ont été documentée plus tard par Zilog, c'est pourquoi peu d'assembleurs les supportent à part Rasm et Sjasm.
* Cette instruction possède un mode d'exécution qui copie le résultat dans un autre registre. La syntaxe a alors besoin de deux opérandes. Là encore, seuls Rasm et Sjasm les supportent.
Combinaisons possibles en mode simple:
Combinaisons possibles en mode groupé:
* Note: Le registre destination contiendra la valeur du décalage même si l'adresse pointée par IX ou IY est en ROM. Dans ce cas de figure, la valeur est lue dans la ROM, le décalage est effectué dans un registre interne du Z80, puis il est copié dans le registre destination. Enfin, la valeur est écrite à l'adresse pointée par IX ou IY +dep8. Si l'adresse pointe sur une ROM active, alors la valeur sera écrite dans la mémoire située en arrière-plan de la ROM.

#### RLD

Ce décalage très particulier impacte le registre A ainsi que l'adresse pointée par HL.
Il effectue une rotation de 4 bits vers la gauche sur le nombre 12 bits composé des 4 bits de poids faible de A et de (HL).
Les 4 bits supérieurs du registre A sont inchangés, il peut être nécessaire d'initialiser à zéro le registre avant usage.
Usage: Cette instruction trouve ses origines dans l'arithmétique BCD et permet par exemple de multiplier par 10 très facilement un nombre BCD de n'importe quelle taille. Comme elle modifie l'octet pointé par HL, il faut faire attention à son usage dans le cadre unique de la lecture.
Effet sur les flags:
* H et N à zéro
* P/V est la parité
* S et Z modifiés par définition
* C n'est pas modifié

#### RRD

RRD est le pendant de l'instruction RLD. Il impacte le registre A ainsi que l'adresse pointée par HL.
Il effectue une rotation de 4 bits vers la droite sur le nombre 12 bits composé des 4 bits de poids faible de A et de (HL).
Effet sur les flags:
* H et N à zéro
* P/V est la parité
* S et Z modifiés par définition
* C n'est pas modifié

#### Décalage 16 bits

Il est possible de réaliser des décalages 16 bits vers la gauche de façon native en utilisant l'addition.
Pour faire un décalage équivalent à SLL il est nécessaire de décomposer
ou bien
On peut réaliser des décalages 16 bits sur les autres registres, toujours en décomposant (exemples pour le registre DE):
SLA DE devient
RL DE devient
SLL DE devient

### Instructions logiques de base

Les opérations logiques de base concernent uniquement le registre A. Il n'existe pas de version 16 bits de ces opérations.

#### AND

Effectue un ET logique sur le registre A.
* C et N sont effacés
* flag H positionné à 1
* P/V est la parité de bits du résultat
* Z=1 si le résultat est nul
* S=1 si le résultat est négatif
Rappel de la logique booléenne

#### OR

Effectue un OU logique sur le registre A.
* C, H et N sont effacés
* P/V est la parité de bits du résultat
* Z=1 si le résultat est nul
* S=1 si le résultat est négatif
Rappel de la logique booléenne

#### XOR

Effectue un OU exclusif logique sur le registre A.
* C, H et N sont effacés
* P/V est la parité de bits du résultat
* Z=1 si le résultat est nul
* S=1 si le résultat est négatif
Rappel de la logique booléenne

#### CPL

Effectue le complément à un du registre A (inverse tous les bits). Rappel de la logique booléenne

#### NEG

Le registre A devient A soustrait de zéro (inverse le signe mathématique).

#### SCF

Cette instruction met à 1 le flag C et remet à zéro les flags H et N. Les autres flags ne sont pas modifiés.

#### CCF

Cette instruction inverse les flags C et H. Le flag N est mis à zéro. Les autres flags ne sont pas modifiés.

### Instruction de traitement des nombres en base 10
#### DAA

Cette instruction sert à ajuster la valeur d'un octet quand on s'en sert comme si il contenait deux chiffres décimaux. Les 4 bits du haut et les 4 bits du bas sont supposés contenir chacun une valeur de 0 à 9. Ainsi, quand on réalise des additions ou des soustractions, on appelle l'instruction DAA pour corriger les retenues à effectuer sur le registre.
Le fonctionnement de l'instruction est le suivant:
* Si les 4 bits les moins significatifs de A contiennent un nombre plus grand que 9 ou que le flag H=1, alors on ajoute #06 au registre A.
* Si les 4 bits les plus significatifs de A sont aussi supérieurs à 9 ou que le flag C=1, alors on ajoute #60 au registre A et on positionne éventuellement la retenue pour le calcul suivant.
Quelques exemples d'exécution de l'instruction DAA:
| LD A,valeur | ADD A,valeur | Résultat de l'addition | Valeur de A après DAA | flag C |
| #55 | #11 | #66 | #66 (55+11=66) | 0 |
| #59 | #12 | #6B | #71 (59+12=71) | 0 |
| #90 | #10 | #A0 | #00 (90+10=100) | 1 |
| #99 | #01 | #9A | #00 (99+1=100) | 1 |
La retenue (flag C) est mise dès lors qu'on dépasse la valeur 99. Il faut la reporter sur l'octet BCD suivant.

### Instructions mathématiques de base
#### INC

Cette instruction incrémente le registre spécifié en opérande de 1.
Effet de l'incrémentation 8 bits sur les flags
* Le flag C n'est pas modifié!
* H=1, N=0
* P/V parité des bits du résultat
* Z est mis à 1 si le résultat est zéro
* S est mis à 1 si le résultat est négatif
Effet de l'incrémentation 16 bits sur les flags
* Aucun flag n'est modifié

#### DEC

Cette instruction décrémente le registre spécifié en opérande de 1.
Effet de la décrémentation 8 bits sur les flags
* Le flag C n'est pas modifié!
* H=1, N=1
* P/V parité des bits du résultat
* Z est mis à 1 si le résultat est zéro
* S est mis à 1 si le résultat est négatif
Effet de la décrémentation 16 bits sur les flags
* Aucun flag n'est modifié

#### ADD

Cette instruction réalise une addition dont le résultat est stocké dans la première opérande. Les combinaisons possibles sont les suivantes:
Effet sur les flags en addition 8 bits
* flag N est mis à zéro
* P/V est interprété comme dépassement de donnée
* flag Z mis à 1 si le résultat est zéro
* flag C mis à 1 si le résultat déborde
* flag S mis à 1 si le résultat est négatif
Effet sur les flags en addition 16 bits
* flag H est indéfini
* P/V, S et Z ne sont pas modifiés
* flag C mis à 1 si le résultat déborde
Attention: Comme l'addition se fait en interprétant les nombres négatifs comme des nombres positifs, la notion de débordement est toute relative. Ainsi, soustraire un nombre plus petit à un autre (en additionnant -100 à 101 par exemple) va positionner la retenue tandis qu'additionner -100 à 99 ne la positionnera pas. Quand on transpose les valeurs négatives en nombres positifs, le positionnement des flags fait sens.
Note On peut écrire de façon raccourcie l'addition 8 bits sans mentionner le registre A

#### SUB

Cette instruction réalise une soustraction dont le résultat est stocké dans la première opérande. Le registre destination est toujours A. Les combinaisons possibles sont les suivantes:
Effet sur les flags
* flag N est mis à 1
* P/V à 1 si dépassement
* flag C à 1 si retenue
* flag Z à 1 si le résultat est zéro
* flag S mis à 1 si le résultat est négatif
Note On peut écrire de façon raccourcie la soustraction 8 bits sans mentionner le registre A

#### ADC

Cette instruction réalise une addition avec ajout de la retenue contenue dans le flag C. Le résultat est stocké dans la première opérande qui est soit A, soit HL. Les combinaisons possibles sont les suivantes:
Effet sur les flags
* Le flag N est mis à zéro
* P/V est mis à 1 en cas de dépassement
* Le flag Z est mis à 1 si le résultat est nul
* Le flag C est mis à 1 en cas de retenue
* Le flag S est mis à 1 si le bit 15 est à 1 (valeur qui peut être considérée comme négative)
Note: On peut écrire de façon raccourcie l'addition 8 bits sans mentionner le registre A

#### SBC

Cette instruction réalise une soustraction en tenant compte de la retenue contenue dans le flag C. Le résultat est stocké dans la première opérande qui est soit A, soit HL. Les combinaisons possibles sont:
Effet sur les flags
* Le flag N est mis à 1
* P/V est mis à 1 en cas de dépassement
* Le flag Z est mis à 1 si le résultat est nul
* Le flag C est mis à 1 en cas de retenue
* Le flag S est mis à 1 si le bit 15 est à 1 (valeur qui peut être considérée comme négative)
Note: On peut écrire de façon raccourcie la soustraction 8 bits sans mentionner le registre A

### Instructions de copie mémoire

Si il est possible de copier la mémoire à partir d'instructions simples, le Z80 offre plusieurs instructions de copie de blocs avec ou sans répétition. Ces super-instructions ont deux avantages:
* Le premier est de pouvoir utiliser BC comme compteur 16 bits et de tester si BC est égal à zéro pour la répétition.
* Le temps d'exécution de cette super instruction est deux fois plus rapide que de décomposer en instructions simples.

#### LDI

Cette instruction exécute la copie mémoire d'un octet de (HL) vers (DE), puis incrémente HL,DE et décrémente BC.
* Le flag P/V est mis à zéro quand BC=0

#### LDIR

Cette instruction exécute la copie mémoire de la même façon que LDI, tant que BC est supérieure à zéro.
* Le flag P/V est mis à zéro quand l'opération LDIR est terminée
* HL et DE auront été incrémenté de BC
* BC vaut toujours zéro en fin d'exécution
Le pseudo-code de cette instruction est le suivant:

#### LDD

Cette instruction est similaire à LDI, si ce n'est que les pointeurs mémoire HL et DE sont décrémentés.

#### LDDR

Cette instruction est similaire à LDIR, si ce n'est que les pointeurs mémoire HL et DE sont décrémentés.

### Instructions d'entrée/sortie

Il est possible de lire ou d'écrire sur un port mémoire. Cette section ne sera pas détaillée car les opérations d'entrée/sortie sont spécifiques au matériel avec lequel est connecté le Z80. Pour la petite anecdote, sur l'Amstrad CPC, les ingénieurs ont inversés les bits de poids fort avec les bits de poids faible du port d'entrée/sortie par économie, rendant inutilisables toutes les fonctions entrée/sortie de répétition qu'offre le Z80. Le processeur Z80 est conçu pour un design qui utilise le port pointé par le registre C alors qu'Amstrad a créé un design qui utilise le registre B pour pointer le port. Comme les instructions de répétition utilisent le registre B comme compteur, il faut pouvoir réajuster le registre B à chaque itération.

#### OUT

Le OUT est l'instruction élémentaire pour envoyer une donnée sur un port I/O. Elle ne s'utilise qu'avec les registres 8 bits non spéciaux.

#### OUTI

Cette instruction est une instruction groupée d'envoi de donnée depuis le tableau pointé par HL avec une post-incrémentation.
Il est important de noter que le registre B est décrémenté AVANT d'envoyer la valeur de (HL) sur le port comme on peut le lire dans beaucoup d'ouvrages. L'ordre a une importance car comme sur l'Amstrad le port de sortie est le port B, si on veut envoyer une valeur sur le port B, il faut la pré-incrémenter!
* Le flag P/V est mis à zéro si BC vaut zéro après l'appel à OUTI.

#### OTIR

Cette instruction répète le OUTI tant que B est supérieur à zéro.
* Le flag P/V est mis à zéro en fin d'itération.

#### OUTD

Cette instruction est une instruction groupée d'envoi de donnée depuis le tableau pointé par HL avec une post-décrémentation.
Il est important de noter que le registre B est décrémenté AVANT d'envoyer la valeur de (HL) sur le port comme on peut le lire dans beaucoup d'ouvrages. L'ordre a une importance car comme sur l'Amstrad le port de sortie est le port B, si on veut envoyer une valeur sur le port B, il faut la pré-incrémenter!
* Le flag P/V est mis à zéro si BC vaut zéro après l'appel à OUTI.

#### OTDR

Cette instruction répète le OUTD tant que B est supérieur à zéro.
* Le flag P/V est mis à zéro en fin d'itération.

#### IN

C'est l'instruction élémentaire pour lire une valeur sur le port I/O. Elle ne s'utilise qu'avec les registres 8 bits non spéciaux.
Les flags sont modifiés en fonction du résultat renvoyé:
* flag S si la valeur lue est négative
* flag Z si la veleur lue est zéro
* flag P si le total des bits de la valeur lue est pair

#### INI

Cette instruction est une instruction groupée de récupération de donnée vers le tableau pointé par HL avec une post-incrémentation.
* N=1
* flag Z positionné si B vaut zéro après décrémentation

#### INDR
### Instructions de gestion des interruptions
#### DI

Cette instruction (Disable Interruptions) désactive toutes les interruptions masquables.

#### EI

Cette instruction (Enable Interruptions) active le déclenchement des interruptions après l'instruction suivante. La précision à propos de l'instruction suivante est importante. En effet, lorsqu'une routine appelée par interruption se termine, il faut autoriser à nouveau les interruptions (sinon elles ne se déclencheront plus). Mais il est tout à fait possible que pendant le déroulement de la fonction sous interruption, une autre interruption soit survenue. L'interruption est donc en attente et se déclenchera dès lors que les interruptions seront à nouveau autorisées. Nous avons vu que le déclenchement d'une interruption saute à une adresse définie par le mode d'interruption ET que l'adresse interrompue est enregistrée dans la pile. Si l'autorisation des interruptions est immédiatement consécutive à l'instruction EI, il ne serait pas possible de revenir au programme interrompu avant qu'une interruption en attente se déclenche. La conséquence serait un empilement d'adresses de retour dans la pile et un écrasement progressif de la mémoire, jusqu'à ce que la pile déborde sur la routine sous interruption. C'est pour cette raison qu'après un EI, le Z80 exécute UNE instruction supplémentaire avant d'autoriser à nouveau les interruptions. L'usage classique en retour d'interruption est le suivant :

#### IM

Cette instruction (Interruption Mode) permet de choisir le mode d'interruption du Z80 parmi 3 modes. Par défaut, le Z80 démarre en mode 0.
Mode 0
Ce mode de fonctionnement indique que les interruptions sont générées par un matériel externe. Le Z80 exécute une instruction dont l'opcode aura été envoyé par le matériel sur le bus de données. En théorie, l'instruction de saut serait un RST. Ce mode a été très peu utilisé sur les ordinateurs.
Mode 1
Fonctionnement par défaut de la plupart des ordinateurs utilisant le Z80, le processeur exécute un saut à l'adresse #38. Sur un Amstrad CPC, les interruptions sont générées par une puce vidéo tous les 300$^{èmes}$ de seconde (soit 52 lignes vidéo). Sur un ZX Spectrum, les interruptions sont aussi générées en corrélation avec le contrôleur vidéo mais tous les 50$^{èmes}$ de seconde (fréquence de rafraîchissement à 50 Hz) lors de la VBL (synchro verticale : Vertical BLanking). Sur les calculatrices TI, le nombre d'interruptions dépend apparemment de l'état de la batterie (autour d'une centaine par seconde).
Mode 2
Le mode 2 est un mode d'interruption vectorisé. Le Z80 récupère un numéro d'interruption sur le bus de données avec lequel il forme l'octet de poids faible d'une adresse. L'octet de poids fort de l'adresse est contenu dans le registre I. À l'adresse (toujours paire) pointée par la valeur 16 bits I<int>, le Z80 va lire une adresse 16 bits à laquelle il va sauter.

#### HALT

Cette instruction boucle en continu jusqu'au déclenchement d'une interruption. On se sert du HALT pour se synchroniser de façon précise sur une interruption. Quand on n'utilise pas de HALT, le saut à l'interruption ne peut se faire qu'après la fin de l'exécution de l'instruction en cours. Si cette instruction est longue, le déclenchement de l'interruption est retardé de quelques cycles d'horloge, ce qui peut être rédhibitoire si on a besoin d'une grande précision (typiquement programmation au vol de la puce vidéo).

#### RETI

Cette instruction sert à acquitter les interruptions à des périphériques hardware en fin de routine.
Il est indispensable de précéder l'instruction avec EI pour que les interruptions puissent se déclencher à nouveau, sinon l'interruption de la carte matérielle restera masquée jusqu'au prochain EI.
En effet, le déclenchement d'une interruption (exceptée NMI) met le flag à 0 (les deux copies internes IFF1 et IFF2 du processeur), comme un appel explicite à l'instruction DI.
Un appel explicite à EI remet les deux copies IFF1 et IFF2 à 1, mais le processeur ne permettra une interruption qu'après l'instruction suivante (RETI dans ce cas) afin qu'une interruption n'empêche pas son exécution.
Dans le cas d'une NMI (Non Maskable Interrupt), seul le flag IFF1 est mis à 0. La routine de traitement de cette interruption n'est pas obligée d'utiliser l'instruction EI, car les instructions RETN et RETI copient la valeur de IFF2 dans IFF1.

#### RETN

Cette instruction sert à acquitter une interruption non masquable en fin de routine. Tant que cette instruction n'est pas exécutée, les interruptions non masquables sont en attente.
RETN ou RETI ? Les deux instructions sont équivalentes. Cependant, RETI est l'alias officiel reconnu par les périphériques pour détecter la fin de traitement d'une interruption. Quand un périphérique voit passer le code de l'instruction RETI sur le bus de données, il sait qu'il peut retenter de déclencher une interruption.

#### LD I,A

C'est la seule instruction qui permet de modifier le registre I. Le registre I indique le poids fort de l'adresse de la table de saut à exécuter lors des interruptions en mode IM 2.

### Instruction qui ne fait rien
#### NOP

Oui, il existe une instruction qui ne fait... ...rien! C'est l'instruction NOP pour No OPeration ou pas d'opération. En fait cette instruction peut jouer un rôle quand on a besoin d'une synchronisation précise. On ajoute des NOP pour créer un délai. Cette instruction ne modifie aucun registre (autre que PC qui passe à l'instruction suivante) et aucun flag. Son opcode #00 est simple à retenir.
Il existe d'autres opcodes qui ne font rien. Ce sont les opcodes non utilisés par le Z80. Comme ils ne sont pas décodés, le Z80 ne fera rien non plus mais ce genre d'utilisation est à éviter, pour préserver la compatibilité ascendante de versions plus évoluées du Z80.