AgonLight programmieren: Von BBC BASIC und Inline-Assembler

AgonLight Serie:
Teil 1: Hardware
Teil 2: Programmieren

Im ersten Teil habe ich dir das AgonLight als Plattform vorgestellt – einen echten 8-Bit-Computer mit eZ80-CPU, ESP32-VDP und Bare-Metal-Charakter. Jetzt wird es praktisch: Wie programmiert man einen modernen 8-Bit Computer? Wir schauen uns dazu BBC BASIC und Z80-Inline-Assembler an.

AgonLight2 von Olimex

Was du wirklich brauchst #

Das Setup bleibt angenehm überschaubar. Du brauchst das Board selbst – AgonLight 2, Agon Origins oder Console8 – plus ein USB-C-Kabel für die 5V-Stromversorgung. Dazu eine PS/2-Tastatur (oder USB mit Adapter) und einen VGA-Monitor. Hast du keinen VGA-Monitor mehr herumstehen, tut es ein VGA-zu-HDMI-Konverter für unter 20 Euro.

Wenn du mit deinen USB-Tastaturen scheiterst, dann fehlt ihnen PS2-Kompatibilität. Ich habe diese Tastatur in Benutzung: CHERRY G84-4100. Die ist weder gut noch schön aber programmieren wirst du wahrscheinlich eh auf deinem PC oder Mac.

Die MicroSD-Karte: FAT32 formatiert, darauf z.B. die aktuelle Console8-Firmware (die läuft auch auf einem Agon Light 2) und alle deine Programme als .bas- oder .bin-Dateien. Am PC reicht ein beliebiger Texteditor – ich nutze VS Code mit BBC-BASIC-Syntax-Highlighting. Für Low-Level-Debug-Ausgaben ist ein USB-Serial-Terminal wie PuTTY oder screen nützlich, aber nicht zwingend nötig.

Seitenblick auf echte 8-Bit Systeme #

Es mag Menschen geben und ich würde mich dazuzählen denen die modernen Zugeständnisse des AgonLight an Komfort und Geschwindigkeit (fast) zu weit gehen. Wer das pure 8-Bit-Erlebniss sucht, der sollte sich eher bei Boards mit RCBus umschauen. Damit lassen sich 8-Bit Systeme zusammenbauen, die wiklich jeden modernen Komfort vermissen lassen. Dafür öffnet man sich damit das Tor in eine alternative Realität wo z.B. der beste 8-Bit Grafikchip in Form eines Yamaha V9938 mit einem MOS 6502 in einem System steckt. Sinn? Unklar. Es würde mich dennoch reizen aber die Anschaffungskosten für Platinen und Chip von um die 500€ sind zu happig.

Bezugsquellen für die coolen RCBus Board z.B. Small Computers Direct

Olimex SC691 - AgonLight 2 fertig montiert

Ohgott ist das Board schon, schnell wieder Webseite schließen ....

Der MOS-Prompt: Dein Einstiegspunkt #

Zurück zum Konfort des AgonLight. Strom rein, und keine halbe Sekunde später ein sattes Pieps und ein MOS-Prompt blinkt– das Machine Operating System des Agon sag Hallo. Kein Bootlogo, kein Splash-Screen, kein Ladebalken. Genau das, was mich an alten Heimcomputern bis cool ist.

Von dort aus arbeitest du mit einer Handvoll Befehlen, die sich wie eine minimalistische Shell anfühlen oder DOS anfühlen:

* ls Verzeichnis anzeigen (wie DIR)
* cat file.txt   Dateiinhalt ausgeben
* cd ordner      Verzeichnis wechseln
* run prog.bin   Programm ausführen
* load basic.bin BBC BASIC starten

Ein kleines Detail, das dir viel Arbeit spart: Die Datei autoexec.txt im Root der SD-Karte wird beim Boot automatisch ausgeführt. Wenn du willst, dass der Agon direkt im BASIC-Interpreter startet, setzt du dort einen einzigen LOAD BASIC.BIN-Befehl rein. Fertig.

BBC BASIC – Fast Forward #

Der integrierte Interpreter ist die Portierung von R.T. Russell, dem Original-Autor des BBC BASIC aus den 80ern. Das ist kein Marketing, sondern ein echter Glücksfall: Dieser Interpreter gehört zu den schnellsten BASICs, die je auf einem 8-Bit-System liefen. Und er ist strukturiert – du kannst sauber mit WHILE/ENDWHILE, IF/THEN/ELSE/ENDIF und PROC/FN arbeiten. Der Spaghetti-Code, den du aus Sinclair BASIC oder Commodore BASIC kennst, bleibt dir weitgehend erspart.

