Ćwiczenie 5 — Uruchomienie prawdziwej gry
Cel
Bez nowego kodu — to moment “wow” na koniec: emulator z ćwiczeń 1-4 uruchamia prawdziwe, publicznie dostępne gry CHIP-8 z lat 70./80.
Skąd wziąć ROM-y
CHIP-8 to platforma z bogatą sceną hobbystyczną — większość klasycznych ROM-ów (Pong, Tetris, Space Invaders, Breakout) jest domeną publiczną albo swobodnie udostępniana przez społeczność retro-computingową. Wyszukaj “chip8 roms public domain” albo “chip8-test-suite” (Timendus) — ten ostatni to zestaw ROM-ów testowych, które systematycznie sprawdzają poprawność implementacji każdej instrukcji (świetne do wykrycia błędów, które przetrwały ćwiczenia 1-4).
Zacznij od małych ROM-ów testowych (IBM logo, test opcode’ów), potem przejdź do właściwych gier — plik .ch8 to zwykły binarny plik, ten sam format co używane w ćwiczeniach testowe “ROM-y” ręcznie sklejane w tablicach bajtów.
Sterowanie
Typowe gry (np. Pong) używają klawiszy 1, 4, 7, A (jedna kolumna klawiatury CHIP-8) do ruchu — sprawdź dokumentację konkretnej gry, jeśli nie reaguje na oczekiwane klawisze.
Checklist rozwiązywania problemów
Jeśli gra się nie uruchamia albo działa źle:
- Czarny ekran, brak reakcji — sprawdź czy
chip8_load_rompoprawnie odczytuje cały plik (freadzwraca liczbę odczytanych elementów — porównaj z oczekiwanym rozmiarem). - “Śmieci” na ekranie zamiast grafiki — najczęściej błąd w
DXYN(zła kolejność bitów w bajcie sprite’u, albo brakujące zawijanie%). - Gra działa, ale za szybko/wolno — sprawdź stosunek cykli CPU do klatek w pętli
main(ćwiczenie 4) — różne gry były pisane z założeniem różnej prędkości procesora, czasem trzeba dostroić liczbę cykli na klatkę. - Program “wisi” na starcie — prawdopodobnie ROM zaczyna się od
FX0A(czekaj na klawisz) i emulator nie odczytujestdinw trybie non-blocking poprawnie. Unknown opcodena stderr — brakująca instrukcja z poprzednich ćwiczeń, albo gra korzysta z rzadziej używanego opcode’u (np.FX33BCD,FX55/FX65zapis/odczyt rejestrów do pamięci) — dobra okazja do rozszerzenia zestawu poza 4 podstawowe ćwiczenia.
Rozszerzenia (dla chętnych / dodatkowe punkty)
FX33(BCD): rozłóżV[x]na cyfry dziesiętne i zapisz podmemory[I..I+2]— potrzebne w niektórych grach do wyświetlania wyniku.FX55/FX65: zapis/odczyt rejestrówV0..Vxdo/z pamięci od adresuI.- Dźwięk:
sound_timer > 0powinno grać dźwięk — najprościejputchar('\a')(bell terminala) zamiast prawdziwego audio. - Debugger krokowy: pauza po każdej instrukcji, podgląd rejestrów i stosu — bezcenne narzędzie dydaktyczne samo w sobie.
- Disassembler: osobny program, który zamiast wykonywać ROM, wypisuje go jako czytelny asembler (
JP 0x204zamiast0x1204) — naturalne uzupełnienie tematu “asembler” z pierwszej rozmowy o pomysłach na ćwiczenia.
Podsumowanie kursu
Po tych 5 ćwiczeniach studenci przeszli przez: reprezentację danych w pamięci, architekturę fetch-decode-execute, arytmetykę i flagi procesora, stos wywołań, manipulację bitową, oraz interakcję z urządzeniami wejścia/wyjścia w czasie rzeczywistym — cały czas pisząc jeden, rosnący, kompilowalny program w C, który na koniec realnie uruchamia grę. To rzadka okazja, żeby “podstawy programowania” skończyły się czymś namacalnie efektownym zamiast kolejnego kalkulatora.