5.3 KiB
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:
$15selects a sprite-list variant.$16 == 4selects the pointer tables at$CC3E/$CC44; other values select$CC24/$CC31.$33is added to the generated OAM X coordinate.- X is the destination OAM-shadow offset.
Format:
- One source byte per sprite.
$FFterminates 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
$CC4Aand$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:
$2Bis the zero-based hole index.$E6C3,Yand$E6D5,Yform the source pointer in$04/$05.- Destination begins at
$0300through$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-$ADusing state byte$8D.$30-$9Fand$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.
$55is a sentinel meaning the optional block is absent.- Otherwise, records are copied in four-byte groups from the source into
$0104+. - X begins at
$04and increases by four per record. - After each group,
$D4F2advances the corresponding destination/object bookkeeping. - Parsing ends when X reaches
$44, allowing at most 16 four-byte groups. $04/$05is 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
$FFterminator - 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.
$FFterminates the variable object list.- Values at or above table position
$2Bselect OAM attribute$42; lower positions select$02through the intentional overlapping-instruction idiom at$DF3A/$DF3B. - The parser resumes at the next source record using
$1Cas 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:
$EFand$FDare special sentinels.- Other values index the property table at
$D80D. - Property values
$10,$20,$40, and$FFselect 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
$CBEAsprite layouts are bounded by$FFor 21 entries.- Primary hole streams are bounded by their first
$FFand decode into a 512-byte RAM area, not a fixed 480-byte area. - Optional auxiliary blocks are bounded by
$55or 16 four-byte groups. - Per-hole object lists are bounded by a secondary
$FFand expand through fixed lookup tables. $D72Dis 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.