Dec 22, 2023
Une langue d’assemblage alphabétisée
Une édition récente de [Babbage] The Chip Letter discute de l'obscurité du langage assembleur. Il souligne, et je pense à juste titre, que le langage assembleur est plus souvent lu qu'écrit, mais presque
Une édition récente de [Babbage] The Chip Letter discute de l'obscurité du langage assembleur. Il souligne, et je pense à juste titre, que le langage assembleur est plus souvent lu qu'écrit, mais presque tous sont gênés par l'obscurité qui reste de l'époque où les cartes perforées avaient 80 colonnes et où un symbole de six lettres était tout ce que vous pouviez gérer. dans l'espace mémoire limité de l'ordinateur. Par exemple, sans chercher, que fait l'instruction ARM FJCVTZS ? Le nom complet de l'instruction est Conversion Javascript à virgule flottante en arrondi à virgule fixe signé vers zéro. Pas très utile.
Mais il m'est venu à l'esprit que rien ne vous empêche d'écrire un assembleur compétent et conçu pour être plus facile à lire. Premièrement, la plupart des compilateurs C acceptent une sorte d’instruction asm, et vous pourriez probablement gérer cela avec la construction de chaînes et les macros au moment de la compilation. Cependant, je pense qu'il existe une meilleure possibilité.
Comme je développe parfois de nouvelles architectures de CPU, j'ai un assembleur croisé universel qui est, honnêtement, un vilain hack, mais qui fonctionne plutôt bien. J'en ai déjà parlé, mais si vous ne voulez pas lire l'intégralité de l'article à ce sujet, il utilise quelques astuces simples pour convertir les formats de langage assembleur d'apparence standard en code C qui est ensuite compilé. L'exécution du programme résultant génère le langage machine souhaité dans un format de fichier souhaité. C'est très simple à mettre en place, et au milieu, il y a un joli programme C qui émet du code machine. Ce n'est pas beaucoup plus lisible que l'assemblage brut, mais vous ne devriez pas avoir à le voir. Mais et si nous commencions le processus par là et rendions le format lisible ?
Au cœur du système se trouve un programme C qui réside dans soloasm.c. Il gère les options de ligne de commande et la génération de fichiers de sortie. Il appelle une fonction externe, genasm, avec un seul argument entier. Lorsque cet argument est défini sur 1, cela indique que l'assembleur en est à sa première passe et qu'il vous suffit de remplir les valeurs d'étiquette avec des nombres réels. Si la réussite est un 2, cela signifie remplir le tableau qui contient le code.
Ce tableau est défini dans l'instruction __solo_info (soloasm.h). Il comprend la taille de la mémoire, un pointeur vers le code, la taille des mots du processeur, les adresses de début et de fin et un indicateur d'erreur. Normalement, le système convertit votre entrée en langage assembleur en un ensemble d'appels de fonction qu'il écrit dans la fonction genasm. Mais dans ce cas, je souhaite réutiliser soloasm.c pour créer un langage assembleur compétent.
J'ai écrit tout cela il y a longtemps, mais je voulais que la création d'un assemblage alphabétisé soit plus facile, j'ai donc décidé de faire une conversion sans effort en C++. Cela vous permet d'utiliser de belles structures de données pour la table des symboles, par exemple. Cependant, je n'ai pas utilisé toutes les fonctionnalités C++ dont je pouvais disposer, simplement par souci de temps.
La classe de base est raisonnablement indépendante du processeur et, à titre d'exemple, j'ai fourni un assembleur RCA 1802 compétent. Juste une preuve de concept, donc je pourrais probablement nommer les instructions de manière un peu plus cohérente, et il y a beaucoup de place pour d'autres améliorations, mais cela fait passer mon message.
Voici un extrait d'un programme de lumière clignotante écrit pour le 1802 en utilisant la syntaxe assembleur standard :
Voici maintenant exactement la même chose écrite pour l'assembleur compétent :
Bon, certes, il y a des commentaires et des symboles, mais quand même. Vous pouvez télécharger les deux fichiers si vous souhaitez comparer. Vous pouvez également retrouver l’intégralité du projet en ligne.
L'idée est simple. Chaque fonction remplit simplement un tableau avec le ou les octets nécessaires. Certes, le 1802 est assez simple. Cela serait plus difficile à réaliser pour un processeur moderne comportant de nombreuses instructions et des modes complexes. Mais pas impossible.
Vous pouvez faire beaucoup de choses pour vous faciliter la vie, à la fois lors de la programmation et lors de la configuration des instructions. Par exemple, si vous vouliez 100 instructions NOP, vous pourriez écrire :
pour (int i = 0 ; i < 100 ; i++) NOP();
D'un autre côté, NOP a un argument facultatif qui le fera à votre place. Vous pouvez utiliser librement le compilateur C++ et le préprocesseur de macros pour vous faciliter la vie. Par exemple, une tâche courante sur le 1802 consiste à mettre une valeur constante comme une étiquette dans un registre. Le fichier lit1802.h contient une macro pour faciliter cela :