diff options
Diffstat (limited to 'src/home/decompress.asm')
-rw-r--r-- | src/home/decompress.asm | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/src/home/decompress.asm b/src/home/decompress.asm new file mode 100644 index 0000000..dda25f4 --- /dev/null +++ b/src/home/decompress.asm @@ -0,0 +1,159 @@ +; initializes variables used to decompress data in DecompressData +; de = source of compressed data +; b = HIGH byte of secondary buffer ($100 bytes of buffer space) +; also clears this $100 byte space +InitDataDecompression: + ld hl, wDecompSourcePosPtr + ld [hl], e + inc hl + ld [hl], d + ld hl, wDecompNumCommandBitsLeft + ld [hl], 1 + inc hl + xor a + ld [hli], a ; wDecompCommandByte + ld [hli], a ; wDecompRepeatModeToggle + ld [hli], a ; wDecompRepeatLengths + ld [hli], a ; wDecompNumBytesToRepeat + ld [hl], b ; wDecompSecondaryBufferPtrHigh + inc hl + ld [hli], a ; wDecompRepeatSeqOffset + ld [hl], LOW(wDecompressionSecondaryBufferStart) ; wDecompSecondaryBufferPtrLow + +; clear buffer + ld h, b + ld l, LOW(wDecompressionSecondaryBuffer) + xor a +.loop + ld [hl], a + inc l + jr nz, .loop + ret + +; decompresses data +; uses values initialized by InitDataDecompression +; wDecompSourcePosPtr holds the pointer for compressed source +; input: +; bc = row width +; de = buffer to place decompressed data +DecompressData: + push hl + push de +.loop + push bc + call .Decompress + ld [de], a + inc de + pop bc + dec bc + ld a, c + or b + jr nz, .loop + pop de + pop hl + ret + +; decompression works as follows: +; first a command byte is read that will dictate how the +; following bytes will be copied +; the position will then move to the next byte (0xXY), and +; the command byte's bits are read from higher to lower bit +; - if command bit is set, then copy 0xXY to buffer; +; - if command bit is not set, then decompression enters "repeat mode," +; which means it stores 0xXY in memory as number of bytes to repeat +; from a given offset. This offset is in the next byte in the data, +; 0xZZ, which tells the offset to start repeating. A toggle is switched +; each time the algorithm hits "repeat mode": +; - if off -> on it reads 0xXY and stores it, +; then repeats (0x0X + 2) bytes from the offset starting at 0xZZ; +; - if on -> off, then the data only provides the offset, +; and the previous byte read for number of bytes to repeat, 0xXY, is reused +; in which case (0x0Y + 2) bytes are repeated starting from the offset. +.Decompress: + ld hl, wDecompNumBytesToRepeat + ld a, [hl] + or a + jr z, .read_command + +; still repeating sequence + dec [hl] + inc hl +.repeat_byte + ld b, [hl] ; wDecompSecondaryBufferPtrHigh + inc hl + ld c, [hl] ; wDecompRepeatSeqOffset + inc [hl] + inc hl + ld a, [bc] + ld c, [hl] ; wDecompSecondaryBufferPtrLow + inc [hl] + ld [bc], a + ret + +.read_command + ld hl, wDecompSourcePosPtr + ld c, [hl] + inc hl + ld b, [hl] + inc hl ; wDecompNumCommandBitsLeft + dec [hl] + inc hl ; wDecompCommandByte + jr nz, .read_command_bit + dec hl ; wDecompNumCommandBitsLeft + ld [hl], 8 ; number of bits + inc hl ; wDecompCommandByte + ld a, [bc] + inc bc + ld [hl], a +.read_command_bit + rl [hl] + ld a, [bc] + inc bc + jr nc, .repeat_command + +; copy 1 byte literally + ld hl, wDecompSourcePosPtr + ld [hl], c + inc hl + ld [hl], b + ld hl, wDecompSecondaryBufferPtrHigh + ld b, [hl] + inc hl + inc hl + ld c, [hl] ; wDecompSecondaryBufferPtrLow + inc [hl] + ld [bc], a + ret + +.repeat_command + ld [wDecompRepeatSeqOffset], a ; save the offset to repeat from + ld hl, wDecompRepeatModeToggle + bit 0, [hl] + jr nz, .repeat_mode_toggle_on + set 0, [hl] + inc hl +; read byte for num of bytes to read +; and use its higher nybble + ld a, [bc] + inc bc + ld [hli], a ; wDecompRepeatLengths + swap a +.get_sequence_len + and $f + inc a ; number of times to repeat + ld [hli], a ; wDecompNumBytesToRepeat + push hl + ld hl, wDecompSourcePosPtr + ld [hl], c + inc hl + ld [hl], b + pop hl + jr .repeat_byte + +.repeat_mode_toggle_on +; get the previous byte (num of bytes to repeat) +; and use its lower nybble + res 0, [hl] + inc hl + ld a, [hli] ; wDecompRepeatLengths + jr .get_sequence_len |