pokecrystal-board/home/decompress.asm

323 lines
4.7 KiB
NASM
Raw Normal View History

2018-06-24 07:09:41 -07:00
FarDecompress::
2014-06-03 14:08:23 -07:00
; Decompress graphics data from a:hl to de.
2013-08-20 00:34:54 -07:00
2014-07-18 05:33:27 -07:00
ld [wLZBank], a
2013-08-20 00:34:54 -07:00
ld a, [hROMBank]
push af
2014-07-18 05:33:27 -07:00
ld a, [wLZBank]
2013-08-20 00:34:54 -07:00
rst Bankswitch
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
call Decompress
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
pop af
rst Bankswitch
ret
2018-06-24 07:09:41 -07:00
Decompress::
2013-08-20 00:34:54 -07:00
; Pokemon Crystal uses an lz variant for compression.
2014-06-03 14:08:23 -07:00
; This is mainly (but not necessarily) used for graphics.
; This function decompresses lz-compressed data from hl to de.
LZ_END EQU $ff ; Compressed data is terminated with $ff.
; A typical control command consists of:
LZ_CMD EQU %11100000 ; command id (bits 5-7)
LZ_LEN EQU %00011111 ; length n (bits 0-4)
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; Additional parameters are read during command execution.
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; Commands:
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
LZ_LITERAL EQU 0 << 5 ; Read literal data for n bytes.
LZ_ITERATE EQU 1 << 5 ; Write the same byte for n bytes.
LZ_ALTERNATE EQU 2 << 5 ; Alternate two bytes for n bytes.
LZ_ZERO EQU 3 << 5 ; Write 0 for n bytes.
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; Another class of commands reuses data from the decompressed output.
LZ_RW EQU 2 + 5 ; bit
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; These commands take a signed offset to start copying from.
; Wraparound is simulated.
; Positive offsets (15-bit) are added to the start address.
; Negative offsets (7-bit) are subtracted from the current position.
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
LZ_REPEAT EQU 4 << 5 ; Repeat n bytes from the offset.
LZ_FLIP EQU 5 << 5 ; Repeat n bitflipped bytes.
LZ_REVERSE EQU 6 << 5 ; Repeat n bytes in reverse.
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; If the value in the count needs to be larger than 5 bits,
; LZ_LONG can be used to expand the count to 10 bits.
LZ_LONG EQU 7 << 5
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; A new control command is read in bits 2-4.
; The top two bits of the length are bits 0-1.
; Another byte is read containing the bottom 8 bits.
LZ_LONG_HI EQU %00000011
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; In other words, the structure of the command becomes
; 111xxxyy yyyyyyyy
; x: the new control command
; y: the length
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; For more information, refer to the code below and in extras/gfx.py.
2013-08-20 00:34:54 -07:00
2014-06-03 14:08:23 -07:00
; Save the output address
; for rewrite commands.
2013-08-20 00:34:54 -07:00
ld a, e
2014-07-18 05:33:27 -07:00
ld [wLZAddress], a
2013-08-20 00:34:54 -07:00
ld a, d
2014-07-18 05:33:27 -07:00
ld [wLZAddress + 1], a
2014-06-03 14:08:23 -07:00
.Main:
2013-08-20 00:34:54 -07:00
ld a, [hl]
2014-06-03 14:08:23 -07:00
cp LZ_END
2013-08-20 00:34:54 -07:00
ret z
2014-06-03 14:08:23 -07:00
and LZ_CMD
cp LZ_LONG
jr nz, .short
.long
; The count is now 10 bits.
; Read the next 3 bits.
; %00011100 -> %11100000
2013-08-20 00:34:54 -07:00
ld a, [hl]
add a
add a ; << 3
add a
2014-06-03 14:08:23 -07:00
2016-06-07 05:13:08 -07:00
; This is our new control code.
2014-06-03 14:08:23 -07:00
and LZ_CMD
2013-08-20 00:34:54 -07:00
push af
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
ld a, [hli]
2014-06-03 14:08:23 -07:00
and LZ_LONG_HI
2013-08-20 00:34:54 -07:00
ld b, a
ld a, [hli]
ld c, a
2014-06-03 14:08:23 -07:00
; read at least 1 byte
2013-08-20 00:34:54 -07:00
inc bc
2014-06-03 14:08:23 -07:00
jr .command
.short
2013-08-20 00:34:54 -07:00
push af
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
ld a, [hli]
2014-06-03 14:08:23 -07:00
and LZ_LEN
2013-08-20 00:34:54 -07:00
ld c, a
2014-06-03 14:08:23 -07:00
ld b, 0
; read at least 1 byte
2013-08-20 00:34:54 -07:00
inc c
2014-06-03 14:08:23 -07:00
.command
; Increment loop counts.
; We bail the moment they hit 0.
2013-08-20 00:34:54 -07:00
inc b
inc c
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
pop af
2014-06-03 14:08:23 -07:00
bit LZ_RW, a
jr nz, .rewrite
cp LZ_ITERATE
jr z, .Iter
cp LZ_ALTERNATE
jr z, .Alt
cp LZ_ZERO
jr z, .Zero
.Literal:
2014-06-03 14:08:23 -07:00
; Read literal data for bc bytes.
.lloop
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .lnext
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .Main
.lnext
2013-08-20 00:34:54 -07:00
ld a, [hli]
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
jr .lloop
.Iter:
2014-06-03 14:08:23 -07:00
; Write the same byte for bc bytes.
2013-08-20 00:34:54 -07:00
ld a, [hli]
2014-06-03 14:08:23 -07:00
2014-07-18 05:33:27 -07:00
.iloop
2013-08-20 00:34:54 -07:00
dec c
2014-07-18 05:33:27 -07:00
jr nz, .inext
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .Main
2014-07-18 05:33:27 -07:00
.inext
2013-08-20 00:34:54 -07:00
ld [de], a
inc de
2014-07-18 05:33:27 -07:00
jr .iloop
2014-06-03 14:08:23 -07:00
.Alt:
2014-06-03 14:08:23 -07:00
; Alternate two bytes for bc bytes.
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .anext1
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .adone1
.anext1
2013-08-20 00:34:54 -07:00
ld a, [hli]
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .anext2
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .adone2
.anext2
2013-08-20 00:34:54 -07:00
ld a, [hld]
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
jr .Alt
; Skip past the bytes we were alternating.
.adone1
2013-08-20 00:34:54 -07:00
inc hl
2014-06-03 14:08:23 -07:00
.adone2
2013-08-20 00:34:54 -07:00
inc hl
2014-06-03 14:08:23 -07:00
jr .Main
.Zero:
2014-06-03 14:08:23 -07:00
; Write 0 for bc bytes.
2013-08-20 00:34:54 -07:00
xor a
2014-06-03 14:08:23 -07:00
.zloop
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .znext
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .Main
.znext
2013-08-20 00:34:54 -07:00
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
jr .zloop
.rewrite
; Repeat decompressed data from output.
2013-08-20 00:34:54 -07:00
push hl
push af
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
ld a, [hli]
2014-06-03 14:08:23 -07:00
bit 7, a ; sign
jr z, .positive
.negative
; hl = de - a
; Since we can't subtract a from de,
; Make it negative and add de.
and %01111111
2013-08-20 00:34:54 -07:00
cpl
add e
ld l, a
2014-06-03 14:08:23 -07:00
ld a, -1
2013-08-20 00:34:54 -07:00
adc d
ld h, a
2014-06-03 14:08:23 -07:00
jr .ok
.positive
; Positive offsets are two bytes.
2013-08-20 00:34:54 -07:00
ld l, [hl]
ld h, a
2014-06-03 14:08:23 -07:00
; add to starting output address
2014-07-18 05:33:27 -07:00
ld a, [wLZAddress]
2013-08-20 00:34:54 -07:00
add l
ld l, a
2014-07-18 05:33:27 -07:00
ld a, [wLZAddress + 1]
2013-08-20 00:34:54 -07:00
adc h
ld h, a
2014-06-03 14:08:23 -07:00
.ok
2013-08-20 00:34:54 -07:00
pop af
2014-06-03 14:08:23 -07:00
cp LZ_REPEAT
jr z, .Repeat
cp LZ_FLIP
jr z, .Flip
cp LZ_REVERSE
jr z, .Reverse
; Since LZ_LONG is command 7,
; only commands 0-6 are passed in.
; This leaves room for an extra command 7.
; However, lengths longer than 768
; would be interpreted as LZ_END.
2014-07-18 05:33:27 -07:00
; More practically, LZ_LONG is not recursive.
2014-06-03 14:08:23 -07:00
; For now, it defaults to LZ_REPEAT.
.Repeat:
2014-06-03 14:08:23 -07:00
; Copy decompressed data for bc bytes.
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .rnext
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jr z, .donerw
.rnext
2013-08-20 00:34:54 -07:00
ld a, [hli]
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
jr .Repeat
.Flip:
2014-06-03 14:08:23 -07:00
; Copy bitflipped decompressed data for bc bytes.
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .fnext
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .donerw
.fnext
2013-08-20 00:34:54 -07:00
ld a, [hli]
push bc
2014-06-03 14:08:23 -07:00
lb bc, 0, 8
.floop
2013-08-20 00:34:54 -07:00
rra
rl b
dec c
2014-06-03 14:08:23 -07:00
jr nz, .floop
2014-07-18 05:33:27 -07:00
2013-08-20 00:34:54 -07:00
ld a, b
pop bc
2014-07-18 05:33:27 -07:00
2013-08-20 00:34:54 -07:00
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
jr .Flip
.Reverse:
2014-06-03 14:08:23 -07:00
; Copy reversed decompressed data for bc bytes.
2013-08-20 00:34:54 -07:00
dec c
2014-06-03 14:08:23 -07:00
jr nz, .rvnext
2013-08-20 00:34:54 -07:00
dec b
2014-06-03 14:08:23 -07:00
jp z, .donerw
.rvnext
2013-08-20 00:34:54 -07:00
ld a, [hld]
ld [de], a
inc de
2014-06-03 14:08:23 -07:00
jr .Reverse
.donerw
2013-08-20 00:34:54 -07:00
pop hl
2014-06-03 14:08:23 -07:00
2013-08-20 00:34:54 -07:00
bit 7, [hl]
jr nz, .next
2014-06-03 14:08:23 -07:00
inc hl ; positive offset is two bytes
2013-08-20 00:34:54 -07:00
.next
inc hl
2014-06-03 14:08:23 -07:00
jp .Main