Reorganize token byte for faster decoding on 8-bit CPUs, without affecting the compression ratio

This commit is contained in:
emmanuel-marty 2019-04-05 11:58:44 +02:00
parent 33b62c004a
commit 1ef1ad8111
4 changed files with 21 additions and 21 deletions

View File

@ -75,7 +75,7 @@ Each frame contains a 3-bytes length followed by block data that expands to up t
LZSA blocks are composed from consecutive commands. Each command follows this format:
* token: <O|LLL|MMMM>
* token: <LLL|MMMM|O>
* optional extra literal length
* literal values
* match offset low
@ -87,11 +87,11 @@ LZSA blocks are composed from consecutive commands. Each command follows this fo
The token byte is broken down into three parts:
7 6 5 4 3 2 1 0
O L L L M M M M
L L L M M M M O
* O: set for a 2-bytes match offset, clear for a 1-byte match offset
* L: 3-bit literals length (0-6, or 7 if extended). If the number of literals for this command is 0 to 6, the length is encoded in the token and no extra bytes are required. Otherwise, a value of 7 is encoded and extra bytes follow as 'optional extra literal length'
* M: 4-bit encoded match length (0-14, or 15 if extended). Likewise, if the encoded match length for this command is 0 to 14, it is directly stored, otherwise 15 is stored and extra bytes follow as 'optional extra encoded match length'. Except for the last command in a block, a command always contains a match, so the encoded match length is the actual match length offset by the minimum, which is 3 bytes. For instance, an actual match length of 10 bytes to be copied, is encoded as 7.
* O: set for a 2-bytes match offset, clear for a 1-byte match offset
**optional extra literal length**
@ -113,7 +113,7 @@ The low 8 bits of the match offset follows.
**optional match offset high**
If the 'O' bit (bit 7) is set in the token, the high 8 bits of the match offset follow, otherwise they are understood to be all set to 0.
If the 'O' bit (bit 0) is set in the token, the high 8 bits of the match offset follow, otherwise they are understood to be all set to 0.
**important note regarding short match offsets: off by 1**

View File

@ -37,13 +37,13 @@ lzsa_decompress:
xor cx,cx
.decode_token:
mov ax,cx ; clear ah - cx is zero from above or from after rep movsw in .copy_match
lodsb ; read token byte: O|LLL|MMMM
mov ax,cx ; clear ah - cx is zero from above or from after rep movsb in .copy_match
lodsb ; read token byte: LLL|MMMM|O
mov dx,ax ; keep token in dl
and al,070H ; isolate literals length in token (LLL)
mov cl,4
shr al,cl ; shift match length into place
mov cl,3
rol al,cl ; shift literals length into place
and al,07H ; isolate literals length in token (LLL)
mov cx,ax ; copy literals length into cx
cmp al,07H ; LITERALS_RUN_LEN?
@ -54,10 +54,10 @@ lzsa_decompress:
.copy_literals:
rep movsb ; copy cx literals from ds:si to es:di
test dl,dl ; check match offset size in token (O bit, ie. bit 7, the sign bit)
js .get_long_offset
ror dl,1 ; check match offset size in token (O bit)
jc .get_long_offset
xor ah,ah ; Get 1-byte match offset
xchg ax,cx ; clear ah - cx is zero from the rep movsb above
lodsb
inc ax ; the match offset is stored off-by-1, increase it
jmp short .get_match_length

View File

