# Five Snapshot Analysis

## What The Effect Shows

The captured program is not a simple static picture. It is a composed Atari XL/XE demo screen built from bitmap playfields, player/missile graphics, display-list switching, and display-list interrupts. The visible result is a structured demo/menu-like screen with a stable text and bitmap composition, colored bands, a lower/footer section, and animated or phase-shifted elements that are controlled by ANTIC rather than by redrawing the whole screen every frame.

The important visual idea is that the screen is split into zones. The upper/main body is a wide bitmap area. A secondary lower section uses a different graphics mode and a different bitmap page. Color changes happen at exact scanline positions, so the screen can have more apparent color structure than a single Atari graphics mode would normally allow. The wave-like part appears to come from changing display-list continuation points and DLI vectors over time, not merely from precomputed pixels.

The checker/object-looking elements are partly software-rendered. The program keeps object state, computes row pointers, masks two-bit fields, and merges object bytes into a work/bitmap buffer. At the same time it uses player/missile hardware for horizontal positioning and small overlay details. In other words, the effect is a hybrid: ANTIC handles the frame layout and scanline timing, GTIA/DLI code handles color changes, and 6502 routines update object/checker data in memory.

## Techniques Used

The program uses several classic Atari 8-bit demo techniques together:

- **Split display list**: `$2200` renders the main ANTIC mode `$0E` body and jumps to `$2377`; `$2377` renders the mode `$0F` footer and waits for vertical blank before returning to `$2200`.
- **Display-list interrupts**: DLI bits in the display list call a chain of handlers at `$3005-$315F`.
- **Runtime DLI chaining**: each DLI writes the next `VDSLST` value, so the interrupt sequence is programmable rather than a single fixed handler.
- **WSYNC color timing**: handlers write `WSYNC` before changing `COLPF*` or `COLBK`, producing stable scanline-aligned bands and ramps.
- **Display-list/vector patching**: `$3184-$3226` changes display-list and DLI-vector bytes based on phase state at `$317B/$317C`, which is the likely source of the wave behavior.
- **Software object masking**: object routines use masks at `$2773` (`$FC,$F3,$CF,$3F`) to clear and merge two-bit pixel fields.
- **Inline parameter blocks**: calls to `$24ED` consume bytes immediately following the `JSR`, so some apparent code bytes are actually call-site data.
- **Player/missile assist**: `$2AAF` writes GTIA player/missile horizontal and graphics registers while also updating software bitmap/work buffers.
- **Snapshot resume reconstruction**: the current XEX restores the captured CPU-visible state and resumes at `$2A85`, rather than reconstructing the original packed loader path.

## Baseline

`reconstruction/five_runtime_snapshot_resume.xex` is the working reconstruction baseline. It loads the captured 64 KB runtime image, restores zero page and stack, initializes ANTIC/GTIA/PIA state, and resumes at `$2A85` through an RTI trampoline.

The project is now self-contained:

- `artifacts/five_runtime_64k.bin` is the captured visible 64 KB runtime RAM.
- `reconstruction/five_runtime_snapshot_resume.asm` is the hand-written snapshot-resume loader.
- `exports/main.asm` and `exports/seg_*.asm` are generated mixed code/data MADS source.
- `exports/five_runtime_snapshot_resume_rebuilt.xex` reassembles byte-for-byte to the working snapshot XEX.

The export uses the `project.json` region map. Code regions are emitted as 6502 instructions; data/display/bitmap regions remain `dta`. The result is still byte-exact, so we can keep improving labels, split more mixed regions, and convert display lists to macros without losing binary equivalence.

## Display

The active display is built from two linked display-list regions:

- `$2200`: primary ANTIC mode E bitmap body, mostly LMS entries into `$8000-$9118` plus a first block at `$A000`.
- `$2377`: secondary ANTIC mode F tail/footer, LMS at `$B000`, then sequential lines through `$B3C0`.

The `$2200` list has 149 decoded entries: 139 graphics lines in ANTIC mode `$0E`, one mode `$02` line, four DLI entries, and a terminal `JMP $2377`. The `$2377` list has 28 decoded entries: 25 graphics lines in ANTIC mode `$0F`, five DLI entries, and a terminal `JVB $2200`. Together they form a frame loop split across two display-list fragments.

The saved ANTIC hardware register points at `$2377`, while the OS shadow at `$0230/$0231` points at `$2200`. That is not contradictory: the capture happened mid-frame, when ANTIC had already advanced into the footer/tail list. The full frame still relies on `$2200` as the vertical-blank restart point.

The visible layout is therefore mostly hardware-composed:

- the main bitmap body uses ANTIC mode `$0E` with 40-byte row pointers,
- the footer or lower band uses ANTIC mode `$0F` from `$B000`,
- DLI bits embedded in both lists trigger palette changes at chosen scanline boundaries,
- `$322B-$32D8` appears to scan or patch display-list boundaries and touches `D404`, so there is probably additional timing/display-list management outside the obvious static list bytes.

Algorithmically, this is a way to exceed the limits of a single graphics mode. ANTIC is not just fetching one contiguous screen; it is being fed a script. The LMS entries select specific memory pages for individual rows, the `JMP` joins another list fragment, and the final `JVB` synchronizes the whole construction to vertical blank. Because the display list is data, the program can modify it cheaply compared with redrawing the full bitmap.

