In der CPU Sandbox programmierst du einen kleinen 8-Bit-Computer, erst in Assembler, später in C. Register, Flags, Speicher, Bildschirm und Geräte sind dabei jederzeit sichtbar, bis hinunter zum einzelnen Takt auf dem Bus. Und am Ende läuft auf derselben Maschine ein 3D-Labyrinth.
Zur CPU Sandbox gehören 26 Beispielprogramme, von der Addition zweier Zahlen bis zu Spielen und Grafikeffekten. Alles, was auf dem Bildschirm erscheint, berechnet die simulierte Maschine selbst, Pixel für Pixel, ohne versteckte Grafikbefehle.

Im Bild läuft 25-raycaster.c, ein Labyrinth im Stil von Wolfenstein 3D, ganz ohne Gleitkommazahlen. In den Beispielen steckt noch viel mehr; jedes Bild hier ist der Bildschirm eines Beispielprogramms:

14-mandelbrot.asm Die Mandelbrot-Menge, in Assembler
15-inferno.asm Inferno: ein Feuer, in dem jedes Pixel die Hitze seiner Nachbarn aufnimmt
16-breakout.asm Breakout, mit Joystick und Ton
20-plasma.c Plasma aus Sinuswellen
21-life.c Conways Game of Life
23-color-cycling.c Color Cycling: Bewegung nur durch die Palette
24-arpeggio-organ.c Arpeggio-Orgel: Akkorde auf der Tastatur
26-landscape.c Landschaft mit WasserspiegelungDu arbeitest mit zwei Git-Repositories. Im Workspace ist ~ dein Ordner /workspace.
| Ordner | Inhalt | Wer ändert es? |
|---|---|---|
~/cpu-sandbox/ |
die App mit den Beispielen | nur deine Lehrkraft |
~/cpu-sandbox/programs/ |
das Klassen-Repository mit euren Programmen | ihr, jede und jeder im eigenen Ordner |
Die Karten auf dieser Seite schauen in deinem Workspace nach und sagen dir, was sie finden. Sie ändern nichts.
Mit einem SSH-Schlüssel meldet sich dein Workspace beim GitLab-Server an, ohne dass du jedes Mal ein Passwort eingibst. Melde dich zuerst auf git.nhcham.org an. Prüfe dann im Terminal, ob du schon einen Schlüssel hast:
ls ~/.ssh/id_ed25519.pub
Erscheint No such file or directory, erzeugst du einen neuen. Bestätige den vorgeschlagenen Speicherort mit Enter; die Passphrase darfst du im Workspace leer lassen und noch zweimal Enter drücken:
ssh-keygen -t ed25519 -C "Vorname Nachname"
Zeige nun den öffentlichen Schlüssel an und kopiere die ganze Zeile, die mit ssh-ed25519 beginnt:
cat ~/.ssh/id_ed25519.pub
In GitLab gehst du oben rechts auf dein Profilbild und dann auf Edit profile → Access → SSH keys → Add new key. Füge die Zeile bei Key ein, gib als Titel zum Beispiel Workspace an und speichere.
Die Datei ~/.ssh/id_ed25519 ohne .pub ist dein privater Schlüssel. Den kopierst du nie und lädst ihn nirgendwo hoch.
Teste die Verbindung. Beim ersten Mal fragt SSH nach, ob du dem Server vertraust; antworte mit yes. Danach begrüßt dich GitLab mit deinem Benutzernamen:
ssh -T git@git.nhcham.org
Meldet SSH Permission denied (publickey), fehlt der Schlüssel in GitLab, oder du hast eine andere Zeile kopiert als die aus id_ed25519.pub.
Dein öffentlicher SSH-Schlüssel liegt in ~/.ssh/id_ed25519.pub.
~ ist im Workspace /workspace. ls ~/.ssh zeigt, was dort liegt.
Jeder Commit trägt einen Namen und eine E-Mail-Adresse. Trage deinen echten Namen und die E-Mail-Adresse deines GitLab-Kontos ein:
git config --global user.name "Vorname Nachname" git config --global user.email "deine.mail@example.org"
Das ist in jedem Workspace nur einmal nötig. Ohne diese Angaben weigert sich Git zu committen.
Git kennt deinen Namen und die E-Mail-Adresse deines GitLab-Kontos.
Klone die App in dein Home-Verzeichnis:
cd ~
git clone https://github.com/specht/cpu-sandbox.git
Wechsle in ihren Ordner und klone dort das Klassen-Repository:
cd cpu-sandbox
git clone git@git.nhcham.org:specht/cpu-sandbox-programs-2026.git programs
Das Klassen-Repository muss in der App liegen und genau programs heißen. Gibt es programs/ schon, klone es nicht noch einmal und lösche nichts, sondern frag nach.
Die App liegt in ~/cpu-sandbox, das Klassen-Repository darin in programs.
programs ist ein eigenes Git-Repository und weiß, wohin es pushen kann.
Starte die App in einem Terminal und lass es offen. Für Git öffnest du ein zweites Terminal.
cd ~/cpu-sandbox
./run
Ein neues Programm legst du in der App mit + neben der Programmauswahl an. Gib als Student folder deinen Ordnernamen an, zum Beispiel anna, dann einen Dateinamen, die Sprache und die CPU. Das Programm entsteht in programs/DEIN_NAME/.
Die MiniCPU gibt es in drei Stufen. Jede behält alles von der vorherigen und fügt genau eine Idee hinzu, sodass du nichts umlernen musst:
| Modell | Neue Idee | Speicher und Register |
|---|---|---|
| MiniCPU 8 | Daten bewegen, rechnen, vergleichen, springen, Schleifen | 256 Byte; A–D, PC, Flags ZF und CF |
| MiniCPU 8S | Stack: Unterprogramme mit CALL/RET, Rekursion |
zusätzlich Stackpointer SP |
| MiniCPU 8X | Zeiger, große Programme, Grafik | 64 KiB, 16-Bit-Adressen, Register X und Y |
Die Schreibweise ist einheitlich: Das Ziel steht immer vorne, und eckige Klammern bedeuten immer »der Speicher an«. LDI A, 0x70 lädt die Zahl 0x70, LDA A, [0x70] das Byte, das an Adresse 0x70 steht. Wer sich vertut, bekommt eine Fehlermeldung, die genau diesen Unterschied erklärt. So sieht eine erste Schleife aus:
LDI A, 5 LDI B, 0 loop: ADD B, A DEC A JNZ loop HLT
Step führt einen Befehl aus, Step back nimmt ihn zurück. Neben jeder Quelltextzeile stehen Adresse und Maschinenbytes; geänderte Speicherzellen leuchten auf. Im Modus Cycles geht es noch eine Ebene tiefer: Jeder Klick ist ein Takt. Du siehst, wie der Opcode geholt und dekodiert wird, wie Operanden gelesen werden, was auf Adress- und Datenbus liegt und wann gesprungen wird.

