commit
08218f3cda
5 changed files with 207 additions and 0 deletions
@ -0,0 +1,125 @@
|
||||
# AGENTS.md — gameboy-hello |
||||
|
||||
Knowledge base for this Game Boy Hello World project and related tools/workflow. |
||||
|
||||
## Project overview |
||||
|
||||
- **Repository**: `ssh://git@git.enne2.net:222/enne2/gameboy-hello.git` |
||||
- **Local path**: `/home/enne2/Development/gameboy-hello` |
||||
- **Goal**: Minimal Game Boy "Hello World" using GBDK-2020 (C) and headless verification with PyBoy. |
||||
- **Artifacts**: |
||||
- `main.c` — C source (`<gb/gb.h>`, `<stdio.h>`, `printf("Hello Game Boy!")`). |
||||
- `Makefile` — builds `hello.gb` with `/home/enne2/.local/gbdk/bin/lcc`. |
||||
- `hello.gb` — generated 32 KB Game Boy ROM. |
||||
- `README.md` — user-facing build/run instructions. |
||||
- This `AGENTS.md` — captured knowledge for coding agents. |
||||
|
||||
## Game Boy development stack |
||||
|
||||
### Toolchain: GBDK-2020 |
||||
|
||||
- **Location**: `/home/enne2/.local/gbdk` (downloaded from GitHub release, no system install needed). |
||||
- **Compiler frontend**: `/home/enne2/.local/gbdk/bin/lcc` |
||||
- **Typical flags used**: |
||||
- `-Wl-yt1` — MBC type 1 (ROM only). |
||||
- `-Wl-ya4` — 4 RAM banks. |
||||
- **Build command**: |
||||
```bash |
||||
cd /home/enne2/Development/gameboy-hello |
||||
make |
||||
``` |
||||
- **Important**: GBDK C is compiled to SM83/Z80-like assembly by SDCC. It is higher-level than RGBDS assembly but slower and with larger ROM footprint. Critical sections can still be written in assembly if needed. |
||||
|
||||
### Hello World source pattern |
||||
|
||||
```c |
||||
#include <gb/gb.h> |
||||
#include <stdio.h> |
||||
|
||||
void main(void) { |
||||
printf("Hello Game Boy!"); |
||||
while (1) { |
||||
wait_vbl_done(); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
- `wait_vbl_done()` synchronizes with the vertical blank interval; always call inside the main loop. |
||||
- `printf` renders to the Game Boy's text console/tilemap area. |
||||
|
||||
### Emulation / verification |
||||
|
||||
- **PyBoy** installed via `pip install --user pyboy`. |
||||
- **Headless screenshot test** (useful for CI/agent verification): |
||||
```python |
||||
from pyboy import PyBoy |
||||
pyboy = PyBoy('hello.gb', window='null') |
||||
for _ in range(60 * 5): |
||||
pyboy.tick() |
||||
pyboy.screen.image.save('/tmp/hello_gb.png') |
||||
pyboy.stop() |
||||
``` |
||||
- **SDL2 window test**: |
||||
```python |
||||
from pyboy import PyBoy |
||||
pyboy = PyBoy('hello.gb', window='SDL2') |
||||
for _ in range(60 * 30): |
||||
pyboy.tick() |
||||
pyboy.stop() |
||||
``` |
||||
- ROM validation: check Nintendo logo at offset `0x104` (48 bytes) and header checksum at `0x14D`. |
||||
|
||||
## Game Boy hardware limits (relevant for future expansion) |
||||
|
||||
- **CPU**: Sharp SM83 @ ~4.19 MHz (Z80-like). |
||||
- **VRAM**: 8 KB; only writable during VBlank/HBlank. |
||||
- **OAM sprites**: max 40 total, max 10 per scanline. |
||||
- **Tilemap**: 20×18 visible or 32×32 total. |
||||
- **Audio**: 4 channels (2 square, 1 wave, 1 noise). |
||||
- **Cartridge MBC**: this project uses MBC1 with `-Wl-yt1 -Wl-ya4`. |
||||
|
||||
## Reverse-engineering Tetris (original Game Boy) |
||||
|
||||
Learned from `kaspermeerts/tetris` disassembly and other sources: |
||||
|
||||
- **Piece representation**: each piece is a 4-block sprite rendered into OAM; rotation is selected by the lowest 2 bits of a state byte (4 pre-rotated sprites per piece type). |
||||
- **Rotation logic**: `RotateAndShiftPiece` increments/decrements orientation, renders into OAM buffer, calls `DetectCollision`, and **cancels the rotation on collision** (no SRS-style wall kicks). |
||||
- **Collision detection**: done on the rendered OAM sprites by looking up background tiles; a non-space tile means collision. |
||||
- **Randomizer (`PickRandomPiece`)**: uses `rDIV` hardware divider as entropy and rerolls up to 3 times if the new piece matches the previous one (history of 1). It is NOT a modern 7-bag randomizer. |
||||
- **DAS (Delayed Auto Shift)**: 23 frames before auto-repeat, then 9 frames per repeat. |
||||
- **Scoring**: BCD arithmetic, level-dependent multipliers. |
||||
- **Bugs/trivia**: |
||||
- Top two rows can never be cleared (only 16 of 18 rows are checked). |
||||
- When clearing multiple lines, the top row is duplicated below — likely an oversight. |
||||
- Demo recording code exists but is unused. |
||||
|
||||
## pi-hitl-programming extension knowledge |
||||
|
||||
- **Goal**: Human-in-the-Loop gate for `write`/`edit` on programming/config files. |
||||
- **Source**: `/home/enne2/Development/pi-hitl/src/index.ts` |
||||
- **Behavior**: |
||||
- Intercepts `write`/`edit` for file extensions like `.py`, `.js`, `.ts`, `.c`, `.cpp`, `.go`, `.rs`, `.sh`, `.html`, `.css`, `.json`, `.yaml`, `.toml`, `.md`, etc. |
||||
- Generates a short LLM explanation of the proposed code. |
||||
- Shows a scrollable panel with explanation + proposed code. |
||||
- Lets user choose: Accept / Modify / Discuss / Reject. |
||||
- Can be toggled with `F10` or `/hitl on|off`. |
||||
- **Lessons learned**: |
||||
- Long explanations cause UI flashing and scrolling issues; keep explanation prompt to 5–6 lines. |
||||
- Use fixed-height scrollable panel for code preview; avoid full-screen expansion. |
||||
- Avoid `PageUp`/`PageDown` bindings that may crash; use `Ctrl+U`/`Ctrl+D` instead. |
||||
- Pass the full source code (up to 60k chars) to the LLM for explanation, not only the TUI preview. |
||||
|
||||
## General workflow rules |
||||
|
||||
- When writing or modifying files, always use the `write` or `edit` tool; never use shell redirections to bypass HITL review. |
||||
- For C/C++ code, `<` in content may be truncated by certain providers; use placeholder replacement if needed. |
||||
- Prefer `python3 -m py_compile` for quick syntax checks on Python scripts. |
||||
- Use `tmux` for interactive TUI tests when the agent cannot open a real terminal. |
||||
|
||||
## Follow-up ideas |
||||
|
||||
- Expand this project into a real Game Boy Tetris faithful to the original: |
||||
- Use sprite OAM for pieces (4 blocks per piece). |
||||
- Implement the original orientation-based rotation and collision cancel logic. |
||||
- Replicate the original `rDIV`-based randomizer with 1-history reroll. |
||||
- Add DAS, BCD scoring, and proper line-clear behavior. |
||||
@ -0,0 +1,10 @@
|
||||
CC = /home/enne2/.local/gbdk/bin/lcc
|
||||
CFLAGS = -Wl-yt1 -Wl-ya4
|
||||
|
||||
hello.gb: main.c |
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
clean: |
||||
rm -f *.gb *.ihx *.cdb *.adb *.noi *.map *.lst *.sym *.rel
|
||||
|
||||
.PHONY: clean |
||||
@ -0,0 +1,63 @@
|
||||
# Game Boy Hello World |
||||
|
||||
Questa sottocartella contiene un minimo esempio di "Hello World" per Game Boy originale, compilato con **GBDK-2020** in C. |
||||
|
||||
## Struttura |
||||
|
||||
- `main.c` — sorgente C. |
||||
- `Makefile` — regola per compilare con `lcc` (GBDK-2020). |
||||
- `hello.gb` — ROM Game Boy risultante (32 KB). |
||||
|
||||
## Requisiti |
||||
|
||||
GBDK-2020 e installato in `/home/enne2/.local/gbdk`. Se vuoi spostarlo altrove, aggiorna il `CC` nel `Makefile`. |
||||
|
||||
## Build |
||||
|
||||
```bash |
||||
cd gameboy-hello |
||||
make |
||||
``` |
||||
|
||||
## Test con emulatore |
||||
|
||||
### PyBoy (senza finestra, screenshot) |
||||
|
||||
```bash |
||||
python3 - <<'PY' |
||||
from pyboy import PyBoy |
||||
rom = 'hello.gb' |
||||
pyboy = PyBoy(rom, window='null') |
||||
for _ in range(60*5): |
||||
pyboy.tick() |
||||
pyboy.screen.image.save('/tmp/hello_gb.png') |
||||
pyboy.stop() |
||||
print('Screenshot salvato in /tmp/hello_gb.png') |
||||
PY |
||||
``` |
||||
|
||||
### PyBoy (con finestra SDL2) |
||||
|
||||
```bash |
||||
python3 - <<'PY' |
||||
from pyboy import PyBoy |
||||
pyboy = PyBoy('hello.gb', window='SDL2') |
||||
for _ in range(60*30): |
||||
pyboy.tick() |
||||
pyboy.stop() |
||||
PY |
||||
``` |
||||
|
||||
## Note |
||||
|
||||
- La ROM usa il logo Nintendo corretto e il checksum di header e valido. |
||||
- Il testo viene visualizzato con `printf` sulla console testuale del Game Boy. |
||||
- Il loop principale chiama `wait_vbl_done()` per sincronizzarsi con il VBlank. |
||||
|
||||
## Prossimi passi |
||||
|
||||
Da qui si puo partire per un vero gioco Game Boy (ad esempio Tetris), aggiungendo: |
||||
- gestione di input tramite `joypad()`; |
||||
- sprite OAM per i pezzi; |
||||
- tilemap per il campo di gioco; |
||||
- musica/effetti sonori con i 4 canali audio del Game Boy. |
||||
Binary file not shown.
Loading…
Reference in new issue