Hello World sieht genau so aus, wie du es erwartest:

10 PRINT "Hello AgonLight!"
20 END

Eine Schleife mit Variable ist kaum komplizierter:

10 FOR i% = 1 TO 10
20   PRINT "Zahl: "; i%
30 NEXT i%

Das % hinter dem Variablennamen signalisiert BBC BASIC, dass es eine 32-Bit Integer-Variable ist – deutlich schneller als die Standard-Fliesskommavariablen. Richtig interessant wird es, sobald du Prozeduren einsetzt, bekannt eher von Pascal und vergleichbar mit modernen Funktionen:

10 PROCgruss("Agon")
20 END
30 :
40 DEF PROCgruss(name$)
50   PRINT "Hallo, "; name$; "!"
60 ENDPROC

Zum Speichern und Laden benutzt du SAVE "meinprog.bas" und LOAD "meinprog.bas". Wenn du ein Programm laden und sofort starten willst, reicht CHAIN "meinprog.bas".

VDU – Mit Brücke zur Grafik #

Der eZ80 selbst erzeugt kein Pixel auf dem Bildschirm. Das macht der ESP32 als Video Display Processor. Die Kommunikation zwischen beiden läuft über das klassische VDU-System des BBC Micro von 1981 – Byte-Sequenzen, die der eZ80 an den VDP schickt.

Ein paar Beispiele, damit du das Prinzip siehst:

VDU 12            : REM Bildschirm löschen
VDU 22, 8         : REM Grafikmodus 8 (320x240, 64 Farben)
VDU 19, 1, 255, 0, 255, 255  : REM Farbe 1 als Cyan definieren
VDU 25, 69, 10; 10;          : REM PLOT-Befehl (Pixel bei 10,10)
VDU 23, 27, ...              : REM Agon-spezifische Erweiterungen

Für die meisten dieser Rohbefehle gibt es bequeme BASIC-Wrapper. Statt VDU 22, 8 schreibst du einfach MODE 8. GCOL 0, 4 ersetzt VDU 18, 0, 4, und CLG löscht nur die Grafikebene. Wer die VDU-Codes direkt benutzt, hat dafür vollen Zugriff auf das gesamte Kommando-Set – inklusive der Agon-spezifischen Erweiterungen ab VDU 23, 27, ... für Sprites, Bitmaps und Double-Buffering.

Die verfügbaren Grafikmodi reichen von 640x480 mit 16 Farben (Modus 0) über 320x240 mit 64 Farben (Modus 8, mein Favorit für kleine Demos) bis hin zu 1024x768 in zwei Farben (Modus 18). Jeder Modus hat seine eigene Balance zwischen Auflösung, Farbtiefe und verfügbarem VRAM. Und wir erinnern uns, der ESP32 ist beschreibbar, damit können theoretisch auch andere Modi realisiert werden.

Zeichnen mit PLOT, DRAW und MOVE #

Ein Quadrat mit zwei Schritten: MOVE setzt den Zeichenstift, DRAW zieht eine Linie dorthin:

10 MODE 8
20 GCOL 0, 4        : REM Farbe Blau
30 MOVE 50, 50
40 DRAW 200, 50
50 DRAW 200, 150
60 DRAW 50, 150
70 DRAW 50, 50

Gefüllte Dreiecke brauchen nur einen einzigen Aufruf des PLOT-Befehls, wenn du dreimal MOVE davor setzt. Ein echter Konfortgewinn:

10 MODE 8
20 GCOL 0, 1        : REM Rot
30 MOVE 160, 20
40 MOVE 60, 200
50 PLOT 85, 260, 200 : REM PLOT 85 = gefüllt

Kreise gehen über einen PLOT-Typ mit Mittelpunkt und Randpunkt. Der eigentliche Witz dahinter: Der ESP32 macht die gesamte Rasterisierung in Hardware – der eZ80 schiebt nur ein Anweisungen über die Serienne Schnittstelle und hat sofort Zeit für das nächste Stück Code.

Sprites: Nicht zeichnen, sondern bewegen #

Hier wird es richtig spannend. Der Agon unterstützt bis zu 256 Hardware-Sprites gleichzeitig, komplett verwaltet im VRAM des ESP32. Das ist Wahsinn, vergleichen mit den Fähigkeiten von 8-Bit Systemen seiner Zeit. Der eZ80 schickt nur noch Positionsbefehle an die VDU – das ist CPU-technisch quasi kostenlos. Genau dadurch werden 60-FPS-Spiele auf einem 8-Bit-System möglich, die aussehen wie auf einer PC-Engine (theoretisch).