## DLI Color Work

The DLI code at `$3005-$315F` is a chained set of handlers. Each handler usually:

1. saves A with `PHA`,
2. synchronizes with `WSYNC`,
3. writes `COLPF1`, `COLPF2`, or `COLBK`,
4. stores the address of the next handler into `VDSLST`,
5. restores A and exits through `RTI`.

The first part of the chain alternates playfield colors:

- `$3005`, `$303B`, `$306F` write `COLPF2` values `$06`, `$0C`, `$08`.
- `$301F`, `$3055`, `$3089` write `COLPF1` values `$0E`, `$0A`, `$06`.
- most of these handlers install the next handler by writing `$0200/$0201`.

The ramps at `$30A6` and `$30EB` write several `COLBK` values on successive `WSYNC`s, creating a vertical color-gradient band. `$30A6` descends through `$DE,$DC,$DA,$D8,$D6,$D4,$D2`; `$30EB` runs the complementary upward sequence while also setting `COLPF1=$D0` and `COLPF2=$DD`.

`$3140` restores `COLPF0..2` from OS color shadows `$02C4-$02C6`, then chains to `$30EB`. `$315F` switches to a separate palette for the mode-F/footer area: `COLPF0=$74`, `COLPF1=$88`, `COLPF2=$9C`, then chains to `$3140`.

`$3184-$3226` is the strongest static evidence for wave motion. It uses phase byte `$317B`, toggle `$317C`, and pointer bytes `$317D-$3180` to patch display-list/vector bytes. The four phase cases write values such as `$2377`, `$2397`, `$23B7`, and two different VDSLST targets. That means the apparent wave is not just precomputed bitmap data: the program is altering where ANTIC/DLI control continues.

## Object/Checker Rendering

The rendering path around `$2CF0-$2E10` calls `$2AAF` repeatedly with object slots and table entries from `$2Cxx`. `$2CF0` starts with a setup call to `$27A8`, loops over eight object slots through `$29D5`, then issues a series of inline-data calls into `$2922` and `$2AAF`.

`$2AAF` is the main object/PMG renderer. It:

- takes object parameters from inline data after the caller's `JSR`,
- uses `$2773` masks (`$FC,$F3,$CF,$3F`) to clear and merge two-bit fields,
- computes source/destination pointers through `$294F`,
- ORs masked object bytes into the target bitmap/work buffer,
- writes player/missile horizontal positions through `HPOSP0+`,
- writes missile shape bits through `GRAFM`,
- caches object state in `$2763/$276B`.

The checker-like parts are therefore not only display-list tricks: there is a software object renderer feeding bitmap/PMG state, while the display list and DLI chain provide the scanline layout and color changes.

The snapshot PC `$2A85` lands inside the mask loop that reads through `($AE),Y`, ANDs against `$2773,X`, and stores back through `($AE),Y`. The stack return address points back into the `$2CF0` scene renderer, which matches the observed runtime: the save-state caught the program while an object/checker mask operation was in progress.

The core object algorithm is read/modify/write on packed pixels. The renderer chooses a mask for the object slot, clears the target two-bit field, computes a source or row pointer, then ORs the shifted object bits into the destination. This is a common compromise on 8-bit machines: the screen memory remains compact, but every moving object requires careful bit masking and alignment.

## Loader And Reconstruction Model

The original `Five to Five.xex` appears packed or staged; the runtime image in the save-state no longer matches the original file byte-for-byte. The reconstruction therefore works from the live 64 KB state rather than from the original loader. The generated XEX is a snapshot-resume program:

1. load the captured visible RAM ranges,
2. restore page-zero and stack bytes,
3. restore ANTIC/GTIA/PIA state needed for the display,
4. build an RTI frame on the stack,
5. resume at the saved instruction boundary `$2A85`.

This is not yet a clean original-style program start. It is a verified runnable runtime reconstruction. The next reverse-engineering milestone is to replace the snapshot resume with a stable frame/main entry once the animation state machine is fully understood.

## Reassembly Workflow

The generated mixed code/data source is in `exports/`:

```text
exports/main.asm
exports/equates.asm
exports/seg_00_0200.asm
...
exports/seg_11_0600.asm
```

Rebuild it with:

```bash
cd /home/ilm/Downloads/5/work/five_snapshot.pyA8/exports
mads main.asm -o:five_runtime_snapshot_resume_rebuilt.xex -l:main.lst
```

The current rebuild is byte-identical to `reconstruction/five_runtime_snapshot_resume.xex`. This matters because we can now improve readability incrementally: split more code/data ranges, add branch-local labels, convert display lists at `$2200/$2377` to structured macros, and convert bitmap/charset blocks to `ins` files while comparing after each step.

## Important Open Questions

- The exact high-level animation state machine still needs live profiling or longer history capture.
- `$322B-$32D8` appears to scan/patch display-list boundaries, but its full call path is not yet proven.
- Extended RAM still appears unnecessary for this reconstructed runtime, but a PORTB sampling pass during the working XEX would be the final proof.