LDA A, [0x80] einen Takt mehr als LDI A, 0x80? Was schreibt CALL in den Speicher, und wohin? Warum kostet ein JZ, das springt, einen Takt mehr als eines, das nicht springt? Stell erst Vermutungen auf und prüf sie dann im Taktmodus.
Ein paar Dinge, die du in der Sandbox fast von selbst entdeckst:
05-self-modifying macht das sogar absichtlich.Ab MiniCPU 8S kannst du Programme auch in MiniC schreiben, einer kleinen Variante von C, die schon beim Tippen übersetzt wird. Versteckt wird dabei nichts: Neben jeder C-Zeile stehen ihre Maschinenbytes, und der Reiter Assembly zeigt das erzeugte Programm. Du siehst, dass lokale Variablen auf dem Stack liegen, wie ein Funktionsaufruf sein Argument übergibt und wie das Ergebnis zurückkommt.

Der Würfel aus 18-cube.c nutzt eine Sinustabelle in Festkommaarithmetik, Perspektive, das Ausblenden verdeckter Flächen, Schattierung und Seitenwechsel (page flipping) gegen Flackern, und die Füllroutine ist von Hand in Assembler geschrieben.
Sechzehn Aufgaben prüfen sich selbst: vom Addieren zweier Bytes über Fibonacci, Multiplikation und Sortieren bis zu einem Schachbrettmuster, dazu Aufgaben speziell für C wie Fakultät, größter gemeinsamer Teiler, Primzahlsieb und Linienzeichnen. + legt ein Programm zu einer Aufgabe an, Check führt alle Testfälle aus und erklärt Fehler wie »0x82 should be 7, but it is 8«, und Try it lädt einen Testfall in die Maschine, damit du ihn Schritt für Schritt verfolgst.
Class progress sammelt die funktionierenden Lösungen der Klasse und sortiert sie nach Takten; das kleinste Programm in Bytes wird zusätzlich markiert. Wer schafft es mit weniger Takten? Wer mit weniger Bytes? Und geht beides gleichzeitig?
Besonders lehrreich ist es, dieselbe Aufgabe zweimal zu lösen, einmal in Assembler und einmal in C. Mit geradlinigen Lösungen ergibt sich etwa:
| Aufgabe | Assembler: Bytes · Takte | C: Bytes · Takte |
|---|---|---|
add |
12 · 75 | 25 · 180 |
maximum |
22 · 820 | 88 · 3.420 |
sort |
42 · 4.260 | 176 · 19.271 |
multiply |
33 · 5.991 | 92 · 1.935 |
multiply ist es umgekehrt: Das C-Programm braucht nur ein Drittel der Takte. Woran liegt das? (Tipp: Wie multipliziert der Compiler, und wie die naheliegende Assembler-Lösung?) Ein besserer Algorithmus schlägt handgeschriebene Befehle.
Mehr zur App steht in ihrer Anleitung, alle Aufgaben in der Aufgabenliste.
Deine Lehrkraft sieht deine Programme erst, wenn sie committet und gepusht sind. Das machst du im Ordner programs, nicht im Ordner der App:
cd ~/cpu-sandbox/programs git pull git add DEIN_NAME/ git commit -m "Aufgabe add von DEIN_NAME" git push
Im Klassen-Repository arbeiten alle. Mit welchem Befehl nimmst du nur deine eigenen Dateien in den nächsten Commit auf?
Deine Arbeit ist committet und gepusht. Erst dann sieht deine Lehrkraft
sie in »Class progress« und die anderen nach git pull in ihrer App.
Prüfe das am Ende jeder Stunde.
In einem Klassen-Repository veröffentlichen viele. Hat jemand kurz vor dir gepusht, lehnt Git deinen Push mit rejected ab, weil dir dessen Commits fehlen. Hol sie zuerst und push dann noch einmal:
git pull git push
Öffnet git pull einen Editor für eine Commit-Nachricht, speichere sie unverändert und schließe den Editor. Meldet Git einen Konflikt, hat jemand dieselbe Datei geändert wie du. Dann gilt: nichts löschen, nichts überschreiben, nach Hilfe fragen. Solange du nur Dateien in deinem eigenen Ordner änderst, passiert das nicht.
cd ~/cpu-sandbox && git pull cd programs && git pull cd .. && ./run
Und am Ende der Stunde: Aufgabe 5 noch einmal prüfen.