Der Workflow ist immer gleich: Bitmap ins VRAM laden, Sprite erstellen, Bitmap zuweisen, Sprite aktivieren und positionieren. Ab da musst du im Game-Loop nur noch die Position aktualisieren.

REM Bitmap 0 definieren: 16x16, RGBA2222
VDU 23, 27, 0, 0
VDU 23, 27, 1, 16; 16; 1

REM Pixeldaten von SD-Karte ins VRAM streamen
f% = OPENIN "ship.rgba"
FOR i% = 1 TO 256
  VDU BGET#f%
NEXT : CLOSE#f%

REM Sprite 0 erstellen und Bitmap 0 zuweisen
VDU 23, 27, 4, 0       : REM Select Sprite 0
VDU 23, 27, 5          : REM Clear frames
VDU 23, 27, 6, 0       : REM Add Bitmap 0
VDU 23, 27, 11         : REM Show Sprite

REM Im Game-Loop: Position setzen, Refresh
VDU 23, 27, 13, 100; 80;  : REM Move to 100,80
VDU 23, 27, 15            : REM Update

Transparenz läuft über den Alpha-Kanal und ist nativ im Bitmap-Format enthalten. Unterstützt werden RGBA8888, RGBA2222, RGB332 und ein paar weitere Formate – je nach VRAM-Budget.

SOUND – Beep, Boop, Wohooooo #

Audio erzeugt der ESP32 über seinen internen DAC, mit mehreren parallelen Kanälen. Der SOUND-Befehl ist direkt aus dem BBC-Micro-Handbuch übernommen:

REM SOUND Kanal, Lautstärke, Tonhöhe, Dauer
SOUND 0, -15, 100, 20
SOUND 1, -15, 150, 20
SOUND 2, -15, 200, 20

Eine kleine Melodie ist mit DATA und READ in sechs Zeilen erledigt:

10 REM Kleine Melodie
20 FOR i% = 0 TO 7
30   READ note%
40   SOUND 0, -15, note%, 10
50 NEXT
60 DATA 53,69,81,89,97,89,81,69

Jetzt kommt das Wohoooo. Wer es etwas weniger piepsig will, wechselt die Wellenform pro Kanal über einen VDU-Befehl – Rechteck, Dreieck, Sägezahn, Sinus und Rauschen stehen zur Auswahl. Und mehr noch, WAV-Samples von der SD-Karte kannst du genauso abspielen.

Der richtige Kick: Inline-Assembler #

Das ist mein Lieblings-Feature des Agon-BBC-BASIC und gleichzeitig der Grund, warum ich überhaupt angefangen habe, mich wieder mit Z80-Assembler zu beschäftigen. Du kannst nämlich Z80/eZ80-Assembly direkt in deinem BASIC-Programm schreiben. Kein externer Compiler, kein Hin-und-Her-Kopieren von Binärdaten – der Assembler ist in BBC BASIC eingebaut. Bessere Lesbarkeit und Speed ...

Ein vollständiges Beispiel: Speicherbereich mit dem Wert 42 füllen.

10 DIM code% 50                   : REM 50 Bytes für den Code reservieren
20 FOR pass% = 0 TO 3 STEP 3      : REM Two-Pass Assembly
30   P% = code%                   : REM Programmzähler setzen
40   [                            : REM ASM-Block öffnen
50   OPT pass%
60   LD A, 42                     \ Füllwert -> Register A
70   LD HL, &40000                \ Zieladresse -> HL
80   LD B, 100                    \ Schleifenzähler -> B
90   .loop
100  LD (HL), A                   \ A -> Speicher
110  INC HL                       \ nächste Adresse
120  DJNZ loop                    \ B--, springe wenn B!=0
130  RET                          \ zurück zu BASIC
140  ]                            : REM ASM-Block Ende
150 NEXT pass%
160 CALL code%                    : REM Code ausführen

Drei Dinge passieren hier gleichzeitig. DIM code% 50 reserviert dir einen Speicherbereich. Die Schleife FOR pass% = 0 TO 3 STEP 3 läuft genau zweimal durch – einmal mit OPT 0 (Pass 1: Adressen und Sprungmarken berechnen, noch keinen Code erzeugen) und einmal mit OPT 3 (Pass 2: fertigen Maschinencode schreiben). Zwischen den eckigen Klammern steht der eigentliche Z80-Code mit Labels, Sprungmarken und Kommentaren – alles, was du von einem vernüftigen Assembler erwartest.

