pokecrystal-board/home/decompress.asm
vulcandth 3648afda16
RGBDS syntax updates (#905)
New MACRO and DEF syntax
2022-06-06 17:25:42 -04:00

318 lines
4.6 KiB
NASM

FarDecompress::
; Decompress graphics data from a:hl to de.
ld [wLZBank], a
ldh a, [hROMBank]
push af
ld a, [wLZBank]
rst Bankswitch
call Decompress
pop af
rst Bankswitch
ret
Decompress::
; Pokemon GSC uses an lz variant (lz3) for compression.
; This is mainly (but not necessarily) used for graphics.
; This function decompresses lz-compressed data from hl to de.
DEF LZ_END EQU $ff ; Compressed data is terminated with $ff.
; A typical control command consists of:
DEF LZ_CMD EQU %11100000 ; command id (bits 5-7)
DEF LZ_LEN EQU %00011111 ; length n (bits 0-4)
; Additional parameters are read during command execution.
; Commands:
DEF LZ_LITERAL EQU 0 << 5 ; Read literal data for n bytes.
DEF LZ_ITERATE EQU 1 << 5 ; Write the same byte for n bytes.
DEF LZ_ALTERNATE EQU 2 << 5 ; Alternate two bytes for n bytes.
DEF LZ_ZERO EQU 3 << 5 ; Write 0 for n bytes.
; Another class of commands reuses data from the decompressed output.
DEF LZ_RW EQU 2 + 5 ; bit
; 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.
DEF LZ_REPEAT EQU 4 << 5 ; Repeat n bytes from the offset.
DEF LZ_FLIP EQU 5 << 5 ; Repeat n bitflipped bytes.
DEF LZ_REVERSE EQU 6 << 5 ; Repeat n bytes in reverse.
; 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.
DEF LZ_LONG EQU 7 << 5
; 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.
DEF LZ_LONG_HI EQU %00000011
; In other words, the structure of the command becomes
; 111xxxyy yyyyyyyy
; x: the new control command
; y: the length
; Save the output address
; for rewrite commands.
ld a, e
ld [wLZAddress], a
ld a, d
ld [wLZAddress + 1], a
.Main:
ld a, [hl]
cp LZ_END
ret z
and LZ_CMD
cp LZ_LONG
jr nz, .short
; The count is now 10 bits.
; Read the next 3 bits.
; %00011100 -> %11100000
ld a, [hl]
add a
add a ; << 3
add a
; This is our new control code.
and LZ_CMD
push af
ld a, [hli]
and LZ_LONG_HI
ld b, a
ld a, [hli]
ld c, a
; read at least 1 byte
inc bc
jr .command
.short
push af
ld a, [hli]
and LZ_LEN
ld c, a
ld b, 0
; read at least 1 byte
inc c
.command
; Increment loop counts.
; We bail the moment they hit 0.
inc b
inc c
pop af
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
; Read literal data for bc bytes.
.lloop
dec c
jr nz, .lnext
dec b
jp z, .Main
.lnext
ld a, [hli]
ld [de], a
inc de
jr .lloop
.Iter:
; Write the same byte for bc bytes.
ld a, [hli]
.iloop
dec c
jr nz, .inext
dec b
jp z, .Main
.inext
ld [de], a
inc de
jr .iloop
.Alt:
; Alternate two bytes for bc bytes.
dec c
jr nz, .anext1
dec b
jp z, .adone1
.anext1
ld a, [hli]
ld [de], a
inc de
dec c
jr nz, .anext2
dec b
jp z, .adone2
.anext2
ld a, [hld]
ld [de], a
inc de
jr .Alt
; Skip past the bytes we were alternating.
.adone1
inc hl
.adone2
inc hl
jr .Main
.Zero:
; Write 0 for bc bytes.
xor a
.zloop
dec c
jr nz, .znext
dec b
jp z, .Main
.znext
ld [de], a
inc de
jr .zloop
.rewrite
; Repeat decompressed data from output.
push hl
push af
ld a, [hli]
bit 7, a ; sign
jr z, .positive
; negative
; hl = de + -a
and %01111111
cpl
add e
ld l, a
ld a, -1
adc d
ld h, a
jr .ok
.positive
; Positive offsets are two bytes.
ld l, [hl]
ld h, a
; add to starting output address
ld a, [wLZAddress]
add l
ld l, a
ld a, [wLZAddress + 1]
adc h
ld h, a
.ok
pop af
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.
; More practically, LZ_LONG is not recursive.
; For now, it defaults to LZ_REPEAT.
.Repeat:
; Copy decompressed data for bc bytes.
dec c
jr nz, .rnext
dec b
jr z, .donerw
.rnext
ld a, [hli]
ld [de], a
inc de
jr .Repeat
.Flip:
; Copy bitflipped decompressed data for bc bytes.
dec c
jr nz, .fnext
dec b
jp z, .donerw
.fnext
ld a, [hli]
push bc
lb bc, 0, 8
.floop
rra
rl b
dec c
jr nz, .floop
ld a, b
pop bc
ld [de], a
inc de
jr .Flip
.Reverse:
; Copy reversed decompressed data for bc bytes.
dec c
jr nz, .rvnext
dec b
jp z, .donerw
.rvnext
ld a, [hld]
ld [de], a
inc de
jr .Reverse
.donerw
pop hl
bit 7, [hl]
jr nz, .next
inc hl ; positive offset is two bytes
.next
inc hl
jp .Main