mirror of
https://github.com/deater/dos33fsprogs.git
synced 2024-12-28 09:30:41 +00:00
164 lines
3.9 KiB
ArmAsm
164 lines
3.9 KiB
ArmAsm
; De-compressor for ZX02 files
|
|
; ----------------------------
|
|
;
|
|
; Decompress ZX02 data (6502 optimized format), optimized for speed and size
|
|
; 138 bytes code, 58.0 cycles/byte in test file.
|
|
;
|
|
; Compress with:
|
|
; zx02 input.bin output.zx0
|
|
;
|
|
; (c) 2022 DMSC
|
|
; Code under MIT license, see LICENSE file.
|
|
|
|
|
|
;ZP=$80
|
|
|
|
;offset = ZP+0
|
|
;ZX0_src = ZP+2
|
|
;ZX0_dst = ZP+4
|
|
;bitr = ZP+6
|
|
;pntr = ZP+7
|
|
|
|
; Initial values for offset, source, destination and bitr
|
|
;zx0_ini_block:
|
|
; .byte $00, $00 ; offset
|
|
;comp_data:
|
|
; .byte $0, $0 ; zx0_src
|
|
;out_addr:
|
|
; .byte $0, $0 ; zx0_dst
|
|
; .byte $80 ; bitr
|
|
|
|
;--------------------------------------------------
|
|
; Decompress ZX0 data (6502 optimized format)
|
|
|
|
; destination page in A
|
|
full_decomp:
|
|
sta ZX0_dst+1
|
|
|
|
ldy #$80
|
|
sty bitr
|
|
|
|
ldy #0 ; always on page boundary
|
|
sty ZX0_dst
|
|
|
|
sty offset
|
|
sty offset+1
|
|
|
|
; Y needs to be 0 here
|
|
|
|
; Get initialization block
|
|
; ldy #7
|
|
|
|
;copy_init: lda zx0_ini_block-1, y
|
|
; sta offset-1, y
|
|
; dey
|
|
; bne copy_init
|
|
|
|
; Decode literal: Ccopy next N bytes from compressed file
|
|
; Elias(length) byte[1] byte[2] ... byte[N]
|
|
decode_literal:
|
|
jsr get_elias
|
|
|
|
cop0: lda (ZX0_src), y
|
|
inc ZX0_src
|
|
bne plus1
|
|
inc ZX0_src+1
|
|
plus1: sta (ZX0_dst),y
|
|
inc ZX0_dst
|
|
bne plus2
|
|
inc ZX0_dst+1
|
|
plus2: dex
|
|
bne cop0
|
|
|
|
asl bitr
|
|
bcs dzx0s_new_offset
|
|
|
|
; Copy from last offset (repeat N bytes from last offset)
|
|
; Elias(length)
|
|
jsr get_elias
|
|
dzx0s_copy:
|
|
lda ZX0_dst
|
|
sbc offset ; C=0 from get_elias
|
|
sta pntr
|
|
lda ZX0_dst+1
|
|
sbc offset+1
|
|
sta pntr+1
|
|
|
|
cop1:
|
|
lda (pntr), y
|
|
inc pntr
|
|
bne plus3
|
|
inc pntr+1
|
|
plus3: sta (ZX0_dst),y
|
|
inc ZX0_dst
|
|
bne plus4
|
|
inc ZX0_dst+1
|
|
plus4: dex
|
|
bne cop1
|
|
|
|
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
|
|
jsr get_elias
|
|
beq exit ; Read a 0, signals the end
|
|
; Decrease and divide by 2
|
|
dex
|
|
txa
|
|
lsr ; @
|
|
sta offset+1
|
|
|
|
; Get low part of offset, a literal 7 bits
|
|
lda (ZX0_src), y
|
|
inc ZX0_src
|
|
bne plus5
|
|
inc ZX0_src+1
|
|
plus5:
|
|
; Divide by 2
|
|
ror ; @
|
|
sta offset
|
|
|
|
; And get the copy length.
|
|
; Start elias reading with the bit already in carry:
|
|
ldx #1
|
|
jsr elias_skip1
|
|
|
|
inx
|
|
bcc dzx0s_copy
|
|
|
|
; Read an elias-gamma interlaced code.
|
|
; ------------------------------------
|
|
get_elias:
|
|
; Initialize return value to #1
|
|
ldx #1
|
|
bne elias_start
|
|
|
|
elias_get: ; Read next data bit to result
|
|
asl bitr
|
|
rol ; @
|
|
tax
|
|
|
|
elias_start:
|
|
; Get one bit
|
|
asl bitr
|
|
bne elias_skip1
|
|
|
|
; Read new bit from stream
|
|
lda (ZX0_src), y
|
|
inc ZX0_src
|
|
bne plus6
|
|
inc ZX0_src+1
|
|
plus6: ;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
|