Déboguer le Neo6502 par SWD : un Pico W en sonde
Quand l'écran reste noir et que le port série se tait, il reste le port de débogage du RP2040. Un Pico W, trois fils et OpenOCD : on lit la mémoire de la carte pendant qu'elle tourne, et on tape même au clavier à sa place.
Sur le Neo6502 d'Olimex, le W65C02S exécute les programmes, mais c'est le RP2040 qui fait tout le reste : vidéo DVI, USB, fichiers, son. Quand on met au point notre fork du firmware, Trinity, on a d'abord un terminal sur un port série. Il a une limite : il suppose un firmware en assez bon état pour parler. Le RP2040 a aussi un port de débogage, SWD, par lequel une sonde lit et écrit sa mémoire sur le bus, sans rien demander au firmware — écran noir ou firmware bloqué compris. Voici notre banc, les commandes, et ce que cela a permis de trancher.
1. Le banc

SWD1.
GP2, GP3 et une masse.Deux cartes, deux câbles USB : la Neo6502 est alimentée et branchée à son écran comme d'habitude ; le Pico W est branché au PC, qui le voit comme une sonde de débogage. Entre les deux, trois fils seulement.
2. La sonde : un Pico W et trois fils
Le Pico W est flashé avec debugprobe, le firmware de Raspberry Pi qui en fait une sonde CMSIS-DAP. Le câblage, relevé dans nos scripts :
| Pico W (sonde) | Neo6502, connecteur SWD1 |
|---|---|
GP2 | SWCLK (SWC) |
GP3 | SWDIO (SWD) |
GND | GND |
La carte doit être alimentée de son côté : la sonde ne l'alimente pas.
3. Se connecter : OpenOCD
OpenOCD parle à la sonde et au RP2040 :
openocd -f interface/cmsis-dap.cfg -c "set USE_CORE 0" -f target/rp2040.cfg \
-c "adapter speed 1000" -c "init"
Une fois connecté, read_memory et write_memory lisent et écrivent n'importe quelle adresse pendant que la carte tourne. Les adresses des variables du firmware changent à chaque compilation : nos scripts ne les figent jamais, ils les relisent dans le fichier ELF de la version flashée.
arm-none-eabi-nm firmware.elf | awk '$3 == "frameCounter" { print "0x" $1 }'
# puis, dans OpenOCD :
read_memory 0x2000xxxx 16 1
4. Lire le firmware en marche : neoswd.sh
neoswd.sh relit en boucle quelques compteurs du firmware. Le plus utile est frameCounter, incrémenté par le cœur 1 au début de chaque trame vidéo : s'il monte encore, le signal vit et seule l'image est fausse ; s'il est figé, l'encodeur s'est arrêté. À côté : lateTotal, les épisodes de lignes livrées en retard ; stoSectorCount, les secteurs déplacés par le pilote de stockage ; et un échantillon de la mémoire vidéo, pour savoir si l'écran est vide ou seulement invisible.
firmware/scripts/neoswd.sh 500 # compteurs toutes les 500 ms
firmware/scripts/neopilot.sh "MODE 1" "DIR" # tape, puis mesure
5. Taper à la place du clavier : neopilot.sh
Quand l'écran est noir, on ne voit plus ce qu'on tape. neopilot.sh écrit directement dans la file clavier du firmware (queue et queueTail) : un caractère toutes les 40 ms, puis Entrée. Il relève ensuite, plusieurs fois par seconde, les niveaux des FIFO du PIO qui alimente la vidéo, leurs drapeaux d'erreur, le compteur de trames et le nombre de lignes de la dernière trame. On rejoue ainsi exactement la même séquence, MODE 1 puis DIR, d'un firmware à l'autre.
6. La règle : n'attacher que le cœur 0
Le RP2040 a deux cœurs ; dans Trinity, le cœur 1 produit la vidéo. OpenOCD peut s'attacher aux deux, mais attacher aussi le cœur 1 fait tomber l'encodeur à 15 trames par seconde et invente une panne qui n'existe pas (mesuré le 25 septembre 2026). D'où set USE_CORE 0 dans toutes nos commandes : l'instrument ne doit pas toucher l'encodeur. Autre effet de bord, observé quand le cœur 1 avait reçu la priorité sur le bus : même les lectures SWD échouaient, car le port de débogage partage ce bus.
7. Ce que la sonde a tranché
Pendant l'écran noir du premier DIR en mode Hercules, la sonde a montré que le compteur de trames gardait ses 60 trames par seconde, que la mémoire vidéo contenait bien le catalogue, et que lateTotal montait pendant la lecture du disque : ni firmware figé, ni écran effacé. Ce relevé, puis ceux qui ont suivi, ont démenti plusieurs explications l'une après l'autre, jusqu'à la vraie cause — un verrou partagé entre les deux cœurs. Toute la traque est racontée dans Un DIR qui éteint l'écran.
8. Ce qu'on ne dit pas
La sonde lit ce que le firmware range en mémoire : les compteurs cités ici existent parce que nous les avons ajoutés à Trinity, et leurs noms sont ceux de notre fork, pas du firmware officiel. Les scripts supposent le fichier ELF exact de la version flashée. Le repérage des broches du connecteur
SWD1se fait à la sérigraphie de la carte ; nous ne donnons ici que les signaux.