chip8-sharp

Un émulateur CHIP-8 complet et testé en C#. Le jeu d'instructions complet vérifié en headless sur des ROM de test communautaires - une bibliothèque pure sans dépendance au rendu.

chip8-sharp
TL;DR

Un émulateur CHIP-8 complet en C#. Le jeu d'instructions entier, les minuteurs et l'entrée, le tout vérifié headless contre des ROMs de test communautaires. Une bibliothèque pure, sans dépendance au dessin.

Aperçu

chip8-sharp est un émulateur CHIP-8 complet écrit en C#. CHIP-8 est petit - quelques dizaines d'instructions, une mémoire simple, un écran de 64 sur 32 pixels - et c'est justement pour cela qu'il est le classique "premier émulateur". Mais la différence entre un jouet et un projet tient dans ce mot "complet" : le jeu d'instructions entier, les minuteurs et l'entrée, et non la moitié "suffisante pour un jeu".

Le cœur est une bibliothèque pure sans dépendance au dessin, exactement comme pour le Game Boy. C'est ce qui permet de lancer toute la machine headless et de la faire passer par des ROMs de test sans aucune fenêtre, ce qui transforme "ça marche sans doute" en "vérifié".

CHIP-8 est un rite de passage pour quiconque veut comprendre comment fonctionne l'émulation. Il est assez petit pour tenir en entier dans la tête, et assez réel pour enseigner tout ce que les émulateurs plus grands font à plus grande échelle : le cycle fetch-decode-execute, la mémoire, les minuteurs, la gestion de l'entrée.

Sa taille est un atout, pas une limite. C'est justement parce qu'il est petit qu'on peut le faire vraiment correctement, et pas seulement "presque". Chaque opcode peut être vérifié séparément, et la communauté a des ROMs toutes prêtes qui affichent "OK" ou "FAIL" pour chaque instruction.

Une boucle : fetch, decode, execute

Toute la machine tourne autour d'une seule boucle. Un opcode fait deux octets, et des bits précis disent de quelle instruction il s'agit et sur quels registres elle doit agir. Le décodage consiste à découper les bons fragments de ces deux octets et à les diriger vers la bonne branche.

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 d'un opcode

Tout le charme de CHIP-8 tient à ce que le décodage se décompose en ses facteurs premiers. Un opcode de seize bits se divise en fragments au sens fixe, et une fois cette anatomie comprise, elle transforme toute la liste d'instructions en quelques règles simples.

Fragments d'un opcode de seize bits

FragmentBitsSignification
nnnles 12 bits de poids faibleune adresse mémoire
xbits 8-11un numéro de registre
kkles 8 bits de poids faibleune constante de huit bits
➜
Conseil

Si vous débutez tout juste avec l'émulation, commencez justement par CHIP-8. Chaque opcode peut être vérifié séparément, et la communauté a des ROMs toutes prêtes qui affichent "OK" ou "FAIL" pour chaque instruction, si bien que dès le premier jour vous travaillez avec un vrai retour.

Le résultat : le jeu complet, pas la moitié

Ce qui en sort est un émulateur petit mais soigné - le jeu d'instructions entier, les minuteurs et l'entrée, vérifié headless contre des ROMs communautaires. Le même tour que pour le Game Boy, la séparation de la logique et de l'affichage, fait que la justesse est prouvée, non déclarée. C'est un projet petit par conception mais vraiment terminé, et non abandonné à "suffisant pour un jeu".

Plus de projets

D'autres réalisations de la même catégorie - découvrez comment nous abordons des défis similaires.

Vous avez un projet similaire ?

Contactez-nous - le devis est gratuit et arrive sous une heure.