233 lines
4.7 KiB
NASM
233 lines
4.7 KiB
NASM
!cpu 6510
|
|
|
|
;EXAMPLE FOR OFFICIAL VERSION
|
|
|
|
lz_sector = ($ffff - (data_end-data) + 1) & $ff00
|
|
|
|
decruncher = $00c2
|
|
|
|
* = $0801
|
|
;basicline 1 SYS2061
|
|
!byte $0b,$08,$39,$05,$9e,$32
|
|
!byte $30,$36,$31,$00,$00,$00
|
|
|
|
sei
|
|
inc $01
|
|
|
|
ldx #$ff
|
|
txs
|
|
|
|
inx
|
|
-
|
|
lda copy_start,x
|
|
sta decruncher,x
|
|
inx
|
|
bne -
|
|
|
|
ldy #(>(data_end-data)) + 1
|
|
-
|
|
;src should be data + packed_size
|
|
dex
|
|
src lda data_end-$100,x
|
|
dst sta $ff00,x
|
|
txa
|
|
bne -
|
|
|
|
dec src+2
|
|
dec dst+2
|
|
dey
|
|
bne -
|
|
|
|
ldx #<($ffff - (data_end-copy_end) + 1)
|
|
jmp go
|
|
|
|
copy_start
|
|
!pseudopc decruncher {
|
|
;fetch depack addr (use --add-depack-addr on lz)
|
|
lz_match !byte $00,$00
|
|
lz_bits !byte $00
|
|
lz_scratch !byte $00
|
|
|
|
go
|
|
;******** Start the next match/literal run ********
|
|
lz_decrunch
|
|
;XXX TODO lz_bist auch gleich passend füllen bei sfx, nicht in stream schreiben?
|
|
sec ;This is the main entry point. Forcibly
|
|
_lz_type_refill jsr _lz_refill_bits ;fill up the the bit buffer on entry
|
|
bne _lz_type_cont ;(BRA)
|
|
|
|
;Wrap the high-byte of the destination pointer.
|
|
_lz_mfinish bcc *+4
|
|
_lz_maximum inc+1 lz_dst+1 ;This is also used by maximum length
|
|
;literals needing an explicit type bit
|
|
|
|
;Literal or match to follow?
|
|
asl lz_bits
|
|
_lz_type_cont bcc _lz_do_match
|
|
beq _lz_type_refill
|
|
|
|
;******** Process literal run ********
|
|
|
|
lda #%00000000 ;Decode run length
|
|
_lz_lrun_loop rol
|
|
asl lz_bits
|
|
bcs _lz_lrun_test
|
|
_lz_lrun_back asl lz_bits
|
|
bne _lz_lrun_loop
|
|
|
|
jsr _lz_refill_bits
|
|
bne _lz_lrun_loop ;(BRA)
|
|
|
|
_lz_lrun_test bne _lz_lrun_gotten
|
|
jsr _lz_refill_bits
|
|
bcc _lz_lrun_back
|
|
|
|
_lz_lrun_gotten
|
|
sta+1 _lz_copy_cnt+1 ;Store LSB of run-length
|
|
ldy #$00
|
|
_lz_lcopy
|
|
lz_sector_ptr2 = *+1 ;Copy the literal data.
|
|
lda lz_sector,x
|
|
inx
|
|
bne *+5
|
|
jsr lz_fetch_sector
|
|
lz_dst = * + 1
|
|
sta $4000,y
|
|
iny
|
|
_lz_copy_cnt cpy #$00
|
|
bne _lz_lcopy
|
|
|
|
;Time to advance the destination pointer.
|
|
;Maximum run length literals exit here as a type-bit needs
|
|
;to be fetched afterwards
|
|
tya
|
|
beq _lz_maximum ;maximum literal run, bump sector pointers and so on
|
|
clc
|
|
adc+1 lz_dst+0
|
|
sta+1 lz_dst+0
|
|
bcc _lz_do_match
|
|
inc+1 lz_dst+1
|
|
|
|
;******** Process match ********
|
|
|
|
_lz_do_match lda #%00100000 ;Determine offset length by a two-bit
|
|
_lz_moff_range asl lz_bits ;prefix combined with the first run
|
|
bne *+5 ;length bit (where a one identifies
|
|
jsr _lz_refill_bits ;a two-byte match).
|
|
rol ;The rest of the length bits will
|
|
bcc _lz_moff_range ;then follow *after* the offset data
|
|
|
|
tay
|
|
lda _lz_moff_length,y
|
|
beq _lz_moff_far
|
|
|
|
_lz_moff_loop asl lz_bits ;Load partial offset byte
|
|
bne *+9
|
|
sty lz_scratch
|
|
jsr _lz_refill_bits
|
|
ldy lz_scratch
|
|
|
|
rol
|
|
bcc _lz_moff_loop
|
|
|
|
bmi _lz_moff_near
|
|
|
|
_lz_moff_far sta lz_scratch ;Save the bits we just read as the
|
|
;high-byte
|
|
|
|
lz_sector_ptr3 = *+1
|
|
lda lz_sector,x ;For large offsets we can load the
|
|
inx ;low-byte straight from the stream
|
|
bne *+5 ;without going throught the shift
|
|
jsr lz_fetch_sector ;register
|
|
|
|
; sec
|
|
adc _lz_moff_adjust_lo,y ;y .. 2 .. 5? ?! necessary with a full lowbyte?!?!
|
|
bcs _lz_moff_pageok
|
|
dec lz_scratch
|
|
sec
|
|
_lz_moff_pageok adc+1 lz_dst+0
|
|
sta lz_match+0
|
|
|
|
lda lz_scratch
|
|
adc _lz_moff_adjust_hi,y
|
|
sec
|
|
bcs _lz_moff_join ;(BRA)
|
|
|
|
_lz_moff_near
|
|
; sec ;Special case handling of <8 bit offsets.
|
|
adc _lz_moff_adjust_lo,y;We may can safely ignore the MSB from
|
|
; sec ;the base adjustment table as the
|
|
adc+1 lz_dst+0 ;maximum base (for a 4/5/6/7 bit
|
|
sta lz_match+0 ;length sequence) is 113
|
|
lda #$ff
|
|
_lz_moff_join adc+1 lz_dst+1
|
|
sta lz_match+1
|
|
|
|
cpy #$04 ;Get any remaning run length bits
|
|
lda #%00000001
|
|
bcs _lz_mrun_start ;Sentinel check can be skipped in that case
|
|
|
|
_lz_mrun_loop asl lz_bits
|
|
bne *+5
|
|
jsr _lz_refill_bits
|
|
rol
|
|
asl lz_bits
|
|
bcc _lz_mrun_loop
|
|
bne _lz_mrun_gotten
|
|
jsr _lz_refill_bits
|
|
bcc _lz_mrun_loop
|
|
|
|
;XXX TODO only needed on near matches as offset = 1 in that case
|
|
_lz_mrun_gotten tay ;A 257-byte (=>$00) run serves as a
|
|
beq _lz_end_of_file ;sentinel
|
|
_lz_mrun_start
|
|
sta _lz_mcopy_len
|
|
|
|
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+1 lz_dst+0
|
|
sta+1 lz_dst+0
|
|
jmp _lz_mfinish
|
|
|
|
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
|
|
+
|
|
rts
|
|
|
|
_lz_end_of_file
|
|
|
|
dec $01
|
|
cli
|
|
!byte $4c
|
|
|
|
_lz_moff_length = * + 2
|
|
_lz_moff_adjust_lo = _lz_moff_length + 8
|
|
_lz_moff_adjust_hi = _lz_moff_length + 16
|
|
|
|
}
|
|
copy_end = * + 26
|
|
data
|
|
;!bin "d.lz",,2
|
|
data_end
|