Programmation Assembleur Z80/Assembler
Assembler un programme
modifierLes directives
modifierPour pouvoir assembler un programme, il suffit rarement d'écrire les quelques lignes d'assembleur pour avoir un programme fonctionnel. En général, il faut préciser son adresse d'exécution afin de renseigner correctement les sauts absolus ou la localisation des variables mémoire. Il est alors nécessaire d'utiliser des directives, qui ne sont pas des instructions Z80 mais des ordres indicatifs afin que l'assembleur sache exactement quoi faire de notre programme. La plupart des assembleurs utilisent les mêmes directives mais il y aura des adaptations nécessaires selon celui que vous utilisez. Parmi toutes les directives, les plus essentielles sont celles qui permettent de réserver de l'espace en mémoire pour y mettre des variables ou valeurs.
DEFB
modifierCette directive est l'abréviation de Define Byte. Elle a pour usage de réserver un ou plusieurs octets. Ces octets peuvent être écrits sous forme texte ou de valeurs litérales.
DEFB 0 ; un octet de valeur 0 DEFB 1,2,3 ; trois octets de valeurs respectives 1,2 et 3 DEFB 'bonjour' ; 7 octets de valeur ascii correspondant aux lettres du mot bonjour. Il n'y a pas de code terminateur ajouté comme dans d'autres langages. DEFB 5,'coucou',18 ; on peut mélanger les déclarations
DEFW
modifierCette directive déclare un mot (Word) de 16 bits. On ne peut pas utiliser de texte (sauf une lettre unique entre quote) avec cette instruction. Par contre, on peut y mettre la valeur d'un label sans risquer le débordement.
DEFW 5 DEFW monlabel
Portée du programme
modifierIl est impératif de se poser quelques questions avant d'assembler un programme, les voici:
- Mon programme doit-il rendre la main après exécution?
Si le programme est susceptible revenir au système, il est impératif de sauvegarder tous les registres qui seront modifiés et de restaurer les interruptions si celles-ci sont modifiées. Si le programme ne revient pas au système, il n'y a rien à prévoir.
- Mon programme a-t'il besoin du système?
Si le programme a besoin du système, il est impératif qu'il s'exécute dans une zone mémoire disponible et qu'il n'altère pas les zones système. Si le programme n'a pas besoin du système ET qu'il n'a pas besoin de rendre la main, alors on peut se positionner où l'on veut en mémoire et écraser toute la mémoire au besoin.
Choisir l'emplacement du programme et des données en mémoire
modifierORG
modifierLe choix de l'adresse d'assemblage se fait avec la directive ORG
ORG #8000 ; commencer à assembler à l'adresse #8000 JR $ ; boucle infinie sur lui même
On peut utiliser autant de ORG que l'on veut dans un programme, afin de positionner facilement des données à différents endroits de la mémoire. Dans l'exemple ci-dessous
ORG #8000 LD HL,machaine ; charge l'adresse de machaine dans HL JR $ ; boucle infinie sur lui même ; ORG #9000 machaine DEFB 'premier programme'
ALIGN
modifierAfin de réaliser des optimisations d'accès mémoire, on peut vouloir aligner des données sur des adresses paires, multiples de 16, 32, 55, etc. ou plus pragmatiquement 256. La directive ALIGN va ajouter des octets vides jusqu'à pointer sur une adresse multiple de la valeur d'alignement souhaitée.
ALIGN 2 DEFW maroutine1 DEFW maroutine2 DEFW maroutine3
L'intérêt de l'alignement est d'utiliser des instructions plus rapides lors de la lecture des données en mémoire. Si on stocke des valeurs 16 bits sur des adresses paires, on sait qu'il n'est pas utile de faire une incrémentation 16 bits du pointeur pour aller chercher le deuxième octet de la valeur, car une incrémentation 8 bits ne débordera jamais.
Assembler à une adresse différente de celle d'exécution
modifierMacro assemblage
modifierLes répétitions
modifierIl est courant d'avoir à répéter des instructions ou déclarations dans un programme. Pour s'éviter de longs et indigestes copié-collés, la directive REPEAT est d'un grand secours.
REPEAT 32 ; répéter 32 fois la séquence PUSH DE ; code à répéter REND ; marqueur de fin de boucle de répétition
Les blocs de REPEAT peuvent s'imbriquer. Dans l'exemple ci-dessous on déclarera 256 octets de valeur 2
REPEAT 8 REPEAT 8 DEFB 2 REND REND
Les variables
modifierLes variables d'assemblage sont des variables ou valeurs qui ne seront pas intégrées au binaire final, bien qu'elles puissent aider à générer ce dernier. Un label est une variable (qui ne change pas au cours de l'assemblage). Le label indique une adresse afin de pouvoir calculer des sauts absolus ou relatifs. Une variable sert à la même chose, à ceci près qu'on peut la faire évoluer dans le temps. Les variables trouvent aussi leur utilité pour réaliser du code modulaire. On peut construire son code à partir de la valeur d'une variable et changer le code en modifiant cette valeur.
Exemple de déclaration d'une table de sinus
angle=0 ALIGN 256 REPEAT 256 DEFB sin(angle)*127 angle=angle+360/256 REND
Le code conditionnel
modifierLes macros
modifierLes labels locaux
modifierDans une boucle de répétition de code, si on écrit un label, l'assemblage tombera en erreur car le label sera déclaré plusieurs fois. Il est possible de déclarer un label local. C'est à dire que ce label ne peut être appelé que lors de l'itération courante de la boucle. Un label local est préfixé par le symbole '@' (Avec l'assembleur de Winape ou RASM).
Par exemple, si on veut factoriser le code suivant avec une boucle REPEAT:
ADD HL,BC JR NC,saut1 INC DE saut1 ADD HL,BC JR NC,saut2 INC DE saut2
Le rôle du label local est exactement de numéroter 1,2,3 le label, mais de façon transparente, c'est à dire qu'au niveau de l'écriture, tout est transparent:
REPEAT 2 ADD HL,BC JR NC,@saut INC DE @saut REND