;those will make the depacker ~5% faster but bloat it: ;FAST_LITERAL_COPY = 1 ;will increase size by 11 bytes ;FAST_MATCH_COPY = 1 ;will increase size by 11 bytes ;------------------------------------------------------------------------------- ;Regular version of the Lempel-Ziv decompressor ;------------------------------------------------------------------------------- ;lz_match = $f9 ;Match source pointer ;lz_dst = $fb ;Decompression destination pointer. ; ;Initialize this to whatever address ; ;you want to decompress to ; ;lz_bits = $fd ;Internal shift register ; ;lz_sector = $0400 ;The one-page buffer from which the ; ;compressed data is actually read, ; ;and which gets refilled by ; ;lz_fetch_sector ;------------------------------------------------------------------------------- ;This is the user's hook to replenish the sector buffer with some new bytes. ; ;A and Y are expected to be preserved while carry must remain set on exit. ;X should point to the first byte of the new data, e.g. zero for a full 256-byte ;page of data or two to skip past the sector and track links. ; ;When fetching from a larger in-memory array rather than a single sector buffer ;the lz_sector_ptr1..3 pointers will need to be patched up ;------------------------------------------------------------------------------- ;lz_fetch_sector ; inc lz_sector_ptr1+1 ; inc lz_sector_ptr2+1 ; inc lz_sector_ptr3+1 ; rts ;------------------------------------------------------------------------------- ;Typical usage ;------------------------------------------------------------------------------- ; ldx #>source ; ldy # 1 -> short match (len 2) ;else long match _lz_do_match lda #$01 ;this could be made shorter by using the last bitfetch of the upcoming loop and restoring the carry again by a cmp #$02. Saves bytes, but makes things slower, as eof check is also done with all short matches then asl lz_bits ;first length bit (where a one identifies bne *+5 ;a two-byte match) jsr _lz_refill_bits bcc lz_get_offs ;all done, length is 2, skip further bitfetches - asl lz_bits bne *+5 jsr _lz_refill_bits rol asl lz_bits bne *+5 jsr _lz_refill_bits bcc - tay ;A 257-byte (=>$00) run serves as a beq _lz_end_of_file ;sentinel lz_get_offs sta _lz_mcopy_len ;store length at final destination lda #%11000000 ;fetch 2 more prefix bits rol ;previous bit is still in carry \o/ - asl lz_bits ;XXX TODO in ultra slim variant this could be a subroutine bne *+5 ;XXX TODO this code could also be called twice jsr _lz_refill_bits rol bcs - tay lda lentab,y beq lz_far ;XXX TODO currently 8 and 9 bit long offsets carry teh same value here, so if one wants to use both, one has to set the value for 8 bit long offsets ;to $ff and check things here with a cmp #$ff. Including teh eor #$ff in lz_far or not will then solvet he problem. This is faster though. - asl lz_bits bne *+5 jsr _lz_refill_bits rol bcs - bmi lz_short lz_far eor #$ff ;negate tay lz_sector_ptr3 = *+1 lda lz_sector,x ;For large offsets we can load the inx ;low-byte straight from the stream bne lz_join ;without going throught the shift jsr lz_fetch_sector ;register !byte $2c ;skip next two bytes lz_short ldy #$ff ;XXX TODO GNAAA y is set twice to $ff in the case of short matches lz_join adc lz_dst ;subtract offset from lz_dst sta lz_match tya ;hibyte adc lz_dst+1 sta lz_match+1 ldy #$ff ;The copy loop. This needs to be run ;forwards since RLE-style matches can overlap the destination _lz_mcopy iny lda (lz_match),y ;Copy one byte sta (lz_dst),y _lz_mcopy_len = *+1 cpy #$ff bne _lz_mcopy tya ;Advance destination pointer ; sec adc lz_dst+0 sta lz_dst+0 jmp _lz_mfinish ;******** Fetch some more bits to work with ******** lz_sector_ptr1 = *+1 _lz_refill_bits ldy lz_sector,x sty lz_bits ; sec rol lz_bits inx bne + lz_fetch_sector inc lz_sector_ptr1+1 inc lz_sector_ptr2+1 inc lz_sector_ptr3+1 + _lz_end_of_file rts lentab ;XXX TODO combine tables so that values used twice are eliminated? -> more classes can be used? ;XXX TODO best rearrange tables by using lookup table? ;short offset init values !byte %11011111 !byte %11111011 !byte %00000000 !byte %10000000 ;long offset init values !byte %11101111 !byte %11111101 !byte %10000000 !byte %11110000