chip8-sharp

Ein vollständiger, getesteter CHIP-8-Emulator in C#. Der komplette Befehlssatz headless gegen Community-Test-ROMs geprüft - eine reine Bibliothek ohne Rendering-Abhängigkeit.

chip8-sharp
TL;DR

Ein vollständiger CHIP-8-Emulator in C#. Der komplette Befehlssatz, Timer und Eingabe, alles headless gegen Community-Test-ROMs geprüft. Eine reine Bibliothek, ohne Abhängigkeit vom Zeichnen.

Überblick

chip8-sharp ist ein vollständiger CHIP-8-Emulator, geschrieben in C#. CHIP-8 ist klein - ein paar Dutzend Instruktionen, ein einfacher Speicher, ein Bildschirm von 64 mal 32 Pixeln - und genau deshalb ist es der klassische "erste Emulator". Aber der Unterschied zwischen einem Spielzeug und einem Projekt liegt in diesem Wort "vollständig": der komplette Befehlssatz, Timer und Eingabe, und nicht die Hälfte, die "für ein Spiel reicht".

Der Kern ist eine reine Bibliothek ohne Abhängigkeit vom Zeichnen, genau wie beim Game Boy. Genau das erlaubt es, die ganze Maschine headless zu starten und durch Test-ROMs zu schicken, ganz ohne Fenster, was "läuft wohl" in "geprüft" verwandelt.

CHIP-8 ist ein Ritus des Übergangs für jeden, der verstehen will, wie Emulation funktioniert. Es ist klein genug, um es ganz im Kopf zu behalten, und echt genug, um alles zu lehren, was größere Emulatoren im größeren Maßstab tun: den Fetch-Decode-Execute-Zyklus, Speicher, Timer, Eingabeverarbeitung.

Seine Größe ist ein Vorteil, keine Einschränkung. Genau weil es klein ist, kann man es wirklich korrekt machen, und nicht nur "fast". Jeder Opcode lässt sich einzeln prüfen, und die Community hat fertige ROMs, die für jede Instruktion "OK" oder "FAIL" ausgeben.

Eine Schleife: fetch, decode, execute

Die ganze Maschine dreht sich um eine Schleife. Ein Opcode besteht aus zwei Bytes, und einzelne Bits sagen, welche Instruktion es ist und auf welchen Registern sie wirken soll. Das Dekodieren besteht darin, die richtigen Fragmente aus diesen zwei Bytes herauszuschneiden und sie in den richtigen Zweig zu leiten.

Interpreter.cs · csharp
ushort opcode = (ushort)(memory[PC] << 8 | memory[PC + 1]);
PC += 2;

ushort nnn = (ushort)(opcode & 0x0FFF);
byte x = (byte)((opcode & 0x0F00) >> 8);
byte kk = (byte)(opcode & 0x00FF);

switch (opcode & 0xF000) {
    case 0x1000: PC = nnn; break;
    case 0x6000: V[x] = kk; break;
    case 0x7000: V[x] += kk; break;
}

Anatomie eines Opcodes

Der ganze Reiz von CHIP-8 liegt darin, dass sich das Dekodieren in seine Bestandteile zerlegen lässt. Ein sechzehn Bit langer Opcode teilt sich in Fragmente mit fester Bedeutung, und einmal verstanden, verwandelt diese Anatomie die ganze Befehlsliste in ein paar einfache Regeln.

Fragmente eines sechzehn Bit langen Opcodes

FragmentBitsBedeutung
nnnuntere 12eine Speicheradresse
xBits 8-11eine Registernummer
kkuntere 8eine acht Bit lange Konstante
➜
Tipp

Wenn Sie gerade erst mit Emulation anfangen, fangen Sie genau mit CHIP-8 an. Jeder Opcode lässt sich einzeln prüfen, und die Community hat fertige ROMs, die für jede Instruktion "OK" oder "FAIL" ausgeben, sodass Sie vom ersten Tag an mit echtem Feedback arbeiten.

Das Ergebnis: der volle Satz, nicht die Hälfte

Heraus kommt ein kleiner, aber ausgefeilter Emulator - der komplette Befehlssatz, Timer und Eingabe, headless gegen Community-ROMs geprüft. Derselbe Trick wie beim Game Boy, die Trennung von Logik und Anzeige, sorgt dafür, dass die Korrektheit bewiesen und nicht behauptet ist. Es ist ein Projekt, das vom Entwurf her klein ist, aber wirklich fertig, und nicht bei "reicht für ein Spiel" liegen gelassen.

Weitere Projekte

Weitere Projekte aus derselben Kategorie - sehen Sie, wie wir ähnliche Herausforderungen angehen.

Haben Sie ein ähnliches Projekt?

Melden Sie sich - ein Angebot ist kostenlos und kommt innerhalb einer Stunde.