# 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.