Tachibana

De Neo6502 debuggen via SWD: een Pico W als probe

#neo6502 #firmware #hulpprogramma's

Als het scherm zwart blijft en de seriële poort zwijgt, is er nog de debugpoort van de RP2040. Een Pico W, drie draden en OpenOCD: je leest het geheugen van het bordje terwijl het draait, en typt zelfs in zijn plaats.

Door bmarty · Tachibana · 26 september 2026

Op de Neo6502 van Olimex voert de W65C02S de programma's uit, maar de RP2040 doet al het andere: DVI-video, USB, bestanden, geluid. Bij het ontwikkelen van onze firmware-fork, Trinity, is het eerste gereedschap een terminal op een seriële poort. Die heeft één grens: hij veronderstelt firmware die gezond genoeg is om te praten. De RP2040 heeft ook een debugpoort, SWD, waarlangs een probe het geheugen via de bus leest en schrijft, zonder de firmware iets te vragen — zwart scherm of vastgelopen firmware inbegrepen. Hier onze opstelling, de commando's, en wat het heeft beslecht.

1. De opstelling

Neo6502-bordje van Olimex onder spanning: scherm op de DVI-uitgang, USB-stick en USB-apparaat op de hostpoorten, drie draden op de SWD1-connector
De Neo6502 onder spanning: scherm op de DVI-uitgang, USB-voeding, USB-stick en een apparaat op de hostpoorten, en drie draden op de connector SWD1.
Raspberry Pi Pico W van onderen gezien, gevoed via USB, draden op GP2, GP3 en een massa
De probe: een Pico W, via USB gevoed door de pc, draden op GP2, GP3 en een massa.

Twee bordjes, twee USB-kabels: de Neo6502 is gevoed en zoals altijd op zijn scherm aangesloten; de Pico W zit aan de pc, die hem als debugprobe ziet. Ertussen: slechts drie draden.

2. De probe: een Pico W en drie draden

De Pico W draait debugprobe, de firmware van Raspberry Pi die er een CMSIS-DAP-probe van maakt. De bedrading, zoals vastgelegd in onze scripts:

Pico W (probe)Neo6502, connector SWD1
GP2SWCLK (SWC)
GP3SWDIO (SWD)
GNDGND

Het bordje moet zelf gevoed worden: de probe voedt het niet.

3. Verbinden: OpenOCD

OpenOCD praat met de probe en met de RP2040:

openocd -f interface/cmsis-dap.cfg -c "set USE_CORE 0" -f target/rp2040.cfg \
        -c "adapter speed 1000" -c "init"

Eenmaal verbonden lezen en schrijven read_memory en write_memory elk adres terwijl het bordje draait. De adressen van de firmwarevariabelen veranderen bij elke build: onze scripts leggen ze nooit vast, ze lezen ze opnieuw uit het ELF-bestand van de geflashte versie.

arm-none-eabi-nm firmware.elf | awk '$3 == "frameCounter" { print "0x" $1 }'
# daarna, in OpenOCD:
read_memory 0x2000xxxx 16 1

4. De draaiende firmware lezen: neoswd.sh

neoswd.sh leest in een lus enkele tellers van de firmware. De nuttigste is frameCounter, die core 1 aan het begin van elk videobeeld ophoogt: loopt hij nog op, dan leeft het signaal en is alleen het beeld fout; staat hij stil, dan is de encoder gestopt. Daarnaast: lateTotal, de episodes van te laat geleverde lijnen; stoSectorCount, de sectoren die de opslagdriver verplaatst; en een steekproef van het videogeheugen, om een leeg scherm van een onzichtbaar scherm te onderscheiden.

firmware/scripts/neoswd.sh 500            # tellers elke 500 ms
firmware/scripts/neopilot.sh "MODE 1" "DIR"   # typt, meet daarna

5. Typen in plaats van het toetsenbord: neopilot.sh

Met een zwart scherm zie je niet meer wat je typt. neopilot.sh schrijft rechtstreeks in de toetsenbordwachtrij van de firmware (queue en queueTail): één teken per 40 ms, daarna Enter. Vervolgens meet het, meermaals per seconde, de FIFO-niveaus van de PIO die de video voedt, hun foutvlaggen, de beeldteller en het aantal lijnen van het laatste beeld. Zo speel je precies dezelfde reeks, MODE 1 en dan DIR, opnieuw af van de ene firmware naar de andere.

6. De regel: alleen core 0 koppelen

De RP2040 heeft twee cores; in Trinity maakt core 1 de video. OpenOCD kan zich aan beide koppelen, maar ook core 1 koppelen laat de encoder terugvallen tot 15 beelden per seconde en verzint een storing die er niet is (gemeten op 25 september 2026). Vandaar set USE_CORE 0 in al onze commando's: het meetinstrument mag de encoder niet aanraken. Nog een neveneffect, gezien toen core 1 voorrang op de bus had gekregen: zelfs de SWD-leesopdrachten mislukten, want de debugpoort deelt die bus.

7. Wat de probe heeft beslecht

Tijdens het zwarte scherm van de eerste DIR in Hercules-modus liet de probe zien dat de beeldteller zijn 60 beelden per seconde hield, dat het videogeheugen wel degelijk de catalogus bevatte, en dat lateTotal opliep tijdens het lezen van de schijf: geen vastgelopen firmware en geen gewist scherm. Die meting, en de volgende, weerlegden de ene verklaring na de andere, tot aan de echte oorzaak — een lock die beide cores deelden. De hele jacht staat in Een DIR die het scherm dooft.

8. Wat we niet beweren

De probe leest wat de firmware in het geheugen zet: de hier genoemde tellers bestaan omdat wij ze aan Trinity hebben toegevoegd, en hun namen zijn die van onze fork, niet van de officiële firmware. De scripts veronderstellen het exacte ELF-bestand van de geflashte versie. De pinnen van de connector SWD1 herken je aan de opdruk op het bordje; hier geven we alleen de signalen.

Bronnen & links

← Neo6502 · Prophet → · AsteroNeo → · Neo6502 →