Tachibana
Langue : français

Utiliser Phosphoneo : jouer, tester, scripter et déboguer sur Neo6502

#neo6502 #émulation #utilitaires

À quoi sert Phosphoneo, concrètement : jouer, essayer un programme en une ligne, scripter et filmer une partie, déboguer, reprendre une exécution, tester — et ce qu'il ne mesure pas encore.

Par bmarty · Tachibana · 30 octobre 2026

Le Neo6502 d'Olimex associe un W65C02S, qui exécute les programmes, et un RP2040, dont le firmware fournit tout le reste : écran, clavier, fichiers, son. Phosphoneo est notre émulateur de cette machine, dans la lignée de Phosphoric. Il est né d'un besoin simple : tester nos portages (AsteroNeo, Wolfenstein 3D, les jeux en cours) sans brancher une carte à chaque essai, et obtenir le même résultat à chaque exécution. Cet article décrit comment on s'en sert ; ce qu'il y a dedans tient en une section.

La vidéo

Le film de trois minutes : jouer, essayer sans écran, scripter et filmer, déboguer, reprendre, tester — avec de vraies sorties de l'émulateur à l'écran. Les images viennent de Phosphoneo lui-même ; la voix est synthétique.

3 min 05 s, voix et sous-titres en anglais. Hébergée sur ce site ; aucun lecteur tiers n'est chargé.

Pourquoi un second émulateur ?

Émulateur officiel (neo)Phosphoneo
API du firmware : le code officielAPI du firmware : le même code, lié en bibliothèque
cœur 6502 maison, non validécœur 65C02 validé à 100 % sur l'oracle SingleStepTests
cadence : cycles par trame6,25 MHz, trame de 109 226 cycles à 60 Hz, latence des appels API mesurée en co-simulation
peu d'options de testmode sans affichage, captures, frappe et manette scriptées, traces, journal d'API, gdb, sauvegarde d'état
pour jouer et vérifier à l'œilpour servir d'oracle aux portages, à l'intégration continue et à la régression

1. Jouer : une fenêtre en temps réel

Le plus simple : on ouvre un programme dans une fenêtre SDL à 60 images par seconde, avec le clavier, la souris, la manette et le son. F11 passe en plein écran, F12 prend une capture, Ctrl+F12 ouvre un menu superposé pour charger un programme de la clé USB émulée, enregistrer ou reprendre un instantané, couper le son, changer l'échelle et sauver la configuration.

phosphoneo --sdl --scale 3 prog.neo      # fenêtre temps réel : clavier, souris, manette, son
phosphoneo --fullscreen prog.neo         # plein écran 4:3
# F11 plein écran · F12 capture · Ctrl+F12 menu (charger, instantané, réglages)

2. Essayer sans écran : captures et frappe automatique

Le même programme peut tourner sans affichage, pour un nombre de cycles donné. On tape des touches à un cycle précis (Entrée, Échap, F1 à F8, flèches), puis on enregistre l'écran en image ou la console en texte. Un essai se résume à une ligne, donne le même résultat à chaque fois, et se range dans un script de test.

phosphoneo --cycles 40000000 --type-keys '15000000:PRINT 6*7\n' \
    --screenshot-text out.txt --screenshot out.ppm

Un programme NeoBASIC tokenisé (.bas), un .neo ou un binaire chargé à une adresse (prog.bin@800) se lancent de la même façon. tools/mkneo.py assemble un .neo à partir de blocs ; --storage désigne le dossier qui joue le rôle de la clé USB, et --load-at y charge un programme en cours de route, comme le fait la page web.

3. Scripter une partie, et la filmer

Pour rejouer un scénario — une partie, un menu, un combat — on programme à des cycles précis les états de la manette, des écritures en mémoire (se téléporter, régler une variable) et des frappes. L'option --record enregistre l'image et le son dans un fichier vidéo. C'est ainsi que sont tournés les extraits de nos films, et que nous validons un jeu de bout en bout : jusqu'à 4 096 actions par essai.

phosphoneo prog.neo --cycles 60000000 \
    --gamepad-at 5000000:04 --gamepad-at 12000000:0 \
    --poke-at 3000000:1F40=64 --record partie.avi

4. Déboguer

