Final Fantasy VI/Compression Format: Difference between revisions

From Data Crystal
Jump to navigation Jump to search
mNo edit summary
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
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.
{{subpage}}
 
The game has a very basic compression for some of its 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 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
The compressed data has a very simple format:
* 2 bytes at the start specify the size of the compressed data (self-inclusive)
* 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.
* 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 an 800 byte buffer.
* 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:  
* 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 800 byte buffer (11 bits = xxx xxxx xxxx = max of 7FF)
**  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 5 high bits specify how many bytes to copy from that buffer to the destination address, plus 3 (it will copy between 3 and 34 bytes, in decimal).
**  The game copies the given bytes to the destination address AND back into the buffer.
**  The game copies the given bytes to the destination address AND back into the buffer.


Line 18: Line 20:
* Destination address is in $F6 (3 bytes)
* Destination address is in $F6 (3 bytes)
* Size to decompress is in $FC (2 bytes)
* Size to decompress is in $FC (2 bytes)
* The 800 byte buffer is located at 7F:F800 - 7F:FFFF
* 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.
* 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
* 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
* 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.
* When processing 'clear' bits, Y is backed up in $F9 and used as the read position in the buffer.

Latest revision as of 14:58, 24 January 2024

This is a sub-page of Final Fantasy VI.

The game has a very basic compression for some of its 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 34 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.