Skip to content

Instantly share code, notes, and snippets.

@petrihakkinen
Last active January 5, 2020 17:04
Show Gist options
  • Save petrihakkinen/6ed4ff9884f079e426c6c682f84cbc45 to your computer and use it in GitHub Desktop.
Save petrihakkinen/6ed4ff9884f079e426c6c682f84cbc45 to your computer and use it in GitHub Desktop.
ZX7 decompressor for 6502 (150 bytes, 146 bytes if dest address is set by caller)
;*****************************************************************
; ZX7 decompressor based on
; ZX7 data decompressor for Apple II
; by Peter Ferrie (peter.ferrie@gmail.com)
; with modifications by Juan J. Martinez (@reidrac)
; optimized by Petri Häkkinen
; This code is in the Public Domain
;*****************************************************************
zx7_src_lo = $20 ; should always contain 0
zx7_src_hi = $21 ; write source page address here
; internal
zx7_dst_lo = $22
zx7_dst_hi = $23
zx7_ecx_lo = $24
zx7_ecx_hi = $25
zx7_last = $26
; in:
; A = dest address lo
; X = dest address hi
; Y = src address lo
zx7_unpack: sta zx7_dst_lo ; sta & stx can be skipped if the address is set by caller
stx zx7_dst_hi
; y = src offset
lda #0
sta zx7_last
sta zx7_ecx_lo
sta zx7_ecx_hi
@copy_byte_loop:jsr @getput
@main_loop: jsr @next_bit
bcc @copy_byte_loop
ldx #0 ; x = counter
@len_size_loop: inx
jsr @next_bit
bcc @len_size_loop
bcs @len_value_skip ; always branch
@len_value_loop:jsr @next_bit
@len_value_skip:rol zx7_ecx_lo
rol zx7_ecx_hi
bcs @next_bit_ret
dex
bne @len_value_loop
inc zx7_ecx_lo
bne :+
inc zx7_ecx_hi
: jsr @getsrc
rol
sta temp1
txa
bcc @offset_end
lda #$10
@rld_next_bit: pha
jsr @next_bit
pla
rol
bcc @rld_next_bit
;clc
;adc #1
adc #0 ; carry is always set
lsr
@offset_end: sta temp2
ror temp1
ldx zx7_src_hi ; store src hi
tya ; store Y
pha
; compute new offset y
lda zx7_dst_lo
sbc temp1
tay ; y = dst_lo - offset
; src_hi = dst_hi - temp2
lda zx7_dst_hi
sbc temp2
sta zx7_src_hi
@loop1: jsr @getput
; dec ecx
lda zx7_ecx_lo
bne :+
dec zx7_ecx_hi
: ;sec ; carry seems to be always set, but why?
sbc #1
sta zx7_ecx_lo
ora zx7_ecx_hi
bne @loop1
; restore src
pla ; restore Y
tay
stx zx7_src_hi ; restore src hi
;jmp @main_loop
bcs @main_loop ; carry seems to be always set, but why?
@getput: jsr @getsrc
sty temp2 ; store Y
ldy #0
sta (zx7_dst_lo), y
ldy temp2 ; restore Y
inc zx7_dst_lo
bne :+
inc zx7_dst_hi
: rts
; read one byte from source
@getsrc: lda (zx7_src_lo), y
iny
bne :+
inc zx7_src_hi
: rts
@next_bit: asl zx7_last
bne @next_bit_ret
jsr @getsrc
sec
rol
sta zx7_last
@next_bit_ret: rts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment