Triceraprog
La programmation depuis le Crétacé

Des outils pour programmer en assembleur sur VG5000µ ()

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 Boujour ! à 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.

Ouverture du fichier binaire comme du texte

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=VAL(A$):POKE S,A
50 S=S+1
60 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.