Rearranged gamma scheme for faster decomp.

This commit is contained in:
Martin Haye 2017-01-01 08:59:35 -08:00
parent 05a63b3e54
commit 7d8c562ffa
2 changed files with 172 additions and 24 deletions

View File

@ -36,7 +36,8 @@ public class Lx47Algorithm
int next;
}
int countEliasGammaBits(int value) {
// It's Elias Gamma, bit the value bits interspersed with the mark bits
int countGammaBits(int value) {
int bits;
assert value >= 1 && value <= 255;
@ -48,15 +49,11 @@ public class Lx47Algorithm
return bits;
}
int countEliasExpGammaBits(int value, int exp) {
return (exp==0) ? countEliasGammaBits(value) : (countEliasGammaBits((value >> exp) + 1) + exp);
}
int countCodePair(int prevLits, int matchLen, int offset) {
int nBits = (prevLits>0 ? 0 : 1)
+ 8 // 8 for the byte that's always emitted
+ (offset>=64 ? countEliasGammaBits(offset>>6) : 0)
+ (matchLen>2 ? countEliasGammaBits(matchLen-2) : 0);
+ (offset>=64 ? countGammaBits(offset>>6) : 0)
+ (matchLen>2 ? countGammaBits(matchLen-2) : 0);
return nBits;
}
@ -66,7 +63,7 @@ public class Lx47Algorithm
int bits = lits * 8;
while (lits > 0) {
int n = Math.min(254, lits);
bits += countEliasGammaBits(n+1);
bits += countGammaBits(n+1);
lits -= n;
}
return bits;
@ -185,17 +182,36 @@ public class Lx47Algorithm
bitPos++;
}
void writeEliasGamma(int value) {
void writeGamma(int value) {
assert value >= 1 && value <= 255;
int i;
for (i = 2; i <= value; i <<= 1)
// Find highest set bit
for (i = 128; (i&value) == 0; i >>= 1)
;
// Write out extra bits with markers
while (i > 1) {
i >>= 1;
writeBit(0);
while ((i >>= 1) > 0)
writeBit(value & i);
}
// And finish
writeBit(1);
}
// 1: 1
// 2: 010 -> 001
// 3: 011 -> 011
// 4: 00100 -> 00001
// 5: 00101 -> 00011
// 6: 00110 -> 01001
// 7: 00111 -> 01011
void writeLiteralLen(int value) {
writeEliasGamma(value+1);
writeGamma(value+1);
}
void writeCodePair(int matchLen, int offset)
@ -211,9 +227,9 @@ public class Lx47Algorithm
writeByte(data);
if (offset >= 64)
writeEliasGamma(offset>>6);
writeGamma(offset>>6);
if (matchLen > 2)
writeEliasGamma(matchLen-2);
writeGamma(matchLen-2);
}
}
@ -328,20 +344,15 @@ public class Lx47Algorithm
return ret;
}
int readEliasGamma() {
int nBits = 0;
while (readBit() == 0)
++nBits;
if (nBits >= 16)
return -99; // EOF marker
int readGamma() {
int out = 1;
while (nBits-- > 0)
while (readBit() == 0)
out = (out << 1) | readBit();
return out;
}
int readLiteralLen() {
return readEliasGamma() - 1;
return readGamma() - 1;
}
int readCodePair()
@ -350,9 +361,9 @@ public class Lx47Algorithm
int offset = data & 63; // 6 bits
int matchLen = 2;
if ((data & 64) == 64)
offset |= readEliasGamma() << 6;
offset |= readGamma() << 6;
if ((data & 128) == 128)
matchLen += readEliasGamma();
matchLen += readGamma();
return matchLen | (offset<<16);
}
}

View File

@ -0,0 +1,137 @@
;****************************************************************************************
; Copyright (C) 2017 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
; (the "License"); you may not use this file except in compliance with the License.
; You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
; Unless required by applicable law or agreed to in writing, software distributed under
; the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
; ANY KIND, either express or implied. See the License for the specific language
; governing permissions and limitations under the License.
;****************************************************************************************
;@com.wudsn.ide.asm.hardware=APPLE2
; Memory manager
; ------------------
;
; See detailed description in mem.i
* = $2000 ; PLASMA loader loads us initially at $2000
; Use hi-bit ASCII for Apple II
!convtab "../include/hiBitAscii.ct"
; Global definitions
!source "../include/global.i"
bits = $B ; len 1
pSrc = $C ; len 2
pDst = $E ; len 2
; Decompress from pSrc to pDst. They can overlap, as long as the source block
; ends (at least) 2 bytes beyond the end of the dest block, e.g.
; DDDDDDDDDDDDDDD
; SSSSSSSSSSSss <-- 2 bytes beyond dest
; This guarantees that the decompression won't overwrite any source material
; before it gets used.
decomp ldy #0 ; invariant: Y=0 unless we're mid-copy
sty bits
beq .lits
.lits jsr rdGamma
tax
dex
beq +
- lda (pSrc),y
sta (pDst),y
iny
dex
bne -
jsr advSrc
jsr advDst
cpy #254 ; special case: long literal string
beq .lits
ldy #0 ; back to invariant
.endchk cmp pEnd
lda pDst+1
sbc pEnd+1
bcc .seq
rts
.seq lda (pSrc),y
iny
asl
php ; save high bit for later len check
asl
bcs .bigoff
lsr
lsr
sta tmp
ldx #0
beq .gotoff ; always taken
.bigoff sta tmp
jsr rdGamma
lsr
rol tmp
lsr
rol tmp
tax
.gotoff lda pDst
sec
sbc tmp
sta pTmp
txa
eor #$FF
adc pDst+1
sta pDst+1
.len ldx #2
plp
bcc .gotlen
jsr rdGamma ; A>=1 + sec + 1 => final len 3 or more
adc #1
tax
.gotlen jsr advSrc
ldy #0
- lda (pTmp),y
sta (pDst),y
iny
dex
bne -
jsr advDst
ldy #0
beq .lits ; always taken
rdGamma lda #1
- asl bits
bne +
jsr getBits
+ bcs .ret
asl bits
bne +
jsr getBits
+ rol
bcc - ; always taken except if overflow error
.ret rts
getBits pha
lda (pSrc),y
iny
sec
rol
sta bits
pla
rts
advSrc tya
clc
adc pSrc
sta pSrc
bcc +
inc pSrc+1
+ rts
advDst tya
clc
adc pDst
sta pDst
bcc +
inc pDst+1
+ rts