Aller au contenu

Programmation Assembleur Z80/Assembler

Un livre de Wikilivres.

Assembler un programme

[modifier | modifier le wikicode]

Les directives

[modifier | modifier le wikicode]

Pour 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.

Cette 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

Cette 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

[modifier | modifier le wikicode]

Il 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

[modifier | modifier le wikicode]

Le 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'

Afin 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

[modifier | modifier le wikicode]

Macro assemblage

[modifier | modifier le wikicode]

Les répétitions

[modifier | modifier le wikicode]

Il 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 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

[modifier | modifier le wikicode]

Les labels locaux

[modifier | modifier le wikicode]

Dans 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