Final Fantasy VI:Compression Format
The game has a very basic compression for some of it's data, such as the intro credits as Terra, Vicks, and Wedge are marching towards Narshe.
The compression is called by first placing the starting address of the compressed data in $F3, and the destination address in RAM in $F6, then a JSL to $C2FF6D.
The compressed data has a very simple format
- 2 bytes at the start specify the size of the compressed data (self-inclusive)
- The next byte is used as 8 bitflags, read lowest bit first: 0th bit is the first bit checked, 7th bit is the last bit checked.
- If the next bit is set, then it puts the next byte into the destination address and in a 2048-byte (800h) buffer.
- If the next bit is clear, then it uses the next 2 bytes to copy from the buffer:
- The 11 low bits are an absolute pointer into the 800h byte buffer (11 bits = xxx xxxx xxxx = max of 7FF)
- The 5 high bits specify how many bytes to copy from that buffer to the destination address, plus 3 (it will copy between 3 and 66 bytes, in decimal).
- The game copies the given bytes to the destination address AND back into the buffer.
When all 8 bits from the current bit-flag byte have been checked, the game uses the next byte as another bitflag. This loop is repeated until the game has decompressed the amount of bytes in ROM specified at the start of the compressed data.
Some notes on the actual code:
- Source address is in $F3 (3 bytes)
- Destination address is in $F6 (3 bytes)
- Size to decompress is in $FC (2 bytes)
- The 800h byte buffer is located at 7F:F800 - 7F:FFFF
- The game starts writing to the buffer at offset 7DE (7F:FFDE) and goes up. It goes back to 000 after 7FF.
- Y holds the relative offset of the byte it's currently decompressing: ($F3) + Y = pointer to current byte
- X holds the buffer offset; 7F:F800,X
- When processing 'clear' bits, Y is backed up in $F9 and used as the read position in the buffer.