passport/src/exodecrunch.s

491 lines
14 KiB
ArmAsm

; This source code is altered and is not the original version found on
; the Exomizer homepage.
; It contains modifications made by qkumba to depack a packed file
; optionally crunched forward, and additional modifications by 4am
; for an optional progress UI.
;
; Original copyright statement follows:
;
; Copyright (c) 2002 - 2018 Magnus Lind.
;
; This software is provided 'as-is', without any express or implied warranty.
; In no event will the authors be held liable for any damages arising from
; the use of this software.
;
; Permission is granted to anyone to use this software for any purpose,
; including commercial applications, and to alter it and redistribute it
; freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must not
; claim that you wrote the original software. If you use this software in a
; product, an acknowledgment in the product documentation would be
; appreciated but is not required.
;
; 2. Altered source versions must be plainly marked as such, and must not
; be misrepresented as being the original software.
;
; 3. This notice may not be removed or altered from any distribution.
;
; 4. The names of this software and/or it's copyright holders may not be
; used to endorse or promote products derived from this software without
; specific prior written permission.
;
; -------------------------------------------------------------------
; The decruncher jsr:s to the get_crunched_byte address when it wants to
; read a crunched byte into A. This subroutine has to preserve X and Y
; register and must not modify the state of the carry nor the overflow flag.
; -------------------------------------------------------------------
;.import get_crunched_byte
; -------------------------------------------------------------------
; this function is the heart of the decruncher.
; It initializes the decruncher zeropage locations and precalculates the
; decrunch tables and decrunches the data
; This function will not change the interrupt status bit and it will not
; modify the memory configuration.
; -------------------------------------------------------------------
;.export decrunch
; -------------------------------------------------------------------
; Controls if the shared get_bits routines should be inlined or not.
;INLINE_GET_BITS=1
; -------------------------------------------------------------------
; if literal sequences is not used (the data was crunched with the -c
; flag) then the following line can be uncommented for shorter and.
; slightly faster code.
;LITERAL_SEQUENCES_NOT_USED = 1
; -------------------------------------------------------------------
; if the sequence length is limited to 256 (the data was crunched with
; the -M256 flag) then the following line can be uncommented for
; shorter and slightly faster code.
;MAX_SEQUENCE_LENGTH_256 = 1
; -------------------------------------------------------------------
; if the sequence length 3 has its own offset table then the following
; line can be uncommented for in some situations slightly better
; compression at the cost of a larger decrunch table.
EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE = 1
; -------------------------------------------------------------------
; optional progress UI
!IFNDEF SHOW_PROGRESS_DURING_DECRUNCH {
!set SHOW_PROGRESS_DURING_DECRUNCH = 0
}
; -------------------------------------------------------------------
; zero page addresses used
; -------------------------------------------------------------------
zp_len_lo = $a7
zp_len_hi = $a8
zp_src_lo = $ae
zp_src_hi = zp_src_lo + 1
zp_bits_hi = $fc
zp_bitbuf = $fd
zp_dest_lo = zp_bitbuf + 1 ; dest addr lo
zp_dest_hi = zp_bitbuf + 2 ; dest addr hi
!IFDEF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE {
encoded_entries = 68
} ELSE {
encoded_entries = 52
}
tabl_bi = decrunch_table
tabl_lo = decrunch_table + encoded_entries
tabl_hi = decrunch_table + encoded_entries * 2
;; refill bits is always inlined
!MACRO mac_refill_bits {
pha
jsr get_crunched_byte
rol
sta zp_bitbuf
pla
}
!IFDEF INLINE_GET_BITS {
!MACRO mac_get_bits {
adc #$80 ; needs c=0, affects v
asl
bpl gb_skip
gb_next:
asl zp_bitbuf
bne gb_ok
mac_refill_bits
gb_ok:
rol
bmi gb_next
gb_skip:
bvc skip
gb_get_hi:
sec
sta zp_bits_hi
jsr get_crunched_byte
skip:
}
} ELSE {
!MACRO mac_get_bits {
jsr get_bits
}
get_bits:
adc #$80 ; needs c=0, affects v
asl
bpl gb_skip
gb_next:
asl zp_bitbuf
bne gb_ok
+mac_refill_bits
gb_ok:
rol
bmi gb_next
gb_skip:
bvs gb_get_hi
rts
gb_get_hi:
sec
sta zp_bits_hi
jmp get_crunched_byte
}
; -------------------------------------------------------------------
; no code below this comment has to be modified in order to generate
; a working decruncher of this source file.
; However, you may want to relocate the tables last in the file to a
; more suitable address.
; -------------------------------------------------------------------
; -------------------------------------------------------------------
; jsr this label to decrunch, it will in turn init the tables and
; call the decruncher
; no constraints on register content, however the
; decimal flag has to be #0 (it almost always is, otherwise do a cld)
decrunch:
!IF SHOW_PROGRESS_DURING_DECRUNCH = 1 {
kExoProgressWidth = 23 ; depends on total size, max 38
ldx #(kExoProgressWidth+2)
lda #$DF
- sta $0528+(20-(kExoProgressWidth/2))-1, x
sta $05A8+(20-(kExoProgressWidth/2))-1, x
dex
bpl -
lda #$20
sta $05A8+(20-(kExoProgressWidth/2))-1
sta $05A8+(20-(kExoProgressWidth/2))+kExoProgressWidth+1
lda #$A8+(20-(kExoProgressWidth/2))
sta ExoProgressPtr+1
}
; -------------------------------------------------------------------
; init zeropage, x and y regs. (12 bytes)
;
ldy #0
ldx #3
init_zp:
jsr get_crunched_byte
sta zp_bitbuf - 1,x
dex
bne init_zp
; -------------------------------------------------------------------
; calculate tables (62 bytes) + get_bits macro
; x and y must be #0 when entering
;
clc
table_gen:
tax
tya
and #$0f
sta tabl_lo,y
beq shortcut ; start a new sequence
; -------------------------------------------------------------------
txa
adc tabl_lo - 1,y
sta tabl_lo,y
lda zp_len_hi
adc tabl_hi - 1,y
shortcut:
sta tabl_hi,y
; -------------------------------------------------------------------
lda #$01
sta <zp_len_hi
lda #$78 ; %01111000
+mac_get_bits
; -------------------------------------------------------------------
lsr
tax
beq rolled
php
rolle:
asl zp_len_hi
sec
ror
dex
bne rolle
plp
rolled:
ror
sta tabl_bi,y
bmi no_fixup_lohi
lda zp_len_hi
stx zp_len_hi
!BYTE $24
no_fixup_lohi:
txa
; -------------------------------------------------------------------
iny
cpy #encoded_entries
bne table_gen
; -------------------------------------------------------------------
; prepare for main decruncher
ldy zp_dest_lo
stx zp_dest_lo
stx zp_bits_hi
; -------------------------------------------------------------------
; copy one literal byte to destination (11(10) bytes)
;
!ifndef FORWARD_DECRUNCHING {
!set FORWARD_DECRUNCHING = 1
}
!if FORWARD_DECRUNCHING = 0 {
literal_start1:
tya
bne no_hi_decr
dec zp_dest_hi
no_hi_decr:
dey
jsr get_crunched_byte
sta (zp_dest_lo),y
!IF SHOW_PROGRESS_DURING_DECRUNCH = 1 {
dec ExoProgressCounter
bne +
lda #$20
ExoProgressPtr
sta $0500 ; SMC lo byte
inc ExoProgressPtr+1
+
}
} else {
literal_start1:
jsr get_crunched_byte
sta (zp_dest_lo),y
iny
bne no_hi_incr
inc zp_dest_hi
no_hi_incr:
}
; -------------------------------------------------------------------
; fetch sequence length index (15 bytes)
; x must be #0 when entering and contains the length index + 1
; when exiting or 0 for literal byte
next_round:
dex
lda zp_bitbuf
no_literal1:
asl
bne nofetch8
jsr get_crunched_byte
rol
nofetch8:
inx
bcc no_literal1
sta zp_bitbuf
; -------------------------------------------------------------------
; check for literal byte (2 bytes)
;
beq literal_start1
; -------------------------------------------------------------------
; check for decrunch done and literal sequences (4 bytes)
;
cpx #$11
!IFDEF INLINE_GET_BITS {
bcc skip_jmp
jmp exit_or_lit_seq
skip_jmp:
} ELSE {
bcs exit_or_lit_seq
}
; -------------------------------------------------------------------
; calulate length of sequence (zp_len) (18(11) bytes) + get_bits macro
;
lda tabl_bi - 1,x
+mac_get_bits
adc tabl_lo - 1,x ; we have now calculated zp_len_lo
sta zp_len_lo
!IFNDEF MAX_SEQUENCE_LENGTH_256 {
lda zp_bits_hi
adc tabl_hi - 1,x ; c = 0 after this.
sta zp_len_hi
; -------------------------------------------------------------------
; here we decide what offset table to use (27(26) bytes) + get_bits_nc macro
; z-flag reflects zp_len_hi here
;
ldx zp_len_lo
} ELSE {
tax
}
lda #$e1
!IFDEF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE {
cpx #$04
} ELSE {
cpx #$03
}
bcs gbnc2_next
lda tabl_bit - 1,x
gbnc2_next:
asl zp_bitbuf
bne gbnc2_ok
tax
jsr get_crunched_byte
rol
sta zp_bitbuf
txa
gbnc2_ok:
rol
bcs gbnc2_next
tax
; -------------------------------------------------------------------
; calulate absolute offset (zp_src) (21(23) bytes) + get_bits macro
;
!IFNDEF MAX_SEQUENCE_LENGTH_256 {
lda #0
sta zp_bits_hi
}
lda tabl_bi,x
+mac_get_bits
!if FORWARD_DECRUNCHING = 0 {
adc tabl_lo,x
sta zp_src_lo
lda zp_bits_hi
adc tabl_hi,x
adc zp_dest_hi
} else {
clc
adc tabl_lo,x
eor #$ff
sta zp_src_lo
lda zp_dest_hi
bcc skip_dest_hi
sbc #1
clc
skip_dest_hi:
sbc zp_bits_hi
sbc tabl_hi,x
clc
}
sta zp_src_hi
; -------------------------------------------------------------------
; prepare for copy loop (2 bytes)
;
pre_copy:
ldx zp_len_lo
; -------------------------------------------------------------------
; main copy loop (30 bytes)
;
copy_next:
!if FORWARD_DECRUNCHING = 0 {
tya
bne copy_skip_hi
dec zp_dest_hi
dec zp_src_hi
copy_skip_hi:
dey
}
!IFNDEF LITERAL_SEQUENCES_NOT_USED {
bcs get_literal_byte
}
lda (zp_src_lo),y
literal_byte_gotten:
sta (zp_dest_lo),y
!if FORWARD_DECRUNCHING = 1 {
iny
bne copy_skip_hi
inc zp_dest_hi
inc zp_src_hi
copy_skip_hi:
}
dex
bne copy_next
!IFNDEF MAX_SEQUENCE_LENGTH_256 {
lda zp_len_hi
!IFDEF INLINE_GET_BITS {
bne copy_next_hi
}
}
begin_stx:
stx zp_bits_hi
!IFNDEF INLINE_GET_BITS {
beq next_round
} ELSE {
jmp next_round
}
!IFNDEF MAX_SEQUENCE_LENGTH_256 {
copy_next_hi:
dec zp_len_hi
jmp copy_next
}
!IFNDEF LITERAL_SEQUENCES_NOT_USED {
get_literal_byte:
jsr get_crunched_byte
bcs literal_byte_gotten
}
; -------------------------------------------------------------------
; exit or literal sequence handling (16(12) bytes)
;
exit_or_lit_seq:
!IFNDEF LITERAL_SEQUENCES_NOT_USED {
beq decr_exit
jsr get_crunched_byte
!IFNDEF MAX_SEQUENCE_LENGTH_256 {
sta zp_len_hi
}
jsr get_crunched_byte
tax
bcs copy_next
decr_exit:
}
rts
!IFDEF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE {
; -------------------------------------------------------------------
; the static stable used for bits+offset for lengths 1, 2 and 3 (3 bytes)
; bits 2, 4, 4 and offsets 64, 48, 32 corresponding to
; %10010000, %11100011, %11100010
tabl_bit:
!BYTE $90, $e3, $e2
} ELSE {
; -------------------------------------------------------------------
; the static stable used for bits+offset for lengths 1 and 2 (2 bytes)
; bits 2, 4 and offsets 48, 32 corresponding to %10001100, %11100010
tabl_bit:
!BYTE $8c, $e2
}
!IF SHOW_PROGRESS_DURING_DECRUNCH = 1 {
ExoProgressCounter
!byte $00
}
; -------------------------------------------------------------------
; end of decruncher
; -------------------------------------------------------------------
; -------------------------------------------------------------------
; this 156 (204) byte table area may be relocated. It may also be
; clobbered by other data between decrunches.
; -------------------------------------------------------------------
decrunch_table=$200;;:
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;.IFDEF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;;.ENDIF
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;; .byte 0,0,0,0,0,0,0,0,0,0,0,0
; -------------------------------------------------------------------
; end of decruncher
; -------------------------------------------------------------------