La dernière fois, j'avais évoqué le logiciel d'assemblage, ou assembleur comme étant le programme permettant de passer d'un programme sous sa forme source, c'est-à-dire écrite sous forme lisible par un humain, dans une forme binaire, qui sera plus exactement nommée forme objet. C'est cette forme qui pourra être exécutée par la machine.
Pour programmer, quel que soit la forme que revêt cette programmation, on a besoin d'outils. Les outils primaires peuvent être une table de référence, des manuels, un stylo, des feuilles et beaucoup de patience. Rapidement, le besoin d'outils pour effectuer les tâches automatiques et répétitives qui forment la transformation d'un programme source en programme objet se fait sentir. Et quoi de mieux pour traier des tâches automatiques et répétitives de transformation qu'un... ordinateur.
Le problème de la poule et de l'œuf n'est pas le sujet ici. Le principal est qu'à l'heure de l'écriture de cet article, il y a des outils utilisables sur un ordinateur actuel pour travailler plus facilement sur les ordinateurs plus anciens qui m'intéressent ici.
Pour le processeur Z80, il y a le choix. Mais comme du travail a déjà été fourni pour le VG5000µ, autant s'en servir. Et c'est vers la suite d'outils z88dk que je vais me tourner. Cette suite contient bien plus qu'un assembleur Z80 et j'en ferai un petit tour par la suite. Mais pour le moment, ce qui m'intéresse, c'est l'assembleur.
Outil de listing
Pour voir en quoi un assembleur peut nous aider, commençons par un test simple. Tout d'abord, j'écris le programme de l'article précédent dans un fichier hello.asm
. Pour rappel, ce programme affichait Bonjour ! à l'écran avec les commandes suivantes :
ORG $7000 ; Spécification de l'adresse mémoire d'implentation
PUSH AF ; Sauvegarde des registres sur la pile
PUSH BC
PUSH DE
PUSH HL
; Le cœur du programme :
LD HL, chaine ; Chargement de l'adresse du texte dans le registre HL
CALL $36AA ; Puis appel de la routine d'affichage de chaîne de caractères.
POP HL ; Restauration des registres depuis la pile
POP DE
POP BC
POP AF
RET ; Retour au programme appelant
chaine:
DEFB "Bonjour !", 0
Dans un terminal, j'exécute la commande suivante : z80asm -l hello.asm
et j'obtiens très rapidement un nouveau fichier, hello.lis
avec le contenu suivant :
1 0000 ORG $7000
2 0000
3 0000 F5 PUSH AF
4 0001 C5 PUSH BC
5 0002 D5 PUSH DE
6 0003 E5 PUSH HL
7 0004
8 0004 21 0F 00 LD HL, chaine
9 0007 CD AA 36 CALL $36AA
10 000A
11 000A E1 POP HL
12 000B D1 POP DE
13 000C C1 POP BC
14 000D F1 POP AF
15 000E
16 000E C9 RET
17 000F chaine:
18 000F 42 6F 6E 6A 6F 75 72 20 21 00
DEFB "Bonjour !", 0
19 0019
Ce fichier listing est constitué en première colonne d'un numéro de ligne, en seconde colonne d'une adresse mémoire relative au début du fichier, dans la colonne suivante de valeurs hexadécimales correspondant au résultat de l'assemblage, autrement dit au langage machine, puis enfin vient le contenu du programme source.
C'est donc un mélange de code source et d'une représentation lisible du code objet. Pratique pour suivre le résultat de la compilation simplement. Mais pas pratique pour essayer de lancer le programme sur la machine cible. Ce format est fait pour être lisible par un humain.
Création d'un binaire
Pour être adapté à la machine, par exemple en utilisant le programme de chargement en BASIC utilisé précédemment, j'ai besoin d'une forme qui ne contient que les octets indiqués dans le listing, sans tous les commentaires. J'ai besoin d'une seconde chose : que le programme soit logé à l'adresse mémoire que j'ai indiqué avec ORG $7000
.
En effet, le listing ci-dessus a été produit avec des adresses commençant à l'adresse mémoire 0
. Sur un VG5000µ, comme dans tous les ordinateurs à base de Z80, c'est un emplacement de ROM, une zone dans laquelle je ne pourrai pas écrire ce programme. J'avais donc indiqué une autre zone mémoire précise pour implenter le programme.
Appartée : à cause des instructions que j'ai utilisé, c´est une indication obligatoire. L'instruction LD HL, chaine
est une instruction qui prend une adresse de manière absolue. La chaîne de caractère doit donc se trouver à un endroit connu et absolu en mémoire. Mon programme n'est pas relogeable. Si je n'avais utilisé que des instructions adressant la mémoire de manière relative, c'est-à-dire toujours sous forme d'une distance à partir de l'instruction courante, alors le programme aurait été relogeable, et l'adresse d'implentation n'aurait pas été importante. Faire des programmes relogeables sur Z80 n'est pas si simple, et même si z80asm
peut aider cela sort du cadre de l'article.
Voyons ce que produit cette autre commande : z80asm -b hello.asm
. Cette fois, c'est une fichier hello.bin
que j'obtiens. Et si j'essaie de l'ouvrir comme un fichier texte, je n'obtiens rien de franchement lisible, à part la chaîne de caractères Bonjour ! à la fin.
Cependant, la taille du fichierest de 25 octets et c'est exactement le nombre de données hexadécimales indiqué dans le listing obtenu plus tôt. C'est aussi le nombre d'octets dans le chargeur en BASIC utilisé à l'article précédent.
Si je regarde le contenu de ce fichier avec un outil qui permet d'afficher le contenu de fichier sous forme hexadécimale, j'obtiens bien la même chose.
00000000 f5 c5 d5 e5 21 0f 70 cd aa 36 e1 d1 c1 f1 c9 42 |....!.p..6.....B|
00000010 6f 6e 6a 6f 75 72 20 21 00 |onjour !.|
Une utilisation possible est alors de transférer le contenu de ce fichier sous forme de DATA dans un chargeur en BASIC et voilà.
Par exemple, avec un petit script écrit en Python 3, cela pourrait donner ça :
basic = """10 S=&"7000"
20 READ A$
30 IF A$="FIN" THEN END
40 A$="&"+CHR$(34)+A$+CHR$(34):A=VAL(A$)
50 POKE S,A
60 S=S+1
70 GOTO 20
300 DATA {0}
400 DATA FIN"""
with open('hello.bin', 'rb') as f:
content = f.read()
data = [hex(d)[2:].upper() for d in content]
data = ",".join(data)
print(basic.format(data))
C'est un script assez limité, sans protection au niveau de la taille du programme, ce qui pourrait générer un trop grand nombre de DATA
, mais cela peut être utile pour, par exemple... écrire des articles avec des petits bouts de programmes à copier/coller dans un émulateur facilement.
Cependant, cela reste très manuel et ce n'est pas très satisfaisant. Nous verrons donc dans l'article suivant comment aller plus loin en utilisant les outils à disposition et se faciliter la vie.