mirror of https://github.com/pret/pokecrystal.git
Recomment lz deecompression.
This commit is contained in:
parent
20444d2f63
commit
21708a2271
|
@ -1,19 +1,14 @@
|
||||||
FarDecompress:: ; b40
|
FarDecompress:: ; b40
|
||||||
; Decompress graphics data at a:hl to de
|
; Decompress graphics data from a:hl to de.
|
||||||
|
|
||||||
; put a away for a sec
|
|
||||||
ld [$c2c4], a
|
ld [$c2c4], a
|
||||||
; save bank
|
|
||||||
ld a, [hROMBank]
|
ld a, [hROMBank]
|
||||||
push af
|
push af
|
||||||
; bankswitch
|
|
||||||
ld a, [$c2c4]
|
ld a, [$c2c4]
|
||||||
rst Bankswitch
|
rst Bankswitch
|
||||||
|
|
||||||
; what we came here for
|
|
||||||
call Decompress
|
call Decompress
|
||||||
|
|
||||||
; restore bank
|
|
||||||
pop af
|
pop af
|
||||||
rst Bankswitch
|
rst Bankswitch
|
||||||
ret
|
ret
|
||||||
|
@ -22,170 +17,158 @@ FarDecompress:: ; b40
|
||||||
|
|
||||||
Decompress:: ; b50
|
Decompress:: ; b50
|
||||||
; Pokemon Crystal uses an lz variant for compression.
|
; Pokemon Crystal uses an lz variant for compression.
|
||||||
|
; This is mainly (but not necessarily) used for graphics.
|
||||||
|
|
||||||
; This is mainly used for graphics, but the intro's
|
; This function decompresses lz-compressed data from hl to de.
|
||||||
; tilemaps also use this compression.
|
|
||||||
|
|
||||||
; This function decompresses lz-compressed data at hl to de.
|
|
||||||
|
|
||||||
|
|
||||||
; Basic rundown:
|
LZ_END EQU $ff ; Compressed data is terminated with $ff.
|
||||||
|
|
||||||
|
|
||||||
; A typical control command consists of:
|
; A typical control command consists of:
|
||||||
; -the command (bits 5-7)
|
|
||||||
; -the count (bits 0-4)
|
|
||||||
; -and any additional params
|
|
||||||
|
|
||||||
; $ff is used as a terminator.
|
LZ_CMD EQU %11100000 ; command id (bits 5-7)
|
||||||
|
LZ_LEN EQU %00011111 ; length n (bits 0-4)
|
||||||
|
|
||||||
|
; Additional parameters are read during command execution.
|
||||||
|
|
||||||
|
|
||||||
; Commands:
|
; Commands:
|
||||||
|
|
||||||
; 0: literal
|
LZ_LITERAL EQU 0 << 5 ; Read literal data for n bytes.
|
||||||
; literal data for some number of bytes
|
LZ_ITERATE EQU 1 << 5 ; Write the same byte for n bytes.
|
||||||
; 1: iterate
|
LZ_ALTERNATE EQU 2 << 5 ; Alternate two bytes for n bytes.
|
||||||
; one byte repeated for some number of bytes
|
LZ_ZERO EQU 3 << 5 ; Write 0 for n bytes.
|
||||||
; 2: alternate
|
|
||||||
; two bytes alternated for some number of bytes
|
|
||||||
; 3: zero (whitespace)
|
|
||||||
; 0x00 repeated for some number of bytes
|
|
||||||
|
|
||||||
; Repeater control commands have a signed parameter used to determine the start point.
|
|
||||||
; Wraparound is simulated:
|
|
||||||
; Positive values are added to the start address of the decompressed data
|
|
||||||
; and negative values are subtracted from the current position.
|
|
||||||
|
|
||||||
; 4: repeat
|
; Another class of commands reuses data from the decompressed output.
|
||||||
; repeat some number of bytes from decompressed data
|
LZ_RW EQU 2 + 5 ; bit
|
||||||
; 5: flipped
|
|
||||||
; repeat some number of flipped bytes from decompressed data
|
; These commands take a signed offset to start copying from.
|
||||||
; ex: $ad = %10101101 -> %10110101 = $b5
|
; Wraparound is simulated.
|
||||||
; 6: reverse
|
; Positive offsets (15-bit) are added to the start address.
|
||||||
; repeat some number of bytes in reverse from decompressed data
|
; Negative offsets (7-bit) are subtracted from the current position.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
; If the value in the count needs to be larger than 5 bits,
|
; If the value in the count needs to be larger than 5 bits,
|
||||||
; control code 7 can be used to expand the count to 10 bits.
|
; LZ_LONG can be used to expand the count to 10 bits.
|
||||||
|
LZ_LONG EQU 7 << 5
|
||||||
|
|
||||||
; A new control command is read in bits 2-4.
|
; A new control command is read in bits 2-4.
|
||||||
; The new 10-bit count is split:
|
; The top two bits of the length are bits 0-1.
|
||||||
; bits 0-1 contain the top 2 bits
|
; Another byte is read containing the bottom 8 bits.
|
||||||
; another byte is added containing the latter 8
|
LZ_LONG_HI EQU %00000011
|
||||||
|
|
||||||
; So, the structure of the control command becomes:
|
; In other words, the structure of the command becomes
|
||||||
; 111xxxyy yyyyyyyy
|
; 111xxxyy yyyyyyyy
|
||||||
; | | | |
|
; x: the new control command
|
||||||
; | | our new count
|
; y: the length
|
||||||
; | the control command for this count
|
|
||||||
; 7 (this command)
|
|
||||||
|
|
||||||
; For more information, refer to the code below and in extras/gfx.py .
|
|
||||||
|
|
||||||
; save starting output address
|
; For more information, refer to the code below and in extras/gfx.py.
|
||||||
|
|
||||||
|
|
||||||
|
; Save the output address
|
||||||
|
; for rewrite commands.
|
||||||
ld a, e
|
ld a, e
|
||||||
ld [$c2c2], a
|
ld [$c2c2], a
|
||||||
ld a, d
|
ld a, d
|
||||||
ld [$c2c3], a
|
ld [$c2c2 + 1], a
|
||||||
|
|
||||||
.loop
|
.Main
|
||||||
; get next byte
|
|
||||||
ld a, [hl]
|
ld a, [hl]
|
||||||
; done?
|
cp LZ_END
|
||||||
cp $ff ; end
|
|
||||||
ret z
|
ret z
|
||||||
|
|
||||||
; get control code
|
and LZ_CMD
|
||||||
and %11100000
|
|
||||||
|
|
||||||
; 10-bit param?
|
cp LZ_LONG
|
||||||
cp $e0 ; LZ_HI
|
jr nz, .short
|
||||||
jr nz, .normal
|
|
||||||
|
|
||||||
|
.long
|
||||||
|
; The count is now 10 bits.
|
||||||
|
|
||||||
; 10-bit param:
|
; Read the next 3 bits.
|
||||||
|
; %00011100 -> %11100000
|
||||||
; get next 3 bits (%00011100)
|
|
||||||
ld a, [hl]
|
ld a, [hl]
|
||||||
add a
|
add a
|
||||||
add a ; << 3
|
add a ; << 3
|
||||||
add a
|
add a
|
||||||
|
|
||||||
; this is our new control code
|
; This is our new control code.
|
||||||
and %11100000
|
and LZ_CMD
|
||||||
push af
|
push af
|
||||||
|
|
||||||
; get param hi
|
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
and %00000011
|
and LZ_LONG_HI
|
||||||
ld b, a
|
ld b, a
|
||||||
|
|
||||||
; get param lo
|
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
ld c, a
|
ld c, a
|
||||||
|
|
||||||
; read at least 1 byte
|
; read at least 1 byte
|
||||||
inc bc
|
inc bc
|
||||||
jr .readers
|
jr .command
|
||||||
|
|
||||||
|
|
||||||
.normal
|
.short
|
||||||
; push control code
|
|
||||||
push af
|
push af
|
||||||
; get param
|
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
and %00011111
|
and LZ_LEN
|
||||||
ld c, a
|
ld c, a
|
||||||
ld b, $0
|
ld b, 0
|
||||||
; read at least 1 byte
|
|
||||||
|
; read at least 1 byte
|
||||||
inc c
|
inc c
|
||||||
|
|
||||||
.readers
|
|
||||||
; let's get started
|
|
||||||
|
|
||||||
; inc loop counts since we bail as soon as they hit 0
|
.command
|
||||||
|
; Increment loop counts.
|
||||||
|
; We bail the moment they hit 0.
|
||||||
inc b
|
inc b
|
||||||
inc c
|
inc c
|
||||||
|
|
||||||
; get control code
|
|
||||||
pop af
|
pop af
|
||||||
; command type
|
|
||||||
bit 7, a ; 80, a0, c0
|
|
||||||
jr nz, .repeatertype
|
|
||||||
|
|
||||||
; literals
|
bit LZ_RW, a
|
||||||
cp $20 ; LZ_ITER
|
jr nz, .rewrite
|
||||||
jr z, .iter
|
|
||||||
cp $40 ; LZ_ALT
|
|
||||||
jr z, .alt
|
|
||||||
cp $60 ; LZ_ZERO
|
|
||||||
jr z, .zero
|
|
||||||
; else $00
|
|
||||||
|
|
||||||
; 00 ; LZ_LIT
|
cp LZ_ITERATE
|
||||||
; literal data for bc bytes
|
jr z, .Iter
|
||||||
.loop1
|
cp LZ_ALTERNATE
|
||||||
; done?
|
jr z, .Alt
|
||||||
|
cp LZ_ZERO
|
||||||
|
jr z, .Zero
|
||||||
|
|
||||||
|
|
||||||
|
.Literal
|
||||||
|
; Read literal data for bc bytes.
|
||||||
|
.lloop
|
||||||
dec c
|
dec c
|
||||||
jr nz, .next1
|
jr nz, .lnext
|
||||||
dec b
|
dec b
|
||||||
jp z, .loop
|
jp z, .Main
|
||||||
|
|
||||||
.next1
|
.lnext
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
jr .loop1
|
jr .lloop
|
||||||
|
|
||||||
|
|
||||||
; 20 ; LZ_ITER
|
.Iter
|
||||||
; write byte for bc bytes
|
; Write the same byte for bc bytes.
|
||||||
.iter
|
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
|
|
||||||
.iterloop
|
.iterloop
|
||||||
dec c
|
dec c
|
||||||
jr nz, .iternext
|
jr nz, .iternext
|
||||||
dec b
|
dec b
|
||||||
jp z, .loop
|
jp z, .Main
|
||||||
|
|
||||||
.iternext
|
.iternext
|
||||||
ld [de], a
|
ld [de], a
|
||||||
|
@ -193,88 +176,79 @@ Decompress:: ; b50
|
||||||
jr .iterloop
|
jr .iterloop
|
||||||
|
|
||||||
|
|
||||||
; 40 ; LZ_ALT
|
.Alt
|
||||||
; alternate two bytes for bc bytes
|
; Alternate two bytes for bc bytes.
|
||||||
|
|
||||||
; next pair
|
|
||||||
.alt
|
|
||||||
; done?
|
|
||||||
dec c
|
dec c
|
||||||
jr nz, .alt0
|
jr nz, .anext1
|
||||||
dec b
|
dec b
|
||||||
jp z, .altclose0
|
jp z, .adone1
|
||||||
|
.anext1
|
||||||
; alternate for bc
|
|
||||||
.alt0
|
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
|
|
||||||
dec c
|
dec c
|
||||||
jr nz, .alt1
|
jr nz, .anext2
|
||||||
; done?
|
|
||||||
dec b
|
dec b
|
||||||
jp z, .altclose1
|
jp z, .adone2
|
||||||
.alt1
|
.anext2
|
||||||
ld a, [hld]
|
ld a, [hld]
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
jr .alt
|
|
||||||
|
|
||||||
; skip past the bytes we were alternating
|
jr .Alt
|
||||||
.altclose0
|
|
||||||
|
; Skip past the bytes we were alternating.
|
||||||
|
.adone1
|
||||||
inc hl
|
inc hl
|
||||||
.altclose1
|
.adone2
|
||||||
inc hl
|
inc hl
|
||||||
jr .loop
|
jr .Main
|
||||||
|
|
||||||
|
|
||||||
; 60 ; LZ_ZERO
|
.Zero
|
||||||
; write 00 for bc bytes
|
; Write 0 for bc bytes.
|
||||||
.zero
|
|
||||||
xor a
|
xor a
|
||||||
|
|
||||||
.zeroloop
|
.zloop
|
||||||
dec c
|
dec c
|
||||||
jr nz, .zeronext
|
jr nz, .znext
|
||||||
dec b
|
dec b
|
||||||
jp z, .loop
|
jp z, .Main
|
||||||
|
|
||||||
.zeronext
|
.znext
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
jr .zeroloop
|
jr .zloop
|
||||||
|
|
||||||
|
|
||||||
; repeats
|
.rewrite
|
||||||
; 80, a0, c0
|
; Repeat decompressed data from output.
|
||||||
; repeat decompressed data from output
|
|
||||||
.repeatertype
|
|
||||||
push hl
|
push hl
|
||||||
push af
|
push af
|
||||||
; get next byte
|
|
||||||
ld a, [hli]
|
|
||||||
; absolute?
|
|
||||||
bit 7, a
|
|
||||||
jr z, .absolute
|
|
||||||
|
|
||||||
; relative
|
ld a, [hli]
|
||||||
; a = -a
|
bit 7, a ; sign
|
||||||
and %01111111 ; forget the bit we just looked at
|
jr z, .positive
|
||||||
|
|
||||||
|
.negative
|
||||||
|
; hl = de - a
|
||||||
|
; Since we can't subtract a from de,
|
||||||
|
; Make it negative and add de.
|
||||||
|
and %01111111
|
||||||
cpl
|
cpl
|
||||||
; add de (current output address)
|
|
||||||
add e
|
add e
|
||||||
ld l, a
|
ld l, a
|
||||||
ld a, $ff ; -1
|
ld a, -1
|
||||||
adc d
|
adc d
|
||||||
ld h, a
|
ld h, a
|
||||||
jr .repeaters
|
jr .ok
|
||||||
|
|
||||||
.absolute
|
.positive
|
||||||
; get next byte (lo)
|
; Positive offsets are two bytes.
|
||||||
ld l, [hl]
|
ld l, [hl]
|
||||||
; last byte (hi)
|
|
||||||
ld h, a
|
ld h, a
|
||||||
; add starting output address
|
; add to starting output address
|
||||||
ld a, [$c2c2]
|
ld a, [$c2c2]
|
||||||
add l
|
add l
|
||||||
ld l, a
|
ld l, a
|
||||||
|
@ -282,86 +256,86 @@ Decompress:: ; b50
|
||||||
adc h
|
adc h
|
||||||
ld h, a
|
ld h, a
|
||||||
|
|
||||||
.repeaters
|
.ok
|
||||||
pop af
|
pop af
|
||||||
cp $80 ; LZ_REPEAT
|
|
||||||
jr z, .repeat
|
|
||||||
cp $a0 ; LZ_FLIP
|
|
||||||
jr z, .flip
|
|
||||||
cp $c0 ; LZ_REVERSE
|
|
||||||
jr z, .reverse
|
|
||||||
|
|
||||||
; e0 -> 80
|
cp LZ_REPEAT
|
||||||
|
jr z, .Repeat
|
||||||
|
cp LZ_FLIP
|
||||||
|
jr z, .Flip
|
||||||
|
cp LZ_REVERSE
|
||||||
|
jr z, .Reverse
|
||||||
|
|
||||||
; 80 ; LZ_REPEAT
|
; Since LZ_LONG is command 7,
|
||||||
; repeat some decompressed data
|
; only commands 0-6 are passed in.
|
||||||
.repeat
|
; This leaves room for an extra command 7.
|
||||||
; done?
|
; However, lengths longer than 768
|
||||||
|
; would be interpreted as LZ_END.
|
||||||
|
|
||||||
|
; For now, it defaults to LZ_REPEAT.
|
||||||
|
|
||||||
|
|
||||||
|
.Repeat
|
||||||
|
; Copy decompressed data for bc bytes.
|
||||||
dec c
|
dec c
|
||||||
jr nz, .repeatnext
|
jr nz, .rnext
|
||||||
dec b
|
dec b
|
||||||
jr z, .cleanup
|
jr z, .donerw
|
||||||
|
|
||||||
.repeatnext
|
.rnext
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
jr .repeat
|
jr .Repeat
|
||||||
|
|
||||||
|
|
||||||
; a0 ; LZ_FLIP
|
.Flip
|
||||||
; repeat some decompressed data w/ flipped bit order
|
; Copy bitflipped decompressed data for bc bytes.
|
||||||
.flip
|
|
||||||
dec c
|
dec c
|
||||||
jr nz, .flipnext
|
jr nz, .fnext
|
||||||
dec b
|
dec b
|
||||||
jp z, .cleanup
|
jp z, .donerw
|
||||||
|
|
||||||
.flipnext
|
.fnext
|
||||||
ld a, [hli]
|
ld a, [hli]
|
||||||
push bc
|
push bc
|
||||||
ld bc, $0008
|
lb bc, 0, 8
|
||||||
|
|
||||||
.fliploop
|
.floop
|
||||||
rra
|
rra
|
||||||
rl b
|
rl b
|
||||||
dec c
|
dec c
|
||||||
jr nz, .fliploop
|
jr nz, .floop
|
||||||
ld a, b
|
ld a, b
|
||||||
pop bc
|
pop bc
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
jr .flip
|
jr .Flip
|
||||||
|
|
||||||
|
|
||||||
; c0 ; LZ_REVERSE
|
.Reverse
|
||||||
; repeat some decompressed data in reverse
|
; Copy reversed decompressed data for bc bytes.
|
||||||
.reverse
|
|
||||||
dec c
|
dec c
|
||||||
jr nz, .reversenext
|
jr nz, .rvnext
|
||||||
|
|
||||||
dec b
|
dec b
|
||||||
jp z, .cleanup
|
jp z, .donerw
|
||||||
|
|
||||||
.reversenext
|
.rvnext
|
||||||
ld a, [hld]
|
ld a, [hld]
|
||||||
ld [de], a
|
ld [de], a
|
||||||
inc de
|
inc de
|
||||||
jr .reverse
|
jr .Reverse
|
||||||
|
|
||||||
|
|
||||||
.cleanup
|
.donerw
|
||||||
; get type of repeat we just used
|
|
||||||
pop hl
|
pop hl
|
||||||
; was it relative or absolute?
|
|
||||||
bit 7, [hl]
|
bit 7, [hl]
|
||||||
jr nz, .next
|
jr nz, .next
|
||||||
|
inc hl ; positive offset is two bytes
|
||||||
; skip two bytes for absolute
|
|
||||||
inc hl
|
|
||||||
; skip one byte for relative
|
|
||||||
.next
|
.next
|
||||||
inc hl
|
inc hl
|
||||||
jp .loop
|
jp .Main
|
||||||
; c2f
|
; c2f
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue