Den Neo6502 über SWD debuggen: ein Pico W als Sonde
Wenn der Bildschirm schwarz bleibt und die serielle Schnittstelle schweigt, bleibt der Debug-Port des RP2040. Ein Pico W, drei Drähte und OpenOCD: Man liest den Speicher der Platine im Betrieb und tippt sogar an ihrer Stelle.
Auf dem Neo6502 von Olimex führt der W65C02S die Programme aus, doch der RP2040 erledigt alles andere: DVI-Video, USB, Dateien, Ton. Bei der Arbeit an unserem Firmware-Fork Trinity ist das erste Werkzeug ein Terminal an einer seriellen Schnittstelle. Es hat eine Grenze: Es setzt eine Firmware voraus, die gesund genug ist, um zu sprechen. Der RP2040 hat außerdem einen Debug-Port, SWD, über den eine Sonde seinen Speicher über den Bus liest und schreibt, ohne die Firmware um etwas zu bitten — schwarzer Bildschirm oder hängende Firmware eingeschlossen. Hier unser Aufbau, die Befehle, und was damit geklärt wurde.
1. Der Aufbau

SWD1.
GP2, GP3 und einer Masse.Zwei Platinen, zwei USB-Kabel: Der Neo6502 ist wie gewohnt versorgt und an seinen Bildschirm angeschlossen; der Pico W hängt am PC, der ihn als Debug-Sonde sieht. Dazwischen nur drei Drähte.
2. Die Sonde: ein Pico W und drei Drähte
Auf dem Pico W läuft debugprobe, die Firmware von Raspberry Pi, die ihn zu einer CMSIS-DAP-Sonde macht. Die Verdrahtung, wie in unseren Skripten festgehalten:
| Pico W (Sonde) | Neo6502, Anschluss SWD1 |
|---|---|
GP2 | SWCLK (SWC) |
GP3 | SWDIO (SWD) |
GND | GND |
Die Platine muss selbst versorgt sein: Die Sonde versorgt sie nicht.
3. Verbinden: OpenOCD
OpenOCD spricht mit der Sonde und mit dem RP2040:
openocd -f interface/cmsis-dap.cfg -c "set USE_CORE 0" -f target/rp2040.cfg \
-c "adapter speed 1000" -c "init"
Einmal verbunden, lesen und schreiben read_memory und write_memory jede Adresse, während die Platine läuft. Die Adressen der Firmware-Variablen ändern sich mit jedem Build: Unsere Skripte legen sie nie fest, sie lesen sie aus der ELF-Datei der geflashten Version.
arm-none-eabi-nm firmware.elf | awk '$3 == "frameCounter" { print "0x" $1 }'
# danach, in OpenOCD:
read_memory 0x2000xxxx 16 1
4. Die laufende Firmware lesen: neoswd.sh
neoswd.sh liest in einer Schleife einige Zähler der Firmware. Der nützlichste ist frameCounter, den Kern 1 zu Beginn jedes Videobilds erhöht: Steigt er noch, lebt das Signal und nur das Bild ist falsch; steht er still, ist der Encoder stehen geblieben. Daneben: lateTotal, die Episoden verspätet gelieferter Zeilen; stoSectorCount, die vom Speichertreiber bewegten Sektoren; und eine Stichprobe des Videospeichers, um einen leeren von einem unsichtbaren Bildschirm zu unterscheiden.
firmware/scripts/neoswd.sh 500 # Zähler alle 500 ms
firmware/scripts/neopilot.sh "MODE 1" "DIR" # tippt, misst dann
5. Tippen statt der Tastatur: neopilot.sh
Bei schwarzem Bildschirm sieht man nicht mehr, was man tippt. neopilot.sh schreibt direkt in die Tastaturwarteschlange der Firmware (queue und queueTail): ein Zeichen alle 40 ms, dann Enter. Danach misst es mehrmals pro Sekunde die FIFO-Füllstände des PIO, der das Video speist, ihre Fehlerflags, den Bildzähler und die Zeilenzahl des letzten Bilds. So lässt sich genau dieselbe Folge, MODE 1 und dann DIR, von einer Firmware zur nächsten wiederholen.
6. Die Regel: nur Kern 0 anhängen
Der RP2040 hat zwei Kerne; in Trinity erzeugt Kern 1 das Video. OpenOCD kann sich an beide hängen, doch auch Kern 1 anzuhängen lässt den Encoder auf 15 Bilder pro Sekunde fallen und erfindet einen Fehler, den es nicht gibt (gemessen am 25. September 2026). Daher set USE_CORE 0 in allen unseren Befehlen: Das Messinstrument darf den Encoder nicht berühren. Eine weitere Nebenwirkung, beobachtet, als Kern 1 Vorrang auf dem Bus bekommen hatte: Selbst die SWD-Lesezugriffe schlugen fehl, denn der Debug-Port teilt sich diesen Bus.
7. Was die Sonde geklärt hat
Während des schwarzen Bildschirms beim ersten DIR im Hercules-Modus zeigte die Sonde, dass der Bildzähler seine 60 Bilder pro Sekunde hielt, dass der Videospeicher das Verzeichnis tatsächlich enthielt und dass lateTotal beim Lesen der Platte stieg: weder eine hängende Firmware noch ein gelöschter Bildschirm. Diese Messung und die folgenden widerlegten mehrere Erklärungen nacheinander, bis zur eigentlichen Ursache — einer Sperre, die sich beide Kerne teilten. Die ganze Jagd steht in Ein DIR, das den Bildschirm löscht.
8. Was wir nicht behaupten
Die Sonde liest, was die Firmware im Speicher ablegt: Die hier genannten Zähler gibt es, weil wir sie Trinity hinzugefügt haben, und ihre Namen sind die unseres Forks, nicht die der offiziellen Firmware. Die Skripte setzen die exakte ELF-Datei der geflashten Version voraus. Die Pins des Anschlusses
SWD1erkennt man am Bestückungsdruck der Platine; hier nennen wir nur die Signale.