Files
disasm/_wip/Golf (JU)/copilot/COMPRESSED_PARSER_AUDIT.md
T
2026-10-18 16:47:03 -04:00

153 lines
5.3 KiB
Markdown

# Pass 1 compressed and packed-data parser audit
## Summary
Four distinct packed-data consumers are confirmed. Only one is a general
run-length decoder. The others are pointer-selected sprite/object lists or
cell-code interpreters.
## 1. `$CBEA`: pointer-selected OAM sprite-list parser
Inputs:
- `$15` selects a sprite-list variant.
- `$16 == 4` selects the pointer tables at `$CC3E/$CC44`; other values select
`$CC24/$CC31`.
- `$33` is added to the generated OAM X coordinate.
- X is the destination OAM-shadow offset.
Format:
- One source byte per sprite.
- `$FF` terminates the list early.
- A hard limit of `$15` (21) source entries prevents runaway parsing.
- The source byte is both the CHR tile index and the index into coordinate
tables `$CC4A` and `$CC5F`.
Output record at `$0200,X`:
- byte 0: `$88 + table_CC5F[tile]` (Y)
- byte 1: source byte (tile)
- byte 2: `$00` (attributes)
- byte 3: `$33 + table_CC4A[tile]` (X)
This is a compact sprite-layout parser, not RLE compression.
## 2. `$DD78-$DE39`: primary course-map RLE decoder
Pointer selection:
- `$2B` is the zero-based hole index.
- `$E6C3,Y` and `$E6D5,Y` form the source pointer in `$04/$05`.
- Destination begins at `$0300` through `$06/$07`.
Header:
- First three source bytes are copied to `$19-$1B`.
- Source pointer then advances by three bytes.
Commands:
- `$FF`: end primary stream.
- `$00-$0F`: emit header byte 0, `(low_nibble + 1)` times.
- `$10-$1F`: emit header byte 1, `(low_nibble + 1)` times.
- `$20-$2F`: emit header byte 2, `(low_nibble + 1)` times.
- `$A0-$AF`: emit `(low_nibble + 1)` values cycling through `$AB-$AD` using
state byte `$8D`.
- `$30-$9F` and `$B0-$FE`: emit the command byte literally.
Output is divided into 16-byte units. After each unit, `$04/$05` advances by
`$1C` consumed source bytes and `$06/$07` advances by `$10` destination bytes.
### Hole 2 / Hole 3 length correction
The decoder does not enforce a 480-byte limit. RAM `$0300-$04FF` is cleared
before decoding, providing a 512-byte destination area. Therefore the measured
outputs are valid:
- Hole 2: 482 bytes
- Hole 3: 483 bytes
- Other currently measured streams: 480 bytes
The earlier 480-byte expectation came from the common case of 30 16-byte
units, not from a decoder bound. Both longer streams remain within the 512-byte
course buffer and do not indicate malformed pointers or an incorrect opcode
model.
## 3. `$DE3B-$DE5D`: optional auxiliary block parser
After the primary `$FF`, the decoder advances the source pointer past the
primary stream and examines the next byte.
- `$55` is a sentinel meaning the optional block is absent.
- Otherwise, records are copied in four-byte groups from the source into
`$0104+`.
- X begins at `$04` and increases by four per record.
- After each group, `$D4F2` advances the corresponding destination/object
bookkeeping.
- Parsing ends when X reaches `$44`, allowing at most 16 four-byte groups.
- `$04/$05` is then advanced by the number of consumed source bytes.
This is a bounded fixed-record block, not a terminator-scanned RLE stream.
## 4. `$DE5E-$DF52`: per-hole OAM/object package parser
The parser begins at the source position following the optional auxiliary
block.
### Fixed setup record
The first bytes initialize OAM-shadow entries beginning at `$0298` and setup
fields `$65-$66`, `$57`, `$1A-$1B`. Tables at `$E37D-$E3DE` expand one compact
source selector into multiple sprite records.
### Variable object list
At `$DF03`, each object record begins with:
- byte 0: object/shape selector, or `$FF` terminator
- byte 1: X/base-position adjustment
- byte 2: Y/base-position adjustment
The selector indexes span tables at `$E283/$E284`, then source tables at
`$E2EB`, `$E2A2`, and `$E334`. One compact three-byte object record expands to
one or more four-byte OAM entries.
- `$FF` terminates the variable object list.
- Values at or above table position `$2B` select OAM attribute `$42`; lower
positions select `$02` through the intentional overlapping-instruction idiom
at `$DF3A/$DF3B`.
- The parser resumes at the next source record using `$1C` as the consumed-byte
offset.
This is a table-expanded object/sprite list, not a byte-run compressor.
## 5. `$D72D-$D7FF`: course-cell code interpreter
This routine reads one byte through `($19),Y` from the generated course map. It
is not a stream decompressor. It interprets cell codes for collision or terrain
response:
- `$EF` and `$FD` are special sentinels.
- Other values index the property table at `$D80D`.
- Property values `$10`, `$20`, `$40`, and `$FF` select distinct collision or
response paths.
- Fine X/Y bits are converted into a bit mask and tested against the selected
property byte.
The `$FF` comparison at `$D74D` belongs to this cell-property dispatch and must
not be mistaken for a compressed-stream terminator.
## Parser-boundary conclusions
- `$CBEA` sprite layouts are bounded by `$FF` or 21 entries.
- Primary hole streams are bounded by their first `$FF` and decode into a
512-byte RAM area, not a fixed 480-byte area.
- Optional auxiliary blocks are bounded by `$55` or 16 four-byte groups.
- Per-hole object lists are bounded by a secondary `$FF` and expand through
fixed lookup tables.
- `$D72D` is a map-cell interpreter, not another compressed-data parser.
No remaining `$FF` comparison in reachable code has been found that represents
an unclassified compressed-stream parser.