mirror of
https://github.com/exoticorn/upkr.git
synced 2026-01-20 11:36:42 +01:00
Merge pull request #3 from ped7g/z80_ped7g
backward unpacker + example extended
This commit is contained in:
@@ -3,7 +3,8 @@
|
|||||||
DEVICE ZXSPECTRUM48,$8FFF
|
DEVICE ZXSPECTRUM48,$8FFF
|
||||||
|
|
||||||
ORG $9000
|
ORG $9000
|
||||||
compressed_scr_files: ; border color byte + upkr-packed .scr file
|
;; forward example data
|
||||||
|
compressed_scr_files.fwd: ; border color byte + upkr-packed .scr file
|
||||||
DB 1
|
DB 1
|
||||||
INCBIN "screens/Grongy - ZX Spectrum (2022).scr.upk"
|
INCBIN "screens/Grongy - ZX Spectrum (2022).scr.upk"
|
||||||
DB 7
|
DB 7
|
||||||
@@ -13,37 +14,87 @@ compressed_scr_files: ; border color byte + upkr-packed .scr file
|
|||||||
DB 6
|
DB 6
|
||||||
INCBIN "screens/diver - Back to Bjork (2015).scr.upk"
|
INCBIN "screens/diver - Back to Bjork (2015).scr.upk"
|
||||||
.e:
|
.e:
|
||||||
|
;; backward example data (unpacker goes from the end of the data!)
|
||||||
|
compressed_scr_files.rwd.e: EQU $-1 ; the final IX will point one byte ahead of "$" here
|
||||||
|
INCBIN "screens.reversed/diver - Back to Bjork (2015).scr.upk"
|
||||||
|
DB 6
|
||||||
|
INCBIN "screens.reversed/diver - Mercenary 4. The Heaven's Devil (2014) (Forever 2014 Olympic Edition, 1).scr.upk"
|
||||||
|
DB 0
|
||||||
|
INCBIN "screens.reversed/Schafft - Poison (2017).scr.upk"
|
||||||
|
DB 7
|
||||||
|
INCBIN "screens.reversed/Grongy - ZX Spectrum (2022).scr.upk"
|
||||||
|
compressed_scr_files.rwd: ; border color byte + upkr-packed .scr file (backward)
|
||||||
|
DB 1
|
||||||
|
|
||||||
start:
|
start:
|
||||||
di
|
di
|
||||||
; OPT --zxnext
|
; OPT --zxnext
|
||||||
; nextreg 7,3 ; ZX Next: switch to 28Mhz
|
; nextreg 7,3 ; ZX Next: switch to 28Mhz
|
||||||
ld ix,compressed_scr_files
|
|
||||||
.slideshow_loop
|
;;; FORWARD packed/unpacked data demo
|
||||||
|
ld ix,compressed_scr_files.fwd
|
||||||
|
.slideshow_loop.fwd:
|
||||||
; set BORDER for next image
|
; set BORDER for next image
|
||||||
ldi a,(ix) ; fake: ld a,(ix) : inc ix
|
ld a,(ix)
|
||||||
|
inc ix
|
||||||
out (254),a
|
out (254),a
|
||||||
; call unpack of next image directly into VRAM
|
; call unpack of next image directly into VRAM
|
||||||
ld de,$4000 ; target VRAM
|
ld de,$4000 ; target VRAM
|
||||||
exx
|
exx
|
||||||
; IX = packed data, DE' = destination ($4000)
|
; IX = packed data, DE' = destination ($4000)
|
||||||
; returned IX will point right after the packed data
|
; returned IX will point right after the packed data
|
||||||
call upkr.unpack
|
call fwd.upkr.unpack
|
||||||
; do some busy loop with CPU to delay between images
|
; do some busy loop with CPU to delay between images
|
||||||
|
call delay
|
||||||
|
; check if all images were displayed, loop around from first one then
|
||||||
|
ld a,ixl
|
||||||
|
cp low compressed_scr_files.fwd.e
|
||||||
|
jr nz,.slideshow_loop.fwd
|
||||||
|
|
||||||
|
;;; BACKWARD packed/unpacked data demo
|
||||||
|
ld ix,compressed_scr_files.rwd
|
||||||
|
.slideshow_loop.rwd:
|
||||||
|
; set BORDER for next image
|
||||||
|
ld a,(ix)
|
||||||
|
dec ix
|
||||||
|
out (254),a
|
||||||
|
; call unpack of next image directly into VRAM
|
||||||
|
ld de,$5AFF ; target VRAM
|
||||||
|
exx
|
||||||
|
; IX = packed data, DE' = destination
|
||||||
|
; returned IX will point right ahead of the packed data
|
||||||
|
call rwd.upkr.unpack
|
||||||
|
; do some busy loop with CPU to delay between images
|
||||||
|
call delay
|
||||||
|
; check if all images were displayed, loop around from first one then
|
||||||
|
ld a,ixl
|
||||||
|
cp low compressed_scr_files.rwd.e
|
||||||
|
jr nz,.slideshow_loop.rwd
|
||||||
|
|
||||||
|
jr start
|
||||||
|
|
||||||
|
delay:
|
||||||
ld bc,$AA00
|
ld bc,$AA00
|
||||||
.delay:
|
.delay:
|
||||||
.8 ex (sp),ix
|
.8 ex (sp),ix
|
||||||
dec c
|
dec c
|
||||||
jr nz,.delay
|
jr nz,.delay
|
||||||
djnz .delay
|
djnz .delay
|
||||||
; check if all images were displayed, loop around from first one then
|
ret
|
||||||
ld a,ixl
|
|
||||||
cp low compressed_scr_files.e
|
|
||||||
jr z,start
|
|
||||||
jr .slideshow_loop
|
|
||||||
|
|
||||||
; include the depacker library, optionally putting probs array buffer near end of RAM
|
; include the depacker library, optionally putting probs array buffer near end of RAM
|
||||||
DEFINE UPKR_PROBS_ORIGIN $FA00 ; if not defined, array will be put after unpack code
|
DEFINE UPKR_PROBS_ORIGIN $FA00 ; if not defined, array will be put after unpack code
|
||||||
INCLUDE "../unpack.asm"
|
|
||||||
|
MODULE fwd
|
||||||
|
INCLUDE "../unpack.asm"
|
||||||
|
ENDMODULE
|
||||||
|
|
||||||
|
MODULE rwd
|
||||||
|
DEFINE BACKWARDS_UNPACK ; defined to build backwards unpack
|
||||||
|
; initial IX points at last byte of compressed data
|
||||||
|
; initial DE' points at last byte of unpacked data
|
||||||
|
|
||||||
|
INCLUDE "../unpack.asm"
|
||||||
|
ENDMODULE
|
||||||
|
|
||||||
SAVESNA "example.sna",start
|
SAVESNA "example.sna",start
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,6 +15,12 @@
|
|||||||
;; modifies: all registers except IY, requires 10 bytes of stack space
|
;; modifies: all registers except IY, requires 10 bytes of stack space
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
; DEFINE BACKWARDS_UNPACK ; uncomment to build backwards depacker
|
||||||
|
; initial IX points at last byte of compressed data
|
||||||
|
; initial DE' points at last byte of unpacked data
|
||||||
|
|
||||||
|
; DEFINE UPKR_UNPACK_SPEED ; uncomment to get larger but faster unpack routine
|
||||||
|
|
||||||
OPT push reset --syntax=abf
|
OPT push reset --syntax=abf
|
||||||
MODULE upkr
|
MODULE upkr
|
||||||
|
|
||||||
@@ -100,7 +106,7 @@ unpack:
|
|||||||
ld a,c
|
ld a,c
|
||||||
exx
|
exx
|
||||||
ld (de),a ; *write_ptr++ = byte;
|
ld (de),a ; *write_ptr++ = byte;
|
||||||
inc de
|
IFNDEF BACKWARDS_UNPACK : inc de : ELSE : dec de : ENDIF
|
||||||
exx
|
exx
|
||||||
ld d,b ; prev_was_match = false
|
ld d,b ; prev_was_match = false
|
||||||
jr .decompress_data
|
jr .decompress_data
|
||||||
@@ -137,9 +143,13 @@ unpack:
|
|||||||
ld h,d ; DE = write_ptr
|
ld h,d ; DE = write_ptr
|
||||||
ld l,e
|
ld l,e
|
||||||
.offset+*: ld bc,0
|
.offset+*: ld bc,0
|
||||||
|
IFNDEF BACKWARDS_UNPACK
|
||||||
sbc hl,bc ; CF=0 from decode_number ; HL = write_ptr - offset
|
sbc hl,bc ; CF=0 from decode_number ; HL = write_ptr - offset
|
||||||
|
ELSE
|
||||||
|
add hl,bc ; HL = write_ptr + offset
|
||||||
|
ENDIF
|
||||||
pop bc ; BC = length
|
pop bc ; BC = length
|
||||||
ldir
|
IFNDEF BACKWARDS_UNPACK : ldir : ELSE : lddr : ENDIF
|
||||||
exx
|
exx
|
||||||
ld d,b ; prev_was_match = true
|
ld d,b ; prev_was_match = true
|
||||||
djnz .decompress_data ; adjust context_index back to 0..255 range, go to main loop
|
djnz .decompress_data ; adjust context_index back to 0..255 range, go to main loop
|
||||||
@@ -193,7 +203,7 @@ decode_bit:
|
|||||||
jr nz,.has_bit ; CF=data, ZF=0 -> some bits + stop bit still available
|
jr nz,.has_bit ; CF=data, ZF=0 -> some bits + stop bit still available
|
||||||
; CF=1 (by stop bit)
|
; CF=1 (by stop bit)
|
||||||
ld a,(ix)
|
ld a,(ix)
|
||||||
inc ix ; upkr_current_byte = *upkr_data_ptr++;
|
IFNDEF BACKWARDS_UNPACK : inc ix : ELSE : dec ix : ENDIF ; upkr_current_byte = *upkr_data_ptr++;
|
||||||
adc a,a ; CF=data, b0=1 as new stop bit
|
adc a,a ; CF=data, b0=1 as new stop bit
|
||||||
.has_bit:
|
.has_bit:
|
||||||
adc hl,hl ; upkr_state = (upkr_state << 1) + (upkr_current_byte >> 7);
|
adc hl,hl ; upkr_state = (upkr_state << 1) + (upkr_current_byte >> 7);
|
||||||
@@ -215,6 +225,10 @@ decode_bit:
|
|||||||
ld d,0
|
ld d,0
|
||||||
ld e,a ; DE = state_scale ; prob || (256-prob)
|
ld e,a ; DE = state_scale ; prob || (256-prob)
|
||||||
ld l,d ; H:L = (upkr_state>>8) : 0
|
ld l,d ; H:L = (upkr_state>>8) : 0
|
||||||
|
|
||||||
|
IFNDEF UPKR_UNPACK_SPEED
|
||||||
|
|
||||||
|
;; looped MUL for minimum unpack size
|
||||||
ld b,8 ; counter
|
ld b,8 ; counter
|
||||||
.mulLoop:
|
.mulLoop:
|
||||||
add hl,hl
|
add hl,hl
|
||||||
@@ -222,28 +236,41 @@ decode_bit:
|
|||||||
add hl,de
|
add hl,de
|
||||||
.mul0:
|
.mul0:
|
||||||
djnz .mulLoop ; until HL = state_scale * (upkr_state>>8), also BC becomes (upkr_state & 255)
|
djnz .mulLoop ; until HL = state_scale * (upkr_state>>8), also BC becomes (upkr_state & 255)
|
||||||
|
|
||||||
|
ELSE
|
||||||
|
|
||||||
|
;;; unrolled MUL for better performance, +25 bytes unpack size
|
||||||
|
ld b,d
|
||||||
|
DUP 8
|
||||||
|
add hl,hl
|
||||||
|
jr nc,0_f
|
||||||
|
add hl,de
|
||||||
|
0:
|
||||||
|
EDUP
|
||||||
|
|
||||||
|
ENDIF
|
||||||
|
|
||||||
add hl,bc ; HL = state_scale * (upkr_state >> 8) + (upkr_state & 255)
|
add hl,bc ; HL = state_scale * (upkr_state >> 8) + (upkr_state & 255)
|
||||||
pop af
|
pop af ; restore prob and CF=bit
|
||||||
ld d,-16 ; D = -prob_offset (-16 0xF0 when bit = 0)
|
|
||||||
jr nc,.bit_is_0_2
|
jr nc,.bit_is_0_2
|
||||||
ld d,b ; D = -prob_offset (0 when bit = 1) (also does fix following ADD)
|
dec d ; DE = -prob (also D = bit ? $FF : $00)
|
||||||
dec h
|
add hl,de ; HL += -prob
|
||||||
add hl,de ; HL += -prob (HL += (256 - prob) - 256)
|
; ^ this always preserves CF=1, because (state>>8) >= 128, state_scale: 7..250, prob: 7..250,
|
||||||
.bit_is_0_2: ; HL = state_offset + state_scale * (upkr_state >> 8) + (upkr_state & 255) ; new upkr_state
|
; so 7*128 > 250 and thus edge case `ADD hl=(7*128+0),de=(-250)` => CF=1
|
||||||
|
.bit_is_0_2:
|
||||||
; *** adjust probs[context_index]
|
; *** adjust probs[context_index]
|
||||||
ld e,a ; D:E = -prob_offset:prob, A = prob
|
ld e,a ; preserve prob
|
||||||
and $F8
|
rra ; + (bit<<4) ; part of -prob_offset, needs another -16
|
||||||
|
and $FC ; clear/keep correct bits to get desired (prob>>4) + extras, CF=0
|
||||||
rra
|
rra
|
||||||
rra
|
rra
|
||||||
rra
|
rra ; A = (bit<<4) + (prob>>4), CF=(prob & 8)
|
||||||
rra
|
adc a,-16 ; A = (bit<<4) - 16 + ((prob + 8)>>4) ; -prob_offset = (bit<<4) - 16
|
||||||
adc a,d ; A = -prob_offset + ((prob + 8) >> 4)
|
sub e ; A = (bit<<4) - 16 + ((prob + 8)>>4) - prob ; = ((prob + 8)>>4) - prob_offset - prob
|
||||||
neg
|
neg ; A = prob_offset + prob - ((prob + 8)>>4)
|
||||||
add a,e ; A = prob_offset + prob - ((prob + 8) >> 4)
|
|
||||||
pop bc
|
pop bc
|
||||||
ld (bc),a ; update probs[context_index]
|
ld (bc),a ; probs[context_index] = prob_offset + prob - ((prob + 8) >> 4);
|
||||||
add a,d ; bit=0: A = 23..249, D = 240 -> CF=1 || bit=1: D=0 -> CF=0
|
add a,d ; restore CF = bit (D = bit ? $FF : $00 && A > 0)
|
||||||
ccf ; resulting CF = bit restored
|
|
||||||
pop de
|
pop de
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@@ -287,12 +314,12 @@ decode_number:
|
|||||||
; reserve space for probs array without emitting any machine code (using only EQU)
|
; reserve space for probs array without emitting any machine code (using only EQU)
|
||||||
|
|
||||||
IFDEF UPKR_PROBS_ORIGIN ; if specific address is defined by user, move probs array there
|
IFDEF UPKR_PROBS_ORIGIN ; if specific address is defined by user, move probs array there
|
||||||
ORG UPKR_PROBS_ORIGIN
|
probs: EQU ((UPKR_PROBS_ORIGIN) + 255) & -$100 ; probs array aligned to 256
|
||||||
|
ELSE
|
||||||
|
probs: EQU ($ + 255) & -$100 ; probs array aligned to 256
|
||||||
ENDIF
|
ENDIF
|
||||||
|
.real_c: EQU 1 + 255 + 1 + 2*NUMBER_BITS ; real size of probs array
|
||||||
probs: EQU ($+255) & -$100 ; probs array aligned to 256
|
.c: EQU (.real_c + 1) & -2 ; padding to even size (required by init code)
|
||||||
.real_c: EQU 1 + 255 + 1 + 2*NUMBER_BITS ; real size of probs array
|
|
||||||
.c: EQU (.real_c + 1) & -2 ; padding to even size (required by init code)
|
|
||||||
.e: EQU probs + .c
|
.e: EQU probs + .c
|
||||||
|
|
||||||
DISPLAY "upkr.unpack probs array placed at: ",/A,probs,",\tsize: ",/A,probs.c
|
DISPLAY "upkr.unpack probs array placed at: ",/A,probs,",\tsize: ",/A,probs.c
|
||||||
|
|||||||
Reference in New Issue
Block a user