SPEC: make conform-only a first-class adoption path; concrete Agon /regs shape 42c217d9aaf7
The FAB Agon emulator is Rust and conforms to the contract directly rather than vendoring the C core. Document both adoption paths and add a concrete ADL /regs example; conformance/ is the arbiter either way. Git-Commit: 79c2f15dcc0193cf7415fcbb67a934a470bac4ac Git-Author: Andy McCall <[email protected]>
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-07-19 18:44 UTC
- Signature
- ◈ sealed by Andy McCall
- Hash
42c217d9aaf726fb8b0c38482e4b340e9257b19614b6c16006581b269ee42b2b- Depends on
- 961b3c610c66
- Depended on by
- 67065eaa1a13 674b8447022b d44319b1e712
- In bookmarks
- main perf-6
- Edits
- 6 atoms, 0 tree operations, 1 file
Browse the tree at this change
modified SPEC.md +29 −9
| … | 143 unchanged lines |
||
| 144 | 144 | - Framebuffer: native resolution per the emulator's video mode. |
|
| 145 | 145 | ||
| 146 | 146 | ### Agon (Console8 / Light 2) — FAB Agon Emulator |
|
| 147 | + | - **Adoption:** conform-only (Rust emulator — keeps its own HTTP server, matches |
|
| 148 | + | this contract rather than vendoring the C core). |
|
| 147 | 149 | - Flag: `--control-port <N>`. |
|
| 148 | 150 | - Address space: eZ80 24-bit, flat 16 MB (`addr` up to `0xFFFFFF`); `bank` |
|
| 149 | - | ignored. Program load base `0x040000`. |
|
| 150 | - | - Registers (ADL): `af bc de hl ix iy sp pc mbase` + ADL-mode flag. |
|
| 151 | - | - Framebuffer: from `vgabuf` (the VDP output), server swizzles to PPM RGB. |
|
| 151 | + | tolerated and ignored. Program load base `0x040000`. |
|
| 152 | + | - Registers (ADL) — `/regs` example (16-bit regs; `mbase` 8-bit; `adl` 0/1): |
|
| 153 | + | ```json |
|
| 154 | + | { "af":0, "bc":0, "de":0, "hl":0, "ix":0, "iy":0, |
|
| 155 | + | "sp":0, "pc":262144, "mbase":0, "adl":1 } |
|
| 156 | + | ``` |
|
| 157 | + | - Framebuffer: from `vgabuf` (the VDP output); the offscreen path already keeps |
|
| 158 | + | video alive (the FAB equivalent of x16's `SDL_VIDEODRIVER=dummy`). |
|
| 152 | 159 | ||
| 153 | 160 | --- |
|
| 154 | 161 | ||
| 155 | - | ## Reference implementations in this repo |
|
| 162 | + | ## Adoption paths |
|
| 156 | 163 | ||
| 157 | - | - `core/retro_control.h` — the portable backend vtable each fork implements. |
|
| 158 | - | - `core/retro_control.c` — the shared server (socket loop, HTTP parse, PPM/JSON |
|
| 159 | - | encode, command marshalling). Forks vendor/submodule this and call |
|
| 160 | - | `retro_control_start(port, &backend)`. *(server .c lands next.)* |
|
| 164 | + | An emulator conforms by exposing exactly the HTTP surface above — nothing else |
|
| 165 | + | is required. Two ways to get there: |
|
| 166 | + | ||
| 167 | + | - **Vendor the shared core** (`core/retro_control.c` + `.h`) — for C/C++ |
|
| 168 | + | emulators. Implement the four backend callbacks, wire three loop hooks, call |
|
| 169 | + | `retro_control_start(port, &backend)`; the socket loop, HTTP parsing, PPM/JSON |
|
| 170 | + | encoding and pause/step control come for free. The Commander X16 fork does this. |
|
| 171 | + | - **Conform directly** — for emulators in other languages (the FAB Agon emulator |
|
| 172 | + | is Rust). Keep your own HTTP server; just match the contract and pass the |
|
| 173 | + | conformance suite. Sharing the C core is an optimization, not a requirement — |
|
| 174 | + | the contract is the asset. |
|
| 175 | + | ||
| 176 | + | Either way, `conformance/` is the arbiter: pass it and you conform. |
|
| 177 | + | ||
| 178 | + | ## In this repo |
|
| 179 | + | ||
| 180 | + | - `core/retro_control.{c,h}` — portable server + backend vtable (vendor path). |
|
| 161 | 181 | - `client/emu_control.py` — the shared pytest client. |
|
| 162 | - | - `conformance/` — tests an emulator runs to prove it conforms. *(next.)* |
|
| 182 | + | - `conformance/` — a platform-agnostic pytest that proves an emulator conforms. |