@ -168,7 +168,7 @@ int lzsa_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned ch
while (pInBlock < pInBlockFastEnd && pCurOutData < pOutDataFastEnd) {
const unsigned char token = *pInBlock++;
int nLiterals = (int)((unsigned int)((token & 0x70) >> 4));
int nLiterals = (int)((unsigned int)((token & 0xe0) >> 5));
if (nLiterals < LITERALS_RUN_LEN) {
memcpy(pCurOutData, pInBlock, 8);
@ -184,7 +184,7 @@ int lzsa_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned ch
int nMatchOffset;
nMatchOffset = ((unsigned int)*pInBlock++);
if (token & 0x80) {
if (token & 0x01) {
if (pInBlock >= pInBlockEnd) return -1;
nMatchOffset |= (((unsigned int)*pInBlock++) << 8);
if (nMatchOffset == 0) break;
@ -197,7 +197,7 @@ int lzsa_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned ch
if (pSrc < pOutData)
return -1;
int nMatchLen = (int)((unsigned int)(token & 0x0f));
int nMatchLen = (int)((unsigned int)((token & 0x1e) >> 1));
if (nMatchLen < (16 - MIN_MATCH_SIZE + 1) && (pSrc + MIN_MATCH_SIZE + nMatchLen) < pCurOutData && pCurOutData < pOutDataFastEnd) {
memcpy(pCurOutData, pSrc, 16);
pCurOutData += (MIN_MATCH_SIZE + nMatchLen);
@ -213,7 +213,7 @@ int lzsa_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned ch
while (pInBlock < pInBlockEnd) {
const unsigned char token = *pInBlock++;
int nLiterals = (int)((unsigned int)((token & 0x70) >> 4));
int nLiterals = (int)((unsigned int)((token & 0xe0) >> 5));
if (lzsa_expand_literals_slow(&pInBlock, pInBlockEnd, nLiterals, &pCurOutData, pOutDataEnd))
return -1;
@ -222,7 +222,7 @@ int lzsa_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned ch
int nMatchOffset;
nMatchOffset = ((unsigned int)*pInBlock++);
if (token & 0x80) {
if (token & 0x01) {
if (pInBlock >= pInBlockEnd) return -1;
nMatchOffset |= (((unsigned int)*pInBlock++) << 8);
if (nMatchOffset == 0) break;
@ -235,7 +235,7 @@ int lzsa_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned ch
if (pSrc < pOutData)
return -1;
int nMatchLen = (int)((unsigned int)(token & 0x0f));
int nMatchLen = (int)((unsigned int)((token & 0x1e) >> 1));
if (lzsa_expand_match_slow(&pInBlock, pInBlockEnd, pSrc, nMatchLen, &pCurOutData, pOutDataEnd, pOutDataFastEnd))
return -1;
}

View File

@ -585,7 +585,7 @@ static int lzsa_write_block(lsza_compressor *pCompressor, const unsigned char *p
int nEncodedMatchLen = nMatchLen - MIN_MATCH_SIZE;
int nNibbleLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN) ? LITERALS_RUN_LEN : nNumLiterals;
int nNibbleMatchLen = (nEncodedMatchLen >= MATCH_RUN_LEN) ? MATCH_RUN_LEN : nEncodedMatchLen;
int nNibbleLongOffset = (nMatchOffset <= 256) ? 0x00 : 0x80;
int nNibbleLongOffset = (nMatchOffset <= 256) ? 0x00 : 0x01;
int nTokenSize = 1 /* nibble */ + lzsa_get_literals_varlen_size(nNumLiterals) + nNumLiterals + (nNibbleLongOffset ? 2 : 1) /* match offset */ + lzsa_get_match_varlen_size(nEncodedMatchLen);
if ((nOutOffset + nTokenSize) > nMaxOutDataSize)
@ -593,7 +593,7 @@ static int lzsa_write_block(lsza_compressor *pCompressor, const unsigned char *p
if (nMatchOffset < MIN_OFFSET || nMatchOffset > MAX_OFFSET)
return -1;
pOutData[nOutOffset++] = nNibbleLongOffset | (nNibbleLiteralsLen << 4) | nNibbleMatchLen;
pOutData[nOutOffset++] = (nNibbleLiteralsLen << 5) | (nNibbleMatchLen << 1) | nNibbleLongOffset;
nOutOffset = lzsa_write_literals_varlen(pOutData, nOutOffset, nNumLiterals);
if (nNumLiterals != 0) {
@ -627,7 +627,7 @@ static int lzsa_write_block(lsza_compressor *pCompressor, const unsigned char *p
if ((nOutOffset + nTokenSize) > nMaxOutDataSize)
return -1;
pOutData[nOutOffset++] = 0x80 | (nNibbleLiteralsLen << 4);
pOutData[nOutOffset++] = (nNibbleLiteralsLen << 5) | 0x01;
nOutOffset = lzsa_write_literals_varlen(pOutData, nOutOffset, nNumLiterals);
if (nNumLiterals != 0) {