Merge pull request #2847 from colinleroy/zx02-faster-decompressor
Add a 9% faster ZX02 decompressor
This commit is contained in:
179
libsrc/common/zx02_fast.s
Normal file
179
libsrc/common/zx02_fast.s
Normal file
@@ -0,0 +1,179 @@
|
||||
; void __fastcall__ decompress_zx02_fast(const void *src, void *dest)
|
||||
;
|
||||
; De-compressor for ZX02 files
|
||||
; 9% faster than decompress_zx02, 34 bytes bigger
|
||||
;
|
||||
; Compress with:
|
||||
; zx02 input.bin output.zx0
|
||||
;
|
||||
; (c) 2022 DMSC
|
||||
; Code under MIT license, see LICENSE file.
|
||||
|
||||
.export _decompress_zx02_fast
|
||||
|
||||
.import popax
|
||||
.importzp ptr1, ptr2, ptr3, tmp1, tmp2
|
||||
|
||||
ZX0_src = ptr1
|
||||
ZX0_dst = ptr2
|
||||
pntr = ptr3
|
||||
offset_hi = tmp1
|
||||
bitr = tmp2
|
||||
|
||||
.proc _decompress_zx02_fast
|
||||
sta ZX0_dst
|
||||
stx ZX0_dst+1
|
||||
|
||||
jsr popax
|
||||
sta ZX0_src
|
||||
stx ZX0_src+1
|
||||
|
||||
; Init values
|
||||
lda #$80
|
||||
sta bitr
|
||||
ldy #$FF
|
||||
sty pntr
|
||||
iny
|
||||
sty offset_hi
|
||||
beq decode_literal
|
||||
|
||||
cop0_inc_high:
|
||||
inc ZX0_src+1
|
||||
inc ZX0_dst+1
|
||||
dex
|
||||
bne cop0
|
||||
beq cop0_done
|
||||
|
||||
; Decode literal: Copy next N bytes from compressed file
|
||||
; Elias(length) byte[1] byte[2] ... byte[N]
|
||||
decode_literal:
|
||||
ldx #$01
|
||||
jsr get_elias
|
||||
|
||||
cop0:
|
||||
lda (ZX0_src),y
|
||||
sta (ZX0_dst),y
|
||||
|
||||
iny
|
||||
beq cop0_inc_high
|
||||
dex
|
||||
bne cop0
|
||||
cop0_done:
|
||||
; Update pointers from Y
|
||||
tya
|
||||
clc
|
||||
adc ZX0_src
|
||||
sta ZX0_src
|
||||
bcc :+
|
||||
inc ZX0_src+1
|
||||
clc
|
||||
|
||||
: tya
|
||||
adc ZX0_dst
|
||||
sta ZX0_dst
|
||||
bcc :+
|
||||
inc ZX0_dst+1
|
||||
:
|
||||
ldy #$00
|
||||
|
||||
asl bitr
|
||||
bcs dzx0s_new_offset
|
||||
|
||||
; Copy from last offset (repeat N bytes from last offset)
|
||||
; Elias(length)
|
||||
inx
|
||||
jsr get_elias
|
||||
|
||||
dzx0s_copy:
|
||||
lda ZX0_dst+1
|
||||
sbc offset_hi ; C=0 from get_elias
|
||||
sta pntr+1
|
||||
|
||||
cop1:
|
||||
ldy ZX0_dst ; Align dest pointer
|
||||
lda #$00
|
||||
sta ZX0_dst
|
||||
cop1_cont:
|
||||
lda (pntr), y
|
||||
sta (ZX0_dst),y
|
||||
iny
|
||||
beq cop1_inc_high
|
||||
dex
|
||||
bne cop1_cont
|
||||
cop1_done:
|
||||
sty ZX0_dst ; Update dest pointer
|
||||
ldy #$00
|
||||
|
||||
asl bitr
|
||||
bcc decode_literal
|
||||
|
||||
; Copy from new offset (repeat N bytes from new offset)
|
||||
; Elias(MSB(offset)) LSB(offset) Elias(length-1)
|
||||
dzx0s_new_offset:
|
||||
; Read elias code for high part of offset
|
||||
inx
|
||||
jsr get_elias
|
||||
beq exit ; Read a 0, signals the end
|
||||
|
||||
; Decrease and divide by 2
|
||||
dex
|
||||
txa
|
||||
lsr
|
||||
sta offset_hi
|
||||
|
||||
; Get low part of offset, a literal 7 bits
|
||||
lda (ZX0_src), y
|
||||
inc ZX0_src
|
||||
bne :+
|
||||
inc ZX0_src+1
|
||||
|
||||
: ; Divide by 2
|
||||
ror
|
||||
eor #$ff
|
||||
sta pntr
|
||||
|
||||
; And get the copy length.
|
||||
; Start elias reading with the bit already in carry:
|
||||
ldx #1
|
||||
jsr elias_skip1
|
||||
|
||||
inx
|
||||
bcc dzx0s_copy ; C=0 here so equivalent to bra
|
||||
|
||||
; Read an elias-gamma interlaced code.
|
||||
elias_get:
|
||||
; Read next data bit to result
|
||||
asl bitr
|
||||
rol
|
||||
tax
|
||||
|
||||
get_elias:
|
||||
; Get one bit
|
||||
asl bitr
|
||||
bne elias_skip1
|
||||
|
||||
; Read new bit from stream
|
||||
lda (ZX0_src), y
|
||||
inc ZX0_src
|
||||
bne :+
|
||||
inc ZX0_src+1
|
||||
|
||||
: ; sec ; not needed, C=1 guaranteed from last bit
|
||||
rol
|
||||
sta bitr
|
||||
|
||||
elias_skip1:
|
||||
txa
|
||||
bcs elias_get
|
||||
|
||||
; Got ending bit, stop reading
|
||||
exit:
|
||||
rts
|
||||
|
||||
cop1_inc_high:
|
||||
inc ZX0_dst+1
|
||||
inc pntr+1
|
||||
dex
|
||||
bne cop1_cont
|
||||
beq cop1_done
|
||||
.endproc
|
||||
Reference in New Issue
Block a user