173 lines
2.9 KiB
ArmAsm
173 lines
2.9 KiB
ArmAsm
; Copyright 1999-2015 Aske Simon Christensen.
|
|
;
|
|
; The code herein is free to use, in whole or in part,
|
|
; modified or as is, for any legal purpose.
|
|
;
|
|
; No warranties of any kind are given as to its behavior
|
|
; or suitability.
|
|
|
|
|
|
INIT_ONE_PROB = $8000
|
|
ADJUST_SHIFT = 4
|
|
SINGLE_BIT_CONTEXTS = 1
|
|
NUM_CONTEXTS = 1536
|
|
|
|
|
|
; Decompress Shrinkler-compressed data produced with the --data option.
|
|
;
|
|
; A0 = Compressed data
|
|
; A1 = Decompressed data destination
|
|
; A2 = Progress callback, can be zero if no callback is desired.
|
|
; Callback will be called continuously with
|
|
; D0 = Number of bytes decompressed so far
|
|
; A0 = Callback argument
|
|
; A3 = Callback argument
|
|
;
|
|
; Uses 3 kilobytes of space on the stack.
|
|
; Preserves D2-D7/A2-A6 and assumes callback does the same.
|
|
;
|
|
; Decompression code may read one longword beyond compressed data.
|
|
; The contents of this longword does not matter.
|
|
|
|
ShrinklerDecompress:
|
|
movem.l d2-d7/a4-a6,-(a7)
|
|
|
|
move.l a0,a4
|
|
move.l a1,a5
|
|
move.l a1,a6
|
|
|
|
; Init range decoder state
|
|
moveq.l #0,d2
|
|
moveq.l #1,d3
|
|
moveq.l #1,d4
|
|
ror.l #1,d4
|
|
|
|
; Init probabilities
|
|
move.l #NUM_CONTEXTS,d6
|
|
.init: move.w #INIT_ONE_PROB,-(a7)
|
|
subq.w #1,d6
|
|
bne.b .init
|
|
|
|
; D6 = 0
|
|
.lit:
|
|
; Literal
|
|
addq.b #1,d6
|
|
.getlit:
|
|
bsr.b GetBit
|
|
addx.b d6,d6
|
|
bcc.b .getlit
|
|
move.b d6,(a5)+
|
|
bsr.b ReportProgress
|
|
.switch:
|
|
; After literal
|
|
bsr.b GetKind
|
|
bcc.b .lit
|
|
; Reference
|
|
moveq.l #-1,d6
|
|
bsr.b GetBit
|
|
bcc.b .readoffset
|
|
.readlength:
|
|
moveq.l #4,d6
|
|
bsr.b GetNumber
|
|
.copyloop:
|
|
move.b (a5,d5.l),(a5)+
|
|
subq.l #1,d7
|
|
bne.b .copyloop
|
|
bsr.b ReportProgress
|
|
; After reference
|
|
bsr.b GetKind
|
|
bcc.b .lit
|
|
.readoffset:
|
|
moveq.l #3,d6
|
|
bsr.b GetNumber
|
|
moveq.l #2,d5
|
|
sub.l d7,d5
|
|
bne.b .readlength
|
|
|
|
lea.l NUM_CONTEXTS*2(a7),a7
|
|
movem.l (a7)+,d2-d7/a4-a6
|
|
rts
|
|
|
|
ReportProgress:
|
|
move.l a2,d0
|
|
beq.b .nocallback
|
|
move.l a5,d0
|
|
sub.l a6,d0
|
|
move.l a3,a0
|
|
jsr (a2)
|
|
.nocallback:
|
|
rts
|
|
|
|
GetKind:
|
|
; Use parity as context
|
|
move.l a5,d1
|
|
moveq.l #1,d6
|
|
and.l d1,d6
|
|
lsl.w #8,d6
|
|
bra.b GetBit
|
|
|
|
GetNumber:
|
|
; D6 = Number context
|
|
|
|
; Out: Number in D7
|
|
lsl.w #8,d6
|
|
.numberloop:
|
|
addq.b #2,d6
|
|
bsr.b GetBit
|
|
bcs.b .numberloop
|
|
moveq.l #1,d7
|
|
subq.b #1,d6
|
|
.bitsloop:
|
|
bsr.b GetBit
|
|
addx.l d7,d7
|
|
subq.b #2,d6
|
|
bcc.b .bitsloop
|
|
rts
|
|
|
|
; D6 = Bit context
|
|
|
|
; D2 = Range value
|
|
; D3 = Interval size
|
|
; D4 = Input bit buffer
|
|
|
|
; Out: Bit in C and X
|
|
|
|
readbit:
|
|
add.l d4,d4
|
|
bne.b nonewword
|
|
move.l (a4)+,d4
|
|
addx.l d4,d4
|
|
nonewword:
|
|
addx.w d2,d2
|
|
add.w d3,d3
|
|
GetBit:
|
|
tst.w d3
|
|
bpl.b readbit
|
|
|
|
lea.l 4+SINGLE_BIT_CONTEXTS*2(a7,d6.l),a1
|
|
add.l d6,a1
|
|
move.w (a1),d1
|
|
; D1 = One prob
|
|
|
|
lsr.w #ADJUST_SHIFT,d1
|
|
sub.w d1,(a1)
|
|
add.w (a1),d1
|
|
|
|
mulu.w d3,d1
|
|
swap.w d1
|
|
|
|
sub.w d1,d2
|
|
blo.b .one
|
|
.zero:
|
|
; oneprob = oneprob * (1 - adjust) = oneprob - oneprob * adjust
|
|
sub.w d1,d3
|
|
; 0 in C and X
|
|
rts
|
|
.one:
|
|
; onebrob = 1 - (1 - oneprob) * (1 - adjust) = oneprob - oneprob * adjust + adjust
|
|
add.w #$ffff>>ADJUST_SHIFT,(a1)
|
|
move.w d1,d3
|
|
add.w d1,d2
|
|
; 1 in C and X
|
|
rts
|