Warum das so fantastisch, praktisch ist, wird im direkten Vergleich mit einem Sinclair-BASIC klar. Derselbe Maschinencode auf einem ZX81 sieht nämlich so aus - urks:

1  REM XXXXXXXXXXXX  : REM 12 Byte-Platzhalter
10 FOR I=0 TO 11
20 READ B
30 POKE 16514+I, B
40 NEXT I
50 DATA 62,42          : REM  LD A, 42
60 DATA 33,0,125       : REM  LD HL, 32000
70 DATA 6,100          : REM  LD B, 100
80 DATA 119            : REM  LD (HL), A
90 DATA 35             : REM  INC HL
100 DATA 16,252        : REM  DJNZ -4  
#include 

int main(void) {
  printf("Hello AgonLight!\n");
  return 0;
}

Der Build-Zyklus ist genauso einfach:

make                    # Kompilieren
cp build/hello.bin /sd/ # Auf SD kopieren
* run hello.bin         # Auf Agon starten

Für Projekte, in denen du komplexere Datenstrukturen, Pointer-Arithmetik oder Header-Files brauchst, ist das der richtige Weg. Standard-Libraries (stdio, stdlib, string, math) sind da, dazu die Agon-spezifischen mos_api.h, vdp_vdu.h und vdp_audio.h.

Der Dev-Workflow #

Klingt nach viel, ist aber in der Praxis angenehm unaufgeregt. Mein Workflow mit echter Hardware sah bisher so aus:

  1. Code am PC im Texteditor schreiben
  2. Datei auf die SD-Karte speichern
  3. SD-Karte in den Agon stecken (oder per Agon WiFi Programmer kabellos über WLAN)
  4. Programm ausführen
  5. Bei Fehler: zurück zu Schritt 1

Die Boards erlauben SD-Karten-Hotswap – Karte raus, am PC ändern, wieder rein, kein Reboot. Für kurze Iterationen ist das Gold wert. Debuggen läuft über die übliche Kombination: PRINT im BASIC, ein serielles Terminal für tieferes Debugging oder *TRACE ON für die MOS-Befehlsverfolgung.

Noch praktischer: Der Fab Agon Emulator läuft auf Windows, Mac und Linux, emuliert VDP, Sound, Tastatur und SD-Karte komplett. Dort habe ich mir eine Basic-Pipeline gebaut mit automsischen teste, Debugger und Sprite-Editor. Dazu bald vielleicht mehr.

Ressourcen & Community #

Das Agon-Ökosystem ist klein, aber erstaunlich aktiv. Die offizielle Dokumentation liegt im AgonLight Wiki auf GitHub – VDP-Referenz, MOS-API, Tutorials. Die wichtigsten Repositories, die du kennen solltest:

  • agon-vdp – VDP-Firmware
  • agon-mos – MOS-Firmware
  • agon-bbc-basic – der BBC-BASIC-Interpreter
  • AgDev – C-Toolchain
  • fab-agon-emulator – der Emulator

Die Discord-Community ist extrem hilfsbereit – du hast dort direkten Kontakt zu den Firmware-Entwicklern, und Fragen werden meist innerhalb weniger Stunden beantwortet. Für Videoinhalte lohnt sich der Kanal The Byte Attic von Bernardo Kastrup, dem Erfinder des Agon. Spiele und Demos findest du auf itch.io unter dem Agon-Tag.

Wenn du selbst loslegen willst: Das Agon Light 2 von Olimex gibt es ab etwa 50 Euro. Das Agon Origins ist das Premium-Board direkt aus Kastrups Shop. Und das Console8 ist ein komplettes Konsolen-Kit mit Gehäuse, Controller-Anschlüssen und schickem Case:

Console8 im Gehäuse auf dem Standfuss

Mach mit bei uns im Verein! #

Wenn dich das neugierig macht: Komm am Retro-Mittwoch vorbei. Wir haben ein AgonLight im 3D-gedruckten Gehäuse vor Ort und ich zeige dir gerne, wie das Ganze in der Praxis aussieht. Egal ob du Lust hast, ein kleines Spiel zu schreiben, dich mit Z80-Assembler zu vertiefen oder einfach mal einen BASIC-One-Liner tippen willst – wir finden zusammen einen Einstieg.

Wer mehr zur Hardware selbst wissen will, der findet alles Grundlegende im ersten Teil der Serie. Und natürlich freuen wir uns über jeden, der Lust hat, beim RCD mitzumachen und eigene Projekte auf alten (oder fast-neuen) Maschinen umzusetzen.