; ; Copyright (c) 2002 - 2020 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. ; ; ------------------------------------------------------------------- ; Known quirks: ; Can't handle a sequence reference that ends at $ffff. It is left in ; since it is a corner case and fixing it impacts negatively on ; performance or backwards compatibility. ; A simple way to work around this is to not decrunch to address $ffff. ; ------------------------------------------------------------------- ; Controls if the shared get_bits routines should be inlined or not. ;INLINE_GET_BITS=1 IFNCONST INLINE_GET_BITS INLINE_GET_BITS = 0 ENDIF ; ------------------------------------------------------------------- ; 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 IFNCONST LITERAL_SEQUENCES_NOT_USED LITERAL_SEQUENCES_NOT_USED = 0 ENDIF ; ------------------------------------------------------------------- ; 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 IFNCONST MAX_SEQUENCE_LENGTH_256 MAX_SEQUENCE_LENGTH_256 = 0 ENDIF ; ------------------------------------------------------------------- ; if the sequence length 3 has its own offset table (the data was ; crunched with the -P+16 flag) then the following ; line must be uncommented. ;EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE = 1 IFNCONST EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE = 0 ENDIF ; ------------------------------------------------------------------- ; if sequence offsets are not reused (the data was crunched with the ; -P-32 flag) then the following line must be uncommented. Uncommenting the ; line will also result in shorter and slightly faster code. ;DONT_REUSE_OFFSET = 1 IFNCONST DONT_REUSE_OFFSET DONT_REUSE_OFFSET = 0 ENDIF ; ------------------------------------------------------------------- ; if decrunching forwards then the following line must be uncommented. ;DECRUNCH_FORWARDS = 1 IFNCONST DECRUNCH_FORWARDS DECRUNCH_FORWARDS = 0 ENDIF ; ------------------------------------------------------------------- ; if split encoding is used (the data is crunched with the -E flag) ; then the following line must be uncommented. ;ENABLE_SPLIT_ENCODING = 1 IFNCONST ENABLE_SPLIT_ENCODING ENABLE_SPLIT_ENCODING = 0 ENDIF ; ------------------------------------------------------------------- ; The decruncher jsr:s to the exod_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. ; ------------------------------------------------------------------- ; ------------------------------------------------------------------- ; The exod_decrunch function is the heart of the decruncher. (for non split ; crunched files) ; 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. ; ------------------------------------------------------------------- IF ENABLE_SPLIT_ENCODING != 0 ; ------------------------------------------------------------------- ; To decrunch files crunched with the split feature (-E) you can't use the ; decrunch function. Instead you call the split_decrunch function. But you ; can only do this if the decrunch table contains the encoding used by the ; file you are decrunching. To generate the correct content for the decrunch ; table call set the get_crunched_byte function to point to the encoding data ; and then call the split_gentable function. ; ------------------------------------------------------------------- ENDIF ; ------------------------------------------------------------------- ; zero page addresses used ; ------------------------------------------------------------------- exod_zp_len_lo = $9e exod_zp_len_hi = $9f exod_zp_src_lo = $ae exod_zp_src_hi = exod_zp_src_lo + 1 exod_zp_bits_hi = $a7 IF DONT_REUSE_OFFSET == 0 exod_zp_ro_state = $a8 ENDIF exod_zp_bitbuf = $fd exod_zp_dest_lo = exod_zp_bitbuf + 1 ; dest addr lo exod_zp_dest_hi = exod_zp_bitbuf + 2 ; dest addr hi SUBROUTINE exodecrunch IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE != 0 .encoded_entries = 68 ELSE .encoded_entries = 52 ENDIF .tabl_bi = exod_decrunch_table .tabl_lo = exod_decrunch_table + .encoded_entries .tabl_hi = exod_decrunch_table + .encoded_entries * 2 ;; refill bits is always inlined MAC exod_mac_refill_bits pha jsr exod_get_crunched_byte rol sta exod_zp_bitbuf pla ENDM MAC exod_mac_get_bits IF INLINE_GET_BITS != 0 adc #$80 ; needs c=0, affects v asl bpl .gb_skip .gb_next: asl exod_zp_bitbuf bne .gb_ok exod_mac_refill_bits .gb_ok: rol bmi .gb_next .gb_skip: bvc .skip .gb_get_hi: sec sta exod_zp_bits_hi jsr exod_get_crunched_byte .skip: ELSE jsr exod_get_bits ENDIF ENDM MAC exod_mac_init_zp ; ------------------------------------------------------------------- ; init zeropage and x reg. (8 bytes) ; .init_zp: jsr exod_get_crunched_byte sta exod_zp_bitbuf - 1,x dex bne .init_zp ENDM IF INLINE_GET_BITS == 0 exod_get_bits: adc #$80 ; needs c=0, affects v asl bpl .gb_skip .gb_next: asl exod_zp_bitbuf bne .gb_ok exod_mac_refill_bits .gb_ok: rol bmi .gb_next .gb_skip: bvs .gb_get_hi rts .gb_get_hi: sec sta exod_zp_bits_hi jmp exod_get_crunched_byte ENDIF ; ------------------------------------------------------------------- ; 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 cleared (it almost always is, otherwise do a cld) exod_decrunch: IF ENABLE_SPLIT_ENCODING != 0 ldx #3 jsr .internal_gentable jmp .normal_decrunch exod_split_gentable: ldx #1 .internal_gentable: jsr .split_init_zp ELSE ldx #3 exod_mac_init_zp ENDIF ; ------------------------------------------------------------------- ; calculate tables (64 bytes) + get_bits macro ; x and y must be #0 when entering ; ldy #0 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 exod_zp_len_hi adc .tabl_hi - 1,y .shortcut: sta .tabl_hi,y ; ------------------------------------------------------------------- lda #$01 sta C=0, no reuse bne .copy_next ; bit != 0 => C=0, reuse previous offset ENDIF ; ------------------------------------------------------------------- ; exit or literal sequence handling (16(12) bytes) ; .exit_or_lit_seq: IF LITERAL_SEQUENCES_NOT_USED == 0 beq .decr_exit jsr exod_get_crunched_byte IF MAX_SEQUENCE_LENGTH_256 == 0 sta exod_zp_len_hi ENDIF jsr exod_get_crunched_byte tax bcs .copy_next .decr_exit: ENDIF rts IF LITERAL_SEQUENCES_NOT_USED == 0 .get_literal_byte: jsr exod_get_crunched_byte bcs .literal_byte_gotten ENDIF IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE != 0 ; ------------------------------------------------------------------- ; 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 ENDIF IF ENABLE_SPLIT_ENCODING != 0 .split_init_zp: exod_mac_init_zp rts ENDIF ; ------------------------------------------------------------------- ; end of decruncher ; ------------------------------------------------------------------- ; ------------------------------------------------------------------- ; this 156 (204) byte table area may be relocated. It may also be ; clobbered by other data between decrunches. ; ------------------------------------------------------------------- exod_decrunch_table: .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 IF EXTRA_TABLE_ENTRY_FOR_LENGTH_THREE != 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 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 ; -------------------------------------------------------------------