Quand un programme se comporte mal, on a de quoi regarder dedans. Le journal des appels d'API montre chaque appel (groupe, fonction, paramètres avant et après, code d'erreur), filtré par groupe. La trace note chaque instruction avec son adresse effective, et reconnaît les JSR d'API. Avec le fichier de symboles de 64tass ou de cc65, on pose des points d'arrêt par nom, on s'arrête avant un appel d'API donné et on sauve la RAM, ou on ouvre un moniteur en terminal. Un serveur gdb est aussi disponible.

phosphoneo prog.neo --api-log api.log:3,10 --trace trace.txt
phosphoneo prog.neo --symbols prog.lbl --break-at main --tui
phosphoneo prog.neo --break-api 3,2 --break-dump ram.bin
phosphoneo prog.neo --gdb 1234              # puis : target remote :1234

5. Interrompre et reprendre : la sauvegarde d'état

On peut figer l'émulation à un cycle donné et la reprendre plus tard, exactement : écran et console sont identiques, octet pour octet, à une exécution continue. C'est utile pour sauter les trois premières minutes d'un jeu avant de tester la suivante. La sauvegarde se fait avec le même binaire seulement, et les fichiers ouverts par le programme sont rouverts à leur position.

phosphoneo prog.neo --save-state-at 50000000:jeu.state
phosphoneo --load-state jeu.state

6. Dans le navigateur, et avec le réseau

Le même code se compile en WebAssembly : une page charge l'émulateur, copie les fichiers d'un paquet dans un stockage en mémoire et lance le programme. C'est ce que fait « Jouer » de Prophet. Les programmes qui parlent à un modem peuvent utiliser un modem logiciel (commandes Hayes et ESP-AT, vraies connexions), ou, dans le navigateur, un relais HTTP. Un mode --floppy sert enfin un vrai lecteur de disquettes à travers la pile de fichiers de la carte.

7. Les tests : la raison d'être

Phosphoneo sert surtout d'oracle. Une trentaine de captures de référence sont comparées par empreinte à chaque make test : si un changement modifie un pixel ou une ligne de la console, on le voit, et une capture ne se rebaselinise qu'après avoir été regardée. Les mêmes cas sont comparés à l'émulateur officiel (images identiques au pixel près) et rejoués sur le vrai firmware ARM en co-simulation. Le dépôt d'un projet peut réutiliser le script de captures tel quel : c'est ce que font AsteroNeo, notre portage de Wolfenstein 3D et nos jeux en cours.

8. Sous le capot, en bref

Trois choix expliquent la confiance qu'on peut lui accorder. Le processeur 65C02 est contrôlé contre l'oracle SingleStepTests : 2 540 000 cas, état, RAM, cycles et accès au bus, 100 % exigé. Le firmware n'est pas imité : le code de l'API de Trinity est compilé tel quel (licence MIT), seule la couche matérielle est écrite autour. Et le temps est déterministe : 6,25 MHz, trame de 109 226 cycles à 60 Hz, minuteur de 100 Hz compté en cycles émulés ; un appel d'API coûte 0 cycle par défaut, ou une durée calibrée en co-simulation avec --api-latency.

9. Ce qu'on ne dit pas

Phosphoneo est un modèle, pas la carte. Ne sont pas modélisés : le signal DVI, l'énumération et le timing de l'USB, l'UART d'extension, l'I2C, le SPI et les GPIO ; la vitesse de la carte SD n'est pas simulée ; le menu de démarrage de Trinity s'exécute avant le premier cycle du processeur et reste hors de portée. La cadence et la latence des appels sont modélisées mais non mesurées sur la carte : le protocole existe, il n'a pas encore été déroulé. Un programme qui tourne bien dans Phosphoneo doit donc encore être essayé sur la carte.

Et le code n'est pas public pour l'instant : cet article décrit l'outil, il ne l'offre pas. Ce qu'on peut déjà utiliser, ce sont les programmes qu'il a aidé à mettre au point, et le lecteur du navigateur que Prophet charge.

Sources & liens

← Neo6502 · Neo6502 Chess → · Manoir NG → · Prophet 0.25 → · SWD → · Prophet → · AsteroNeo → · Neo6502 →