mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2024-11-16 11:27:33 -08:00
Recomment lz deecompression.
This commit is contained in:
parent
20444d2f63
commit
21708a2271
@ -1,19 +1,14 @@
|
||||
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
|
||||
; save bank
|
||||
ld a, [hROMBank]
|
||||
push af
|
||||
; bankswitch
|
||||
ld a, [$c2c4]
|
||||
rst Bankswitch
|
||||
|
||||
; what we came here for
|
||||
|
||||
call Decompress
|
||||
|
||||
; restore bank
|
||||
|
||||
pop af
|
||||
rst Bankswitch
|
||||
ret
|
||||
@ -22,346 +17,325 @@ FarDecompress:: ; b40
|
||||
|
||||
Decompress:: ; b50
|
||||
; 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
|
||||
; tilemaps also use this compression.
|
||||
|
||||
; This function decompresses lz-compressed data at hl to de.
|
||||
; This function decompresses lz-compressed data from hl to de.
|
||||
|
||||
|
||||
; Basic rundown:
|
||||
|
||||
; 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_END EQU $ff ; Compressed data is terminated with $ff.
|
||||
|
||||
|
||||
; Commands:
|
||||
; A typical control command consists of:
|
||||
|
||||
; 0: literal
|
||||
; literal data for some number of bytes
|
||||
; 1: iterate
|
||||
; one byte repeated for some number of bytes
|
||||
; 2: alternate
|
||||
; two bytes alternated for some number of bytes
|
||||
; 3: zero (whitespace)
|
||||
; 0x00 repeated for some number of bytes
|
||||
LZ_CMD EQU %11100000 ; command id (bits 5-7)
|
||||
LZ_LEN EQU %00011111 ; length n (bits 0-4)
|
||||
|
||||
; 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.
|
||||
; Additional parameters are read during command execution.
|
||||
|
||||
; 4: repeat
|
||||
; repeat some number of bytes from decompressed data
|
||||
; 5: flipped
|
||||
; repeat some number of flipped bytes from decompressed data
|
||||
; ex: $ad = %10101101 -> %10110101 = $b5
|
||||
; 6: reverse
|
||||
; repeat some number of bytes in reverse from decompressed data
|
||||
|
||||
; 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.
|
||||
; Commands:
|
||||
|
||||
; A new control command is read in bits 2-4.
|
||||
; The new 10-bit count is split:
|
||||
; bits 0-1 contain the top 2 bits
|
||||
; another byte is added containing the latter 8
|
||||
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.
|
||||
|
||||
; So, the structure of the control command becomes:
|
||||
; 111xxxyy yyyyyyyy
|
||||
; | | | |
|
||||
; | | our new count
|
||||
; | the control command for this count
|
||||
; 7 (this command)
|
||||
|
||||
; For more information, refer to the code below and in extras/gfx.py .
|
||||
; Another class of commands reuses data from the decompressed output.
|
||||
LZ_RW EQU 2 + 5 ; bit
|
||||
|
||||
; save starting output address
|
||||
; 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.
|
||||
|
||||
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,
|
||||
; 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.
|
||||
; 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
|
||||
|
||||
; In other words, the structure of the command becomes
|
||||
; 111xxxyy yyyyyyyy
|
||||
; x: the new control command
|
||||
; y: the length
|
||||
|
||||
|
||||
; For more information, refer to the code below and in extras/gfx.py.
|
||||
|
||||
|
||||
; Save the output address
|
||||
; for rewrite commands.
|
||||
ld a, e
|
||||
ld [$c2c2], a
|
||||
ld a, d
|
||||
ld [$c2c3], a
|
||||
|
||||
.loop
|
||||
; get next byte
|
||||
ld [$c2c2 + 1], a
|
||||
|
||||
.Main
|
||||
ld a, [hl]
|
||||
; done?
|
||||
cp $ff ; end
|
||||
cp LZ_END
|
||||
ret z
|
||||
|
||||
; get control code
|
||||
and %11100000
|
||||
|
||||
; 10-bit param?
|
||||
cp $e0 ; LZ_HI
|
||||
jr nz, .normal
|
||||
|
||||
|
||||
; 10-bit param:
|
||||
and LZ_CMD
|
||||
|
||||
; get next 3 bits (%00011100)
|
||||
cp LZ_LONG
|
||||
jr nz, .short
|
||||
|
||||
.long
|
||||
; 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 %11100000
|
||||
push af
|
||||
|
||||
; get param hi
|
||||
ld a, [hli]
|
||||
and %00000011
|
||||
ld b, a
|
||||
|
||||
; get param lo
|
||||
ld a, [hli]
|
||||
ld c, a
|
||||
|
||||
; read at least 1 byte
|
||||
inc bc
|
||||
jr .readers
|
||||
|
||||
|
||||
.normal
|
||||
; push control code
|
||||
push af
|
||||
; get param
|
||||
ld a, [hli]
|
||||
and %00011111
|
||||
ld c, a
|
||||
ld b, $0
|
||||
; read at least 1 byte
|
||||
inc c
|
||||
|
||||
.readers
|
||||
; let's get started
|
||||
|
||||
; inc loop counts since we bail as soon as they hit 0
|
||||
; 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
|
||||
|
||||
; get control code
|
||||
|
||||
pop af
|
||||
; command type
|
||||
bit 7, a ; 80, a0, c0
|
||||
jr nz, .repeatertype
|
||||
|
||||
; literals
|
||||
cp $20 ; LZ_ITER
|
||||
jr z, .iter
|
||||
cp $40 ; LZ_ALT
|
||||
jr z, .alt
|
||||
cp $60 ; LZ_ZERO
|
||||
jr z, .zero
|
||||
; else $00
|
||||
|
||||
; 00 ; LZ_LIT
|
||||
; literal data for bc bytes
|
||||
.loop1
|
||||
; done?
|
||||
|
||||
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, .next1
|
||||
jr nz, .lnext
|
||||
dec b
|
||||
jp z, .loop
|
||||
|
||||
.next1
|
||||
jp z, .Main
|
||||
|
||||
.lnext
|
||||
ld a, [hli]
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .loop1
|
||||
|
||||
|
||||
; 20 ; LZ_ITER
|
||||
; write byte for bc bytes
|
||||
.iter
|
||||
jr .lloop
|
||||
|
||||
|
||||
.Iter
|
||||
; Write the same byte for bc bytes.
|
||||
ld a, [hli]
|
||||
|
||||
|
||||
.iterloop
|
||||
dec c
|
||||
jr nz, .iternext
|
||||
dec b
|
||||
jp z, .loop
|
||||
|
||||
jp z, .Main
|
||||
|
||||
.iternext
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .iterloop
|
||||
|
||||
|
||||
; 40 ; LZ_ALT
|
||||
; alternate two bytes for bc bytes
|
||||
|
||||
; next pair
|
||||
.alt
|
||||
; done?
|
||||
|
||||
.Alt
|
||||
; Alternate two bytes for bc bytes.
|
||||
dec c
|
||||
jr nz, .alt0
|
||||
jr nz, .anext1
|
||||
dec b
|
||||
jp z, .altclose0
|
||||
|
||||
; alternate for bc
|
||||
.alt0
|
||||
jp z, .adone1
|
||||
.anext1
|
||||
ld a, [hli]
|
||||
ld [de], a
|
||||
inc de
|
||||
|
||||
dec c
|
||||
jr nz, .alt1
|
||||
; done?
|
||||
jr nz, .anext2
|
||||
dec b
|
||||
jp z, .altclose1
|
||||
.alt1
|
||||
jp z, .adone2
|
||||
.anext2
|
||||
ld a, [hld]
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .alt
|
||||
|
||||
; skip past the bytes we were alternating
|
||||
.altclose0
|
||||
|
||||
jr .Alt
|
||||
|
||||
; Skip past the bytes we were alternating.
|
||||
.adone1
|
||||
inc hl
|
||||
.altclose1
|
||||
.adone2
|
||||
inc hl
|
||||
jr .loop
|
||||
|
||||
|
||||
; 60 ; LZ_ZERO
|
||||
; write 00 for bc bytes
|
||||
.zero
|
||||
jr .Main
|
||||
|
||||
|
||||
.Zero
|
||||
; Write 0 for bc bytes.
|
||||
xor a
|
||||
|
||||
.zeroloop
|
||||
|
||||
.zloop
|
||||
dec c
|
||||
jr nz, .zeronext
|
||||
jr nz, .znext
|
||||
dec b
|
||||
jp z, .loop
|
||||
|
||||
.zeronext
|
||||
jp z, .Main
|
||||
|
||||
.znext
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .zeroloop
|
||||
|
||||
|
||||
; repeats
|
||||
; 80, a0, c0
|
||||
; repeat decompressed data from output
|
||||
.repeatertype
|
||||
jr .zloop
|
||||
|
||||
|
||||
.rewrite
|
||||
; Repeat decompressed data from output.
|
||||
push hl
|
||||
push af
|
||||
; get next byte
|
||||
|
||||
ld a, [hli]
|
||||
; absolute?
|
||||
bit 7, a
|
||||
jr z, .absolute
|
||||
|
||||
; relative
|
||||
; a = -a
|
||||
and %01111111 ; forget the bit we just looked at
|
||||
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
|
||||
cpl
|
||||
; add de (current output address)
|
||||
add e
|
||||
ld l, a
|
||||
ld a, $ff ; -1
|
||||
ld a, -1
|
||||
adc d
|
||||
ld h, a
|
||||
jr .repeaters
|
||||
|
||||
.absolute
|
||||
; get next byte (lo)
|
||||
jr .ok
|
||||
|
||||
.positive
|
||||
; Positive offsets are two bytes.
|
||||
ld l, [hl]
|
||||
; last byte (hi)
|
||||
ld h, a
|
||||
; add starting output address
|
||||
; add to starting output address
|
||||
ld a, [$c2c2]
|
||||
add l
|
||||
ld l, a
|
||||
ld a, [$c2c3]
|
||||
adc h
|
||||
ld h, a
|
||||
|
||||
.repeaters
|
||||
|
||||
.ok
|
||||
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
|
||||
|
||||
; 80 ; LZ_REPEAT
|
||||
; repeat some decompressed data
|
||||
.repeat
|
||||
; done?
|
||||
|
||||
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.
|
||||
|
||||
; For now, it defaults to LZ_REPEAT.
|
||||
|
||||
|
||||
.Repeat
|
||||
; Copy decompressed data for bc bytes.
|
||||
dec c
|
||||
jr nz, .repeatnext
|
||||
jr nz, .rnext
|
||||
dec b
|
||||
jr z, .cleanup
|
||||
|
||||
.repeatnext
|
||||
jr z, .donerw
|
||||
|
||||
.rnext
|
||||
ld a, [hli]
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .repeat
|
||||
|
||||
|
||||
; a0 ; LZ_FLIP
|
||||
; repeat some decompressed data w/ flipped bit order
|
||||
.flip
|
||||
jr .Repeat
|
||||
|
||||
|
||||
.Flip
|
||||
; Copy bitflipped decompressed data for bc bytes.
|
||||
dec c
|
||||
jr nz, .flipnext
|
||||
jr nz, .fnext
|
||||
dec b
|
||||
jp z, .cleanup
|
||||
|
||||
.flipnext
|
||||
jp z, .donerw
|
||||
|
||||
.fnext
|
||||
ld a, [hli]
|
||||
push bc
|
||||
ld bc, $0008
|
||||
|
||||
.fliploop
|
||||
lb bc, 0, 8
|
||||
|
||||
.floop
|
||||
rra
|
||||
rl b
|
||||
dec c
|
||||
jr nz, .fliploop
|
||||
jr nz, .floop
|
||||
ld a, b
|
||||
pop bc
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .flip
|
||||
|
||||
|
||||
; c0 ; LZ_REVERSE
|
||||
; repeat some decompressed data in reverse
|
||||
.reverse
|
||||
jr .Flip
|
||||
|
||||
|
||||
.Reverse
|
||||
; Copy reversed decompressed data for bc bytes.
|
||||
dec c
|
||||
jr nz, .reversenext
|
||||
|
||||
jr nz, .rvnext
|
||||
|
||||
dec b
|
||||
jp z, .cleanup
|
||||
|
||||
.reversenext
|
||||
jp z, .donerw
|
||||
|
||||
.rvnext
|
||||
ld a, [hld]
|
||||
ld [de], a
|
||||
inc de
|
||||
jr .reverse
|
||||
|
||||
|
||||
.cleanup
|
||||
; get type of repeat we just used
|
||||
jr .Reverse
|
||||
|
||||
|
||||
.donerw
|
||||
pop hl
|
||||
; was it relative or absolute?
|
||||
|
||||
bit 7, [hl]
|
||||
jr nz, .next
|
||||
|
||||
; skip two bytes for absolute
|
||||
inc hl
|
||||
; skip one byte for relative
|
||||
inc hl ; positive offset is two bytes
|
||||
.next
|
||||
inc hl
|
||||
jp .loop
|
||||
jp .Main
|
||||
; c2f
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user