Simple8

L'environnement Simple8

Avant d'écrire la première ligne de code, ce chapitre présente les outils : ce que fait le compilateur, les machines qu'il connaît, ses bibliothèques, comment l'installer et le lancer, puis comment préparer Simple8 IDE.

1.1Ce qu'est Simple8

Simple8 est à la fois un langage et un compilateur. Le langage ressemble à Java et au C : des blocs entre accolades, des types (byte, int, uint…), des fonctions, des boucles for et while. Le compilateur traduit ce code en assembleur natif pour la machine choisie, l'assemble, et produit le fichier que l'on charge dans un émulateur ou sur la vraie machine : une ROM PC Engine, un .prg Commodore 64, une disquette Amiga…

Dans sa version actuelle, Simple8 a été pensé pour les petits processeurs 8 bits : le 6502 et ses dérivés (HuC6280, 6510, 2A03), le Z80 et le SM83 de la Game Boy. Ses types, sa gestion de la mémoire et son code généré sont taillés pour des machines qui ont peu de registres, une page zéro et quelques kilo-octets de RAM. Les machines à 68000 sont prises en charge à titre d'essai (voir les architectures).

Un programme Simple8 dit toujours, en première ligne, pour quelle machine il est écrit :

architecture nec.pce;      // ce programme est pour la PC Engine

Tout le reste en découle : le processeur visé, la façon d'organiser la mémoire, les bibliothèques disponibles et le format du fichier produit.

L'environnement complet se compose de :

1.2Comment fonctionne le compilateur

Le compilateur part du fichier principal (main.s8p) et arrive à un fichier prêt à lancer. Entre les deux, le programme passe par une chaîne d'étapes :

Du code Simple8 à la machine : analyse, représentation intermédiaire, optimisation, génération d'assembleur, assemblage, puis la ROM lancée dans un émulateur ou sur la machine Code Simple8 main.s8p Analyseur lexical + syntaxique Représentation intermédiaire IR Optimiseur code mort Génération d'assembleur 6502 · Z80 SM83 · 68000 Assembleur intégré ROM · PRG disquette Émulateur ou machine réelle
Le schéma mental : du fichier source à la machine.

Dans le détail :

  1. LectureLe fichier principal, ses bibliothèques (addlib) et ses units (addunit) sont lus et découpés en arbre syntaxique.
  2. AnalyseTypes, variables, portées et appels de fonctions sont vérifiés ; les erreurs sont signalées avec leur ligne.
  3. Représentation intermédiaireLe programme est réécrit en instructions simples, encore indépendantes du processeur.
  4. Code mortLes fonctions jamais appelées, y compris celles des bibliothèques, sont écartées.
  5. GénérationLe générateur du processeur (6502, Z80, SM83, 68000) écrit l'assembleur, puis l'optimise.
  6. AssemblageL'assembleur intégré produit le fichier final, les listings et les rapports.

Tout se fait dans le même programme : il n'y a aucun outil externe à installer, ni assembleur ni éditeur de liens. Le compilateur écrit son travail dans un dossier asm/, à côté du fichier compilé :

FichierContenu
main.asml'assembleur généré, lisible, avec le code des bibliothèques utilisées
main.lstle listing : chaque instruction avec son adresse et ses octets
main.symla table des symboles, que lisent les émulateurs-débogueurs
main_report.htmlle rapport de compilation : mémoire occupée, fonctions, code écarté
main.pce, main.prg…le programme à lancer, au format de la machine

Lire l'assembleur généré est le meilleur moyen de comprendre ce que coûte une ligne de Simple8. Les chapitres suivants y reviendront souvent.

Quand l'abstraction ne suffit pas, le langage laisse descendre au niveau du matériel : un bloc _asm { … } insère de l'assembleur au milieu du code, et le compilateur vérifie les instructions selon le processeur de la machine.

1.3Les architectures

Une architecture désigne une machine précise. Son nom s'écrit constructeur.machine, et c'est lui qui suit le mot architecture en tête du programme.

ArchitectureProcesseurMachineFichier produit
nec.pceHuC6280PC Engine / TurboGrafx-16.pce
nec.sgxHuC6280PC Engine SuperGrafX.pce et .sgx
commodore.c64MOS 6510Commodore 64.prg, .d64
nintendo.nesRicoh 2A03NES / Famicom.nes
mos.6502MOS 65026502 génériquebinaire brut
amstrad.cpc6128Z80AAmstrad CPC 464 / 664 / 6128.bin, .dsk
zilog.z80Z80Z80 générique (MSX, Master System, Spectrum).bin
nintendo.dmgSharp SM83Game Boy.gb
sega.megadrive68000Mega Drive / Genesis (expérimental).md
commodore.amiga68000Amiga 500 PAL / OCS (expérimental).adf (disquette)

Le langage est le même partout. Ce qui change d'une machine à l'autre, ce sont les bibliothèques (il n'y a pas de sprites matériels à l'identique sur une PC Engine et un Amstrad CPC), la mémoire disponible et la taille des nombres que le processeur manipule sans effort.

Les architectures 68000 sont des essais. Simple8 est aujourd'hui conçu pour les processeurs 8 bits. La Mega Drive et l'Amiga 500 fonctionnent, mais leur prise en charge reste expérimentale : le langage et le code généré ne tirent pas encore parti d'un processeur 16/32 bits. Une prochaine version de Simple8 doit améliorer le développement sur 68000.

motorola.68000, de son côté, est reconnue mais ne produit pas de code : pour le 68000, on choisit une machine concrète, sega.megadrive ou commodore.amiga.

1.4Les bibliothèques

Les bibliothèques sont des fichiers .s8l, écrits en Simple8 (souvent avec un peu d'assembleur). Elles sont rangées dans le dossier libs8/, une branche par machine :

libs8/
├── nec/pce/              PC Engine
│   ├── boot/boot.asm     le démarrage de la machine
│   ├── system/           la bibliothèque système
│   ├── config.json       la carte mémoire de la machine
│   ├── vdc/              l'affichage : tuiles, sprites, défilement
│   ├── vce/              les couleurs
│   ├── psg/              le son
│   └── io/               la manette
├── commodore/c64/
├── nintendo/nes/
├── …
└── math/                 les bibliothèques communes à toutes les machines

Un programme charge une bibliothèque avec addlib, suivi du dossier et du nom du fichier, séparés par un point :

architecture nec.pce;

addlib vdc.base;      // libs8/nec/pce/vdc/base.s8l
addlib io.base;       // libs8/nec/pce/io/base.s8l

Le compilateur cherche le fichier dans cet ordre, et prend le premier trouvé :

  1. le dossier de la machine : libs8/nec/pce/vdc/base.s8l ;
  2. les bibliothèques communes : libs8/vdc/base.s8l ;
  3. vos bibliothèques personnelles, dans le dossier indiqué par la variable S8_USER_LIBS ;
  4. les bibliothèques du projet, dans son dossier userlibs/.

Grâce à l'élimination du code mort, charger une bibliothèque ne coûte rien : seules les fonctions réellement appelées finissent dans la ROM.

1.5Installer Simple8

Ce qu'il faut

OutilPour quoi faire
Java (JDK 21)construire et faire tourner le compilateur
Gitrécupérer les sources
Maven ou Antconstruire le compilateur

Récupérer et construire le compilateur

  1. Récupérer le dépôt :

    git clone https://github.com/beddy70/Simple8.git
    cd Simple8
  2. Construire le compilateur, au choix avec Ant ou avec Maven :

    # Ant : le fichier est écrit dans dist/
    ant compile jar
    
    # Maven : le fichier est écrit dans target/, et les tests sont lancés
    mvn package
  3. Vérifier qu'il répond :

    java -jar dist/LitleCompilator.jar --help

Indiquer où sont les bibliothèques

Le compilateur doit savoir où se trouve le dossier libs8/. Le plus simple est de le déclarer une fois pour toutes dans la variable d'environnement S8_LIBS_PATH :

# macOS, Linux : à ajouter dans ~/.zshrc ou ~/.bashrc
export S8_LIBS_PATH=/chemin/vers/Simple8/libs8
export S8_USER_LIBS=~/mes_libs_simple8        # facultatif

# Windows
setx S8_LIBS_PATH C:\Simple8\libs8

Sans S8_LIBS_PATH ni option -l, le compilateur ne cherche pas les bibliothèques dans le dossier courant : il ne les trouve pas, et signale Library not found.

1.6Compiler en ligne de commande

Le compilateur se lance avec Java, en lui donnant le fichier principal du projet :

java -jar LitleCompilator.jar -f main.s8p
OptionEffet
-f, --file fichierle fichier .s8p à compiler (on peut aussi le donner seul, sans -f)
-l, --libs dossierle dossier libs8/ ; passe avant S8_LIBS_PATH
-d, --debugaffiche les étapes internes : arbre, représentation intermédiaire, assembleur
-h, --helpl'aide

Lancer la commande depuis le dossier du projet. Le dossier asm/ est créé dans le dossier courant : compiler depuis un autre endroit y déposerait les fichiers générés.

Essayer avec un exemple

Le dépôt contient des programmes d'exemple, rangés par machine dans Examples/. Pour compiler le premier programme NES :

cd Examples/nintendo/nes/HelloNES
java -jar ../../../../dist/LitleCompilator.jar -l ../../../../libs8 main.s8p

Si tout va bien, la compilation se termine sans erreur et le dossier asm/ contient main.nes, une cartouche qui se lance directement dans Mesen, FCEUX ou Nestopia.

1.7Simple8 IDE

La ligne de commande suffit, mais Simple8 IDE rend le travail plus confortable : on écrit, on compile et on lance l'émulateur sans quitter l'application. Les erreurs de compilation apparaissent soulignées dans le code, et l'assembleur généré se lit dans un onglet voisin.

L'installer

Bientôt des versions prêtes à installer. Des versions compilées de Simple8 IDE pour macOS, Windows et Linux seront proposées. Une version en ligne de la suite Simple8, utilisable depuis un navigateur, verra aussi le jour. En attendant, l'IDE se construit à partir des sources, comme décrit ci-dessous.

L'IDE se construit depuis le dossier ide/ du dépôt. Il demande, en plus de Java, Rust (version stable) et Node.js 20 ou plus récent :

cd ide
npm install
npm run tauri build      # l'application, prête à installer
npm run tauri dev        # ou : lancer l'IDE directement depuis les sources

Ouvrir un projet

Fichier → Ouvrir un projet… (⌘O) : on choisit le dossier du projet. L'IDE y cherche ensuite :

Fichier → Nouveau projet… (⇧⌘N) demande un nom, une architecture et un dossier, puis crée un main.s8p prêt à remplir.

Sur macOS, une application ouverte depuis le Finder ou le Dock ne voit pas les variables du terminal (S8_LIBS_PATH, S8_USER_LIBS). Si on en a besoin, lancer l'IDE depuis un terminal.

Les raccourcis essentiels

ActionRaccourci
Compiler le fichier principal⌘B
Compiler puis lancer dans l'émulateur⌘R
Ouvrir l'assembleur généré⌥⌘A
Ouvrir le listing⌥⌘L
Ouvrir le rapport de compilation⌥⌘R
Configurer les émulateurs⌘,

Pendant la compilation, la sortie du compilateur défile dans l'onglet Sortie. Les erreurs et avertissements sont rassemblés dans l'onglet Problèmes : un clic ouvre le fichier sur la ligne en cause.

Git

Simple8 IDE gère aussi le dépôt Git du projet, sans passer par le terminal. Tout se règle dans Configuration → Git… :

ActionRaccourci
Valider tous les changements du projet (git commit)⇧⌘K
Pousser la branche vers les serveurs choisis (git push)⇧⌘P

1.8Configurer les émulateurs

Le bouton ▶ Lancer compile le programme puis, si la compilation réussit, ouvre le fichier produit dans l'émulateur choisi. La liste ne montre que les émulateurs compatibles avec la machine du programme.

L'IDE en connaît un par défaut pour chaque machine :

MachineÉmulateur par défautAutres choix prévus
PC EngineGeargrafxares, Mednafen
SuperGrafXGeargrafxMednafen
Commodore 64VirtualC64VICE
Amstrad CPCCaprice32CPCemu
NESMesen
Game BoyGearboy
Mega Driveares
Amiga 500FS-UAE

Les émulateurs eux-mêmes s'installent à part. Ensuite, la fenêtre Configuration → Émulateurs… (⌘,) indique pour chacun si son exécutable est trouvé (●) ou non (○), et permet de choisir son chemin et l'émulateur par défaut de chaque machine.

Le fichier emulators.json

Pour aller plus loin, la configuration est un fichier JSON, ouvert par Configuration → Éditer emulators.json. Un projet peut aussi avoir son propre fichier simple8-emulators.json, qui remplace la configuration générale entrée par entrée :

{
  "defaults": { "nec.pce": "ares-pce" },
  "emulators": {
    "ares-pce": {
      "name": "ares (PC Engine)",
      "command": "/Applications/ares.app/Contents/MacOS/ares",
      "args": ["--system", "PC Engine", "--no-file-prompt", "${rom}"],
      "architectures": ["nec.pce"],
      "rom": "${asmDir}/${name}.pce"
    }
  }
}
VariableValeur
${projectDir}le dossier du fichier compilé
${name}son nom, sans extension
${asmDir}le dossier asm/ du projet
${rom}le fichier à lancer
${sym}la table des symboles, pour les émulateurs-débogueurs

1.9L'organisation d'un projet

Un projet Simple8 est un simple dossier :

MonJeu/
├── main.s8p                  le programme principal
├── Joueur.s8u                d'autres units, ajoutées avec addunit (facultatif)
├── userlibs/                 des bibliothèques propres au projet (facultatif)
├── simple8-emulators.json    les émulateurs du projet (facultatif)
└── asm/                      créé par le compilateur
ExtensionRôle
.s8ple programme : il déclare l'architecture et contient la unit principale, avec main()
.s8uune unit dans son propre fichier, pour découper un programme qui grandit
.s8lune bibliothèque, chargée avec addlib

Le dossier asm/ est entièrement régénéré à chaque compilation : on peut le supprimer sans risque, et il n'a pas besoin d'être conservé dans Git (le modèle .gitignore de l'IDE l'exclut).

L'environnement est prêt. Le chapitre suivant écrira le premier programme.