From 4835e4c26c4429c80932d204f03b6cc6c9ee8389 Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Wed, 24 Jul 2019 20:08:23 +0200 Subject: [PATCH 1/8] Support backward decompression --- asm/6502/decompress_v1.asm | 98 +++++++++++++++++++++++++++++++++++++- asm/6502/decompress_v2.asm | 94 +++++++++++++++++++++++++++++++++++- src/expand_context.c | 26 ++++++++-- src/expand_context.h | 3 +- src/expand_inmem.c | 8 ++-- src/expand_inmem.h | 2 +- src/expand_streaming.c | 2 +- src/lib.h | 18 +++++++ src/lzsa.c | 34 +++++++++++-- src/shrink_context.c | 47 +++++++++++++----- src/shrink_context.h | 2 +- src/shrink_inmem.c | 2 +- src/shrink_inmem.h | 2 +- 13 files changed, 305 insertions(+), 33 deletions(-) diff --git a/asm/6502/decompress_v1.asm b/asm/6502/decompress_v1.asm index be84e88..eec59f3 100755 --- a/asm/6502/decompress_v1.asm +++ b/asm/6502/decompress_v1.asm @@ -7,6 +7,18 @@ ; ; out: ; * LZSA_DST_LO and LZSA_DST_HI contain the last decompressed byte address, +1 +; +; ----------------------------------------------------------------------------- +; Backward decompression is also supported, use lzsa -r -b +; To use it, also define BACKWARD_DECOMPRESS=1 before including this code! +; +; in: +; * LZSA_SRC_LO/LZSA_SRC_HI must contain the address of the last byte of compressed data +; * LZSA_DST_LO/LZSA_DST_HI must contain the address of the last byte of the destination buffer +; +; out: +; * LZSA_DST_LO/LZSA_DST_HI contain the last decompressed byte address, -1 +; ; ----------------------------------------------------------------------------- ; ; Copyright (C) 2019 Emmanuel Marty @@ -96,11 +108,29 @@ PREPARE_COPY_MATCH_Y COPY_MATCH_LOOP LDA $AAAA ; get one byte of backreference + JSR PUTDST ; copy to destination + +ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- put backreference bytes backward + + LDA COPY_MATCH_LOOP+1 + BNE GETMATCH_DONE + DEC COPY_MATCH_LOOP+2 +GETMATCH_DONE + DEC COPY_MATCH_LOOP+1 + +else + + ; Forward decompression -- put backreference bytes forward + INC COPY_MATCH_LOOP+1 BNE GETMATCH_DONE INC COPY_MATCH_LOOP+2 GETMATCH_DONE - JSR PUTDST ; copy to destination + +endif + DEX BNE COPY_MATCH_LOOP DEY @@ -111,6 +141,29 @@ GET_LONG_OFFSET ; handle 16 bit offset: JSR GETLARGESRC ; grab low 8 bits in X, high 8 bits in A GOT_OFFSET + +ifdef BACKWARD_DECOMPRESS + + ; Backward decompression - substract match offset + + STA OFFSHI ; store high 8 bits of offset + STX OFFSLO + + SEC ; substract dest - match offset + LDA PUTDST+1 +OFFSLO = *+1 + SBC #$AA ; low 8 bits + STA COPY_MATCH_LOOP+1 ; store back reference address + LDA PUTDST+2 +OFFSHI = *+1 + SBC #$AA ; high 8 bits + STA COPY_MATCH_LOOP+2 ; store high 8 bits of address + SEC + +else + + ; Forward decompression - add match offset + STA OFFSHI ; store high 8 bits of offset TXA @@ -123,6 +176,8 @@ OFFSHI = *+1 ADC PUTDST+2 STA COPY_MATCH_LOOP+2 ; store high 8 bits of address +endif + PLA ; retrieve token from stack again AND #$0F ; isolate match len (MMMM) ADC #$02 ; plus carry which is always set by the high ADC @@ -145,6 +200,45 @@ OFFSHI = *+1 DECOMPRESSION_DONE RTS +ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- get and put bytes backward + +GETPUT + JSR GETSRC +PUTDST +LZSA_DST_LO = *+1 +LZSA_DST_HI = *+2 + STA $AAAA + LDA PUTDST+1 + BNE PUTDST_DONE + DEC PUTDST+2 +PUTDST_DONE + DEC PUTDST+1 + RTS + +GETLARGESRC + JSR GETSRC ; grab low 8 bits + TAX ; move to X + ; fall through grab high 8 bits + +GETSRC +LZSA_SRC_LO = *+1 +LZSA_SRC_HI = *+2 + LDA $AAAA + PHA + LDA GETSRC+1 + BNE GETSRC_DONE + DEC GETSRC+2 +GETSRC_DONE + DEC GETSRC+1 + PLA + RTS + +else + + ; Forward decompression -- get and put bytes forward + GETPUT JSR GETSRC PUTDST @@ -171,3 +265,5 @@ LZSA_SRC_HI = *+2 INC GETSRC+2 GETSRC_DONE RTS + +endif diff --git a/asm/6502/decompress_v2.asm b/asm/6502/decompress_v2.asm index 9bd7942..46f2a58 100755 --- a/asm/6502/decompress_v2.asm +++ b/asm/6502/decompress_v2.asm @@ -8,6 +8,18 @@ ; ; out: ; * LZSA_DST_LO and LZSA_DST_HI contain the last decompressed byte address, +1 +; +; ----------------------------------------------------------------------------- +; Backward decompression is also supported, use lzsa -r -b -f2 +; To use it, also define BACKWARD_DECOMPRESS=1 before including this code! +; +; in: +; * LZSA_SRC_LO/LZSA_SRC_HI must contain the address of the last byte of compressed data +; * LZSA_DST_LO/LZSA_DST_HI must contain the address of the last byte of the destination buffer +; +; out: +; * LZSA_DST_LO/LZSA_DST_HI contain the last decompressed byte address, -1 +; ; ----------------------------------------------------------------------------- ; ; Copyright (C) 2019 Emmanuel Marty @@ -130,6 +142,25 @@ GOT_OFFSET_LO STX OFFSHI ; store high byte of match offset REP_MATCH +ifdef BACKWARD_DECOMPRESS + + ; Backward decompression - substract match offset + + SEC ; add dest + match offset + LDA PUTDST+1 ; low 8 bits +OFFSLO = *+1 + SBC #$AA + STA COPY_MATCH_LOOP+1 ; store back reference address + LDA PUTDST+2 +OFFSHI = *+1 + SBC #$AA ; high 8 bits + STA COPY_MATCH_LOOP+2 ; store high 8 bits of address + SEC + +else + + ; Forward decompression - add match offset + CLC ; add dest + match offset LDA PUTDST+1 ; low 8 bits OFFSLO = *+1 @@ -140,6 +171,8 @@ OFFSHI = *+1 ADC PUTDST+2 STA COPY_MATCH_LOOP+2 ; store high 8 bits of address +endif + PLA ; retrieve token from stack again AND #$07 ; isolate match len (MMM) ADC #$01 ; add MIN_MATCH_SIZE_V2 and carry @@ -173,11 +206,29 @@ PREPARE_COPY_MATCH_Y COPY_MATCH_LOOP LDA $AAAA ; get one byte of backreference + JSR PUTDST ; copy to destination + +ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- put backreference bytes backward + + LDA COPY_MATCH_LOOP+1 + BNE GETMATCH_DONE + DEC COPY_MATCH_LOOP+2 +GETMATCH_DONE + DEC COPY_MATCH_LOOP+1 + +else + + ; Forward decompression -- put backreference bytes forward + INC COPY_MATCH_LOOP+1 BNE GETMATCH_DONE INC COPY_MATCH_LOOP+2 GETMATCH_DONE - JSR PUTDST ; copy to destination + +endif + DEX BNE COPY_MATCH_LOOP DEY @@ -215,6 +266,45 @@ HAS_NIBBLES AND #$0F ; isolate low 4 bits of nibble RTS +ifdef BACKWARD_DECOMPRESS + + ; Backward decompression -- get and put bytes backward + +GETPUT + JSR GETSRC +PUTDST +LZSA_DST_LO = *+1 +LZSA_DST_HI = *+2 + STA $AAAA + LDA PUTDST+1 + BNE PUTDST_DONE + DEC PUTDST+2 +PUTDST_DONE + DEC PUTDST+1 + RTS + +GETLARGESRC + JSR GETSRC ; grab low 8 bits + TAX ; move to X + ; fall through grab high 8 bits + +GETSRC +LZSA_SRC_LO = *+1 +LZSA_SRC_HI = *+2 + LDA $AAAA + PHA + LDA GETSRC+1 + BNE GETSRC_DONE + DEC GETSRC+2 +GETSRC_DONE + DEC GETSRC+1 + PLA + RTS + +else + + ; Forward decompression -- get and put bytes forward + GETPUT JSR GETSRC PUTDST @@ -241,3 +331,5 @@ LZSA_SRC_HI = *+2 INC GETSRC+2 GETSRC_DONE RTS + +endif diff --git a/src/expand_context.c b/src/expand_context.c index 3178111..b02620d 100644 --- a/src/expand_context.c +++ b/src/expand_context.c @@ -35,6 +35,7 @@ #include "expand_context.h" #include "expand_block_v1.h" #include "expand_block_v2.h" +#include "lib.h" /** * Decompress one data block @@ -45,14 +46,31 @@ * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) * @param nBlockMaxSize total size of output decompression buffer, in bytes * @param nFormatVersion version of format to use (1-2) + * @param nFlags compression flags (LZSA_FLAG_xxx) * * @return size of decompressed data in bytes, or -1 for error */ -int lzsa_decompressor_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion) { +int lzsa_decompressor_expand_block(unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion, const int nFlags) { + int nDecompressedSize; + + if (nFlags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInBlock, nBlockSize); + } + if (nFormatVersion == 1) - return lzsa_decompressor_expand_block_v1(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize); + nDecompressedSize = lzsa_decompressor_expand_block_v1(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize); else if (nFormatVersion == 2) - return lzsa_decompressor_expand_block_v2(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize); + nDecompressedSize = lzsa_decompressor_expand_block_v2(pInBlock, nBlockSize, pOutData, nOutDataOffset, nBlockMaxSize); else - return -1; + nDecompressedSize = -1; + + if (nDecompressedSize != -1 && (nFlags & LZSA_FLAG_RAW_BACKWARD)) { + lzsa_reverse_buffer(pOutData + nOutDataOffset, nDecompressedSize); + } + + if (nFlags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInBlock, nBlockSize); + } + + return nDecompressedSize; } diff --git a/src/expand_context.h b/src/expand_context.h index 9b60c6f..698e039 100644 --- a/src/expand_context.h +++ b/src/expand_context.h @@ -48,10 +48,11 @@ extern "C" { * @param nOutDataOffset starting index of where to store decompressed bytes in output buffer (and size of previously decompressed bytes) * @param nBlockMaxSize total size of output decompression buffer, in bytes * @param nFormatVersion version of format to use (1-2) + * @param nFlags compression flags (LZSA_FLAG_xxx) * * @return size of decompressed data in bytes, or -1 for error */ -int lzsa_decompressor_expand_block(const unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion); +int lzsa_decompressor_expand_block(unsigned char *pInBlock, int nBlockSize, unsigned char *pOutData, int nOutDataOffset, int nBlockMaxSize, const int nFormatVersion, const int nFlags); #ifdef __cplusplus } diff --git a/src/expand_inmem.c b/src/expand_inmem.c index 501ec37..050bdbc 100644 --- a/src/expand_inmem.c +++ b/src/expand_inmem.c @@ -98,8 +98,8 @@ size_t lzsa_get_max_decompressed_size_inmem(const unsigned char *pFileData, size * * @return actual decompressed size, or -1 for error */ -size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion) { - const unsigned char *pCurFileData = pFileData; +size_t lzsa_decompress_inmem(unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion) { + unsigned char *pCurFileData = pFileData; const unsigned char *pEndFileData = pCurFileData + nFileSize; unsigned char *pCurOutBuffer = pOutBuffer; const unsigned char *pEndOutBuffer = pCurOutBuffer + nMaxOutBufferSize; @@ -107,7 +107,7 @@ size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOut const int nHeaderSize = lzsa_get_header_size(); if (nFlags & LZSA_FLAG_RAW_BLOCK) { - return (size_t)lzsa_decompressor_expand_block(pFileData, (int)nFileSize, pOutBuffer, 0, (int)nMaxOutBufferSize, *pFormatVersion); + return (size_t)lzsa_decompressor_expand_block(pFileData, (int)nFileSize, pOutBuffer, 0, (int)nMaxOutBufferSize, *pFormatVersion, nFlags); } /* Check header */ @@ -139,7 +139,7 @@ size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOut if ((pCurFileData + nBlockDataSize) > pEndFileData) return -1; - nDecompressedSize = lzsa_decompressor_expand_block(pCurFileData, nBlockDataSize, pCurOutBuffer - nPreviousBlockSize, nPreviousBlockSize, (int)(pEndOutBuffer - pCurOutBuffer + nPreviousBlockSize), *pFormatVersion); + nDecompressedSize = lzsa_decompressor_expand_block(pCurFileData, nBlockDataSize, pCurOutBuffer - nPreviousBlockSize, nPreviousBlockSize, (int)(pEndOutBuffer - pCurOutBuffer + nPreviousBlockSize), *pFormatVersion, nFlags); if (nDecompressedSize < 0) return -1; diff --git a/src/expand_inmem.h b/src/expand_inmem.h index bd95ff0..b52ee68 100644 --- a/src/expand_inmem.h +++ b/src/expand_inmem.h @@ -61,7 +61,7 @@ size_t lzsa_get_max_decompressed_size_inmem(const unsigned char *pFileData, size * * @return actual decompressed size, or -1 for error */ -size_t lzsa_decompress_inmem(const unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion); +size_t lzsa_decompress_inmem(unsigned char *pFileData, unsigned char *pOutBuffer, size_t nFileSize, size_t nMaxOutBufferSize, const unsigned int nFlags, int *pFormatVersion); #ifdef __cplusplus } diff --git a/src/expand_streaming.c b/src/expand_streaming.c index d981778..b241c68 100644 --- a/src/expand_streaming.c +++ b/src/expand_streaming.c @@ -196,7 +196,7 @@ lzsa_status_t lzsa_decompress_stream(lzsa_stream_t *pInStream, lzsa_stream_t *pO nDecompressedSize = nBlockSize; } else { - nDecompressedSize = lzsa_decompressor_expand_block(pInBlock, nBlockSize, pOutData, BLOCK_SIZE, BLOCK_SIZE, nFormatVersion); + nDecompressedSize = lzsa_decompressor_expand_block(pInBlock, nBlockSize, pOutData, BLOCK_SIZE, BLOCK_SIZE, nFormatVersion, nFlags); if (nDecompressedSize < 0) { nDecompressionError = LZSA_ERROR_DECOMPRESSION; break; diff --git a/src/lib.h b/src/lib.h index 141469c..5556d2a 100755 --- a/src/lib.h +++ b/src/lib.h @@ -69,6 +69,24 @@ typedef enum _lzsa_status_t { /* Compression flags */ #define LZSA_FLAG_FAVOR_RATIO (1<<0) /**< 1 to compress with the best ratio, 0 to trade some compression ratio for extra decompression speed */ #define LZSA_FLAG_RAW_BLOCK (1<<1) /**< 1 to emit raw block */ +#define LZSA_FLAG_RAW_BACKWARD (1<<2) /**< 1 to compress or decompress raw block backward */ + +/** + * Reverse bytes in the specified buffer + * + * @param pBuffer pointer to buffer whose contents are to be reversed + * @param nBufferSize size of buffer in bytes + */ +static inline void lzsa_reverse_buffer(unsigned char *pBuffer, const int nBufferSize) { + int nMidPoint = nBufferSize / 2; + int i, j; + + for (i = 0, j = nBufferSize - 1; i < nMidPoint; i++, j--) { + unsigned char c = pBuffer[i]; + pBuffer[i] = pBuffer[j]; + pBuffer[j] = c; + } +} #ifdef __cplusplus } diff --git a/src/lzsa.c b/src/lzsa.c index ff2e684..4fdf773 100755 --- a/src/lzsa.c +++ b/src/lzsa.c @@ -42,11 +42,12 @@ #endif #include "lib.h" -#define OPT_VERBOSE 1 -#define OPT_RAW 2 -#define OPT_FAVOR_RATIO 4 +#define OPT_VERBOSE 1 +#define OPT_RAW 2 +#define OPT_FAVOR_RATIO 4 +#define OPT_RAW_BACKWARD 8 -#define TOOL_VERSION "1.0.4" +#define TOOL_VERSION "1.0.5" /*---------------------------------------------------------------------------*/ @@ -109,6 +110,8 @@ static int do_compress(const char *pszInFilename, const char *pszOutFilename, co nFlags |= LZSA_FLAG_FAVOR_RATIO; if (nOptions & OPT_RAW) nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; if (nOptions & OPT_VERBOSE) { nStartTime = do_get_time(); @@ -160,6 +163,8 @@ static int do_decompress(const char *pszInFilename, const char *pszOutFilename, nFlags = 0; if (nOptions & OPT_RAW) nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; if (nOptions & OPT_VERBOSE) { nStartTime = do_get_time(); @@ -308,6 +313,8 @@ static int do_compare(const char *pszInFilename, const char *pszOutFilename, con nFlags = 0; if (nOptions & OPT_RAW) nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; if (nOptions & OPT_VERBOSE) { nStartTime = do_get_time(); @@ -419,6 +426,8 @@ static int do_self_test(const unsigned int nOptions, const int nMinMatchSize, in nFlags |= LZSA_FLAG_FAVOR_RATIO; if (nOptions & OPT_RAW) nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; pGeneratedData = (unsigned char*)malloc(4 * BLOCK_SIZE); if (!pGeneratedData) { @@ -590,6 +599,8 @@ static int do_compr_benchmark(const char *pszInFilename, const char *pszOutFilen nFlags |= LZSA_FLAG_FAVOR_RATIO; if (nOptions & OPT_RAW) nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; if (pszDictionaryFilename) { fprintf(stderr, "in-memory benchmarking does not support dictionaries\n"); @@ -720,6 +731,8 @@ static int do_dec_benchmark(const char *pszInFilename, const char *pszOutFilenam nFlags = 0; if (nOptions & OPT_RAW) nFlags |= LZSA_FLAG_RAW_BLOCK; + if (nOptions & OPT_RAW_BACKWARD) + nFlags |= LZSA_FLAG_RAW_BACKWARD; if (pszDictionaryFilename) { fprintf(stderr, "in-memory benchmarking does not support dictionaries\n"); @@ -987,6 +1000,13 @@ int main(int argc, char **argv) { else bArgsError = true; } + else if (!strcmp(argv[i], "-b")) { + if ((nOptions & OPT_RAW_BACKWARD) == 0) { + nOptions |= OPT_RAW_BACKWARD; + } + else + bArgsError = true; + } else { if (!pszInFilename) pszInFilename = argv[i]; @@ -999,6 +1019,11 @@ int main(int argc, char **argv) { } } + if (!bArgsError && (nOptions & OPT_RAW_BACKWARD) && !(nOptions & OPT_RAW)) { + fprintf(stderr, "error: -b (compress backwards) requires -r (raw block format)\n"); + return 100; + } + if (!bArgsError && cCommand == 't') { return do_self_test(nOptions, nMinMatchSize, nFormatVersion); } @@ -1014,6 +1039,7 @@ int main(int argc, char **argv) { fprintf(stderr, " -v: be verbose\n"); fprintf(stderr, " -f : LZSA compression format (1-2)\n"); fprintf(stderr, " -r: raw block format (max. 64 Kb files)\n"); + fprintf(stderr, " -b: compress backward (requires -r and a backward decompressor)\n"); fprintf(stderr, " -D : use dictionary file\n"); fprintf(stderr, " -m : minimum match size (3-5) (default: 3)\n"); fprintf(stderr, " --prefer-ratio: favor compression ratio (default)\n"); diff --git a/src/shrink_context.c b/src/shrink_context.c index 26a5d04..c27bf63 100644 --- a/src/shrink_context.c +++ b/src/shrink_context.c @@ -37,6 +37,7 @@ #include "shrink_block_v2.h" #include "format.h" #include "matchfinder.h" +#include "lib.h" /** * Initialize compression context @@ -188,23 +189,43 @@ void lzsa_compressor_destroy(lzsa_compressor *pCompressor) { * * @return size of compressed data in output buffer, or -1 if the data is uncompressible */ -int lzsa_compressor_shrink_block(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize) { - if (lzsa_build_suffix_array(pCompressor, pInWindow, nPreviousBlockSize + nInDataSize)) - return -1; - if (nPreviousBlockSize) { - lzsa_skip_matches(pCompressor, 0, nPreviousBlockSize); - } - lzsa_find_all_matches(pCompressor, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); +int lzsa_compressor_shrink_block(lzsa_compressor *pCompressor, unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize) { + int nCompressedSize; - if (pCompressor->format_version == 1) { - return lzsa_optimize_and_write_block_v1(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize); - } - else if (pCompressor->format_version == 2) { - return lzsa_optimize_and_write_block_v2(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize); + if (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInWindow + nPreviousBlockSize, nInDataSize); } + + if (lzsa_build_suffix_array(pCompressor, pInWindow, nPreviousBlockSize + nInDataSize)) + nCompressedSize = -1; else { - return -1; + if (nPreviousBlockSize) { + lzsa_skip_matches(pCompressor, 0, nPreviousBlockSize); + } + lzsa_find_all_matches(pCompressor, nPreviousBlockSize, nPreviousBlockSize + nInDataSize); + + if (pCompressor->format_version == 1) { + nCompressedSize = lzsa_optimize_and_write_block_v1(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize); + if (nCompressedSize != -1 && (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD)) { + lzsa_reverse_buffer(pOutData, nCompressedSize); + } + } + else if (pCompressor->format_version == 2) { + nCompressedSize = lzsa_optimize_and_write_block_v2(pCompressor, pInWindow, nPreviousBlockSize, nInDataSize, pOutData, nMaxOutDataSize); + if (nCompressedSize != -1 && (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD)) { + lzsa_reverse_buffer(pOutData, nCompressedSize); + } + } + else { + nCompressedSize = -1; + } } + + if (pCompressor->flags & LZSA_FLAG_RAW_BACKWARD) { + lzsa_reverse_buffer(pInWindow + nPreviousBlockSize, nInDataSize); + } + + return nCompressedSize; } /** diff --git a/src/shrink_context.h b/src/shrink_context.h index 4bbf6ec..cf9b1c5 100644 --- a/src/shrink_context.h +++ b/src/shrink_context.h @@ -123,7 +123,7 @@ void lzsa_compressor_destroy(lzsa_compressor *pCompressor); * * @return size of compressed data in output buffer, or -1 if the data is uncompressible */ -int lzsa_compressor_shrink_block(lzsa_compressor *pCompressor, const unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize); +int lzsa_compressor_shrink_block(lzsa_compressor *pCompressor, unsigned char *pInWindow, const int nPreviousBlockSize, const int nInDataSize, unsigned char *pOutData, const int nMaxOutDataSize); /** * Get the number of compression commands issued in compressed data blocks diff --git a/src/shrink_inmem.c b/src/shrink_inmem.c index 32a727b..c3596b7 100644 --- a/src/shrink_inmem.c +++ b/src/shrink_inmem.c @@ -62,7 +62,7 @@ size_t lzsa_get_max_compressed_size_inmem(size_t nInputSize) { * * @return actual compressed size, or -1 for error */ -size_t lzsa_compress_inmem(const unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, +size_t lzsa_compress_inmem(unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion) { lzsa_compressor compressor; size_t nOriginalSize = 0; diff --git a/src/shrink_inmem.h b/src/shrink_inmem.h index 2c9c89f..2bd8f27 100644 --- a/src/shrink_inmem.h +++ b/src/shrink_inmem.h @@ -61,7 +61,7 @@ size_t lzsa_get_max_compressed_size_inmem(size_t nInputSize); * * @return actual compressed size, or -1 for error */ -size_t lzsa_compress_inmem(const unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, +size_t lzsa_compress_inmem(unsigned char *pInputData, unsigned char *pOutBuffer, size_t nInputSize, size_t nMaxOutBufferSize, const unsigned int nFlags, const int nMinMatchSize, const int nFormatVersion); #ifdef __cplusplus From 316dfdcdce82cddeed6939930110bbe53b118732 Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Fri, 26 Jul 2019 01:12:17 +0200 Subject: [PATCH 2/8] Fix comments, remove unused vars --- src/shrink_block_v2.c | 2 -- src/shrink_streaming.c | 2 ++ src/shrink_streaming.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shrink_block_v2.c b/src/shrink_block_v2.c index cb7a510..99a4367 100644 --- a/src/shrink_block_v2.c +++ b/src/shrink_block_v2.c @@ -188,7 +188,6 @@ static void lzsa_optimize_matches_v2(lzsa_compressor *pCompressor, const int nSt int *cost = (int*)pCompressor->pos_data; /* Reuse */ int *prev_match = (int*)pCompressor->intervals; /* Reuse */ lzsa_repmatch_opt *repmatch_opt = pCompressor->repmatch_opt; - lzsa_match *pBestMatch = pCompressor->best_match; int nLastLiteralsOffset; int nMinMatchSize = pCompressor->min_match_size; const int nFavorRatio = (pCompressor->flags & LZSA_FLAG_FAVOR_RATIO) ? 1 : 0; @@ -805,7 +804,6 @@ static int lzsa_get_compressed_size_v2(lzsa_compressor *pCompressor, lzsa_match } { - int nTokenLiteralsLen = (nNumLiterals >= LITERALS_RUN_LEN_V2) ? LITERALS_RUN_LEN_V2 : nNumLiterals; int nCommandSize = 8 /* token */ + lzsa_get_literals_varlen_size_v2(nNumLiterals) + (nNumLiterals << 3); nCompressedSize += nCommandSize; diff --git a/src/shrink_streaming.c b/src/shrink_streaming.c index 63dc89f..58471e4 100644 --- a/src/shrink_streaming.c +++ b/src/shrink_streaming.c @@ -70,6 +70,7 @@ static void lzsa_delete_file(const char *pszInFilename) { * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful * * @return LZSA_OK for success, or an error value from lzsa_status_t */ @@ -127,6 +128,7 @@ lzsa_status_t lzsa_compress_file(const char *pszInFilename, const char *pszOutFi * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful * * @return LZSA_OK for success, or an error value from lzsa_status_t */ diff --git a/src/shrink_streaming.h b/src/shrink_streaming.h index 2d2186e..1e66bdc 100644 --- a/src/shrink_streaming.h +++ b/src/shrink_streaming.h @@ -57,6 +57,7 @@ typedef enum _lzsa_status_t lzsa_status_t; * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful * * @return LZSA_OK for success, or an error value from lzsa_status_t */ @@ -80,6 +81,7 @@ lzsa_status_t lzsa_compress_file(const char *pszInFilename, const char *pszOutFi * @param pOriginalSize pointer to returned input(source) size, updated when this function is successful * @param pCompressedSize pointer to returned output(compressed) size, updated when this function is successful * @param pCommandCount pointer to returned token(compression commands) count, updated when this function is successful + * @param pSafeDist pointer to return safe distance for raw blocks, updated when this function is successful * * @return LZSA_OK for success, or an error value from lzsa_status_t */ From ae4cc12aedafe53bcfbcb48abfbbd47f7e6d4e8c Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Fri, 26 Jul 2019 12:31:26 +0200 Subject: [PATCH 3/8] Use ACME syntax --- asm/6502/decompress_v1.asm | 30 +++++++++++++++--------------- asm/6502/decompress_v2.asm | 27 ++++++++++++++------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/asm/6502/decompress_v1.asm b/asm/6502/decompress_v1.asm index eec59f3..445c7f6 100755 --- a/asm/6502/decompress_v1.asm +++ b/asm/6502/decompress_v1.asm @@ -49,10 +49,10 @@ DECODE_TOKEN AND #$70 ; isolate literals count BEQ NO_LITERALS ; skip if no literals to copy - LSR A ; shift literals count into place - LSR A - LSR A - LSR A + LSR ; shift literals count into place + LSR + LSR + LSR CMP #$07 ; LITERALS_RUN_LEN? BCC PREPARE_COPY_LITERALS ; if not, count is directly embedded in token @@ -71,7 +71,7 @@ LARGE_VARLEN_LITERALS ; handle 16 bits literals count ; literals count = directly these 16 bits JSR GETLARGESRC ; grab low 8 bits in X, high 8 bits in A TAY ; put high 8 bits in Y - BYTE $A9 ; mask TAX (faster than BCS) + !byte $A9 ; mask TAX (faster than BCS) PREPARE_COPY_LITERALS TAX BEQ COPY_LITERALS @@ -91,7 +91,7 @@ NO_LITERALS JSR GETSRC ; get 8 bit offset from stream in A TAX ; save for later - LDA #$0FF ; high 8 bits + LDA #$FF ; high 8 bits BNE GOT_OFFSET ; go prepare match ; (*like JMP GOT_OFFSET but shorter) @@ -110,7 +110,7 @@ COPY_MATCH_LOOP LDA $AAAA ; get one byte of backreference JSR PUTDST ; copy to destination -ifdef BACKWARD_DECOMPRESS +!ifdef BACKWARD_DECOMPRESS { ; Backward decompression -- put backreference bytes backward @@ -120,7 +120,7 @@ ifdef BACKWARD_DECOMPRESS GETMATCH_DONE DEC COPY_MATCH_LOOP+1 -else +} else { ; Forward decompression -- put backreference bytes forward @@ -129,7 +129,7 @@ else INC COPY_MATCH_LOOP+2 GETMATCH_DONE -endif +} DEX BNE COPY_MATCH_LOOP @@ -142,7 +142,7 @@ GET_LONG_OFFSET ; handle 16 bit offset: GOT_OFFSET -ifdef BACKWARD_DECOMPRESS +!ifdef BACKWARD_DECOMPRESS { ; Backward decompression - substract match offset @@ -160,7 +160,7 @@ OFFSHI = *+1 STA COPY_MATCH_LOOP+2 ; store high 8 bits of address SEC -else +} else { ; Forward decompression - add match offset @@ -176,7 +176,7 @@ OFFSHI = *+1 ADC PUTDST+2 STA COPY_MATCH_LOOP+2 ; store high 8 bits of address -endif +} PLA ; retrieve token from stack again AND #$0F ; isolate match len (MMMM) @@ -200,7 +200,7 @@ endif DECOMPRESSION_DONE RTS -ifdef BACKWARD_DECOMPRESS +!ifdef BACKWARD_DECOMPRESS { ; Backward decompression -- get and put bytes backward @@ -235,7 +235,7 @@ GETSRC_DONE PLA RTS -else +} else { ; Forward decompression -- get and put bytes forward @@ -266,4 +266,4 @@ LZSA_SRC_HI = *+2 GETSRC_DONE RTS -endif +} diff --git a/asm/6502/decompress_v2.asm b/asm/6502/decompress_v2.asm index 46f2a58..f6bd1a0 100755 --- a/asm/6502/decompress_v2.asm +++ b/asm/6502/decompress_v2.asm @@ -53,9 +53,9 @@ DECODE_TOKEN AND #$18 ; isolate literals count (LL) BEQ NO_LITERALS ; skip if no literals to copy - LSR A ; shift literals count into place - LSR A - LSR A + LSR ; shift literals count into place + LSR + LSR CMP #$03 ; LITERALS_RUN_LEN_V2? BCC PREPARE_COPY_LITERALS ; if less, count is directly embedded in token @@ -102,7 +102,7 @@ NO_LITERALS ; 00Z: 5 bit offset - LDX #$0FF ; set offset bits 15-8 to 1 + LDX #$FF ; set offset bits 15-8 to 1 JSR GETCOMBINEDBITS ; rotate Z bit into bit 0, read nibble for bits 4-1 ORA #$E0 ; set bits 7-5 to 1 @@ -142,7 +142,7 @@ GOT_OFFSET_LO STX OFFSHI ; store high byte of match offset REP_MATCH -ifdef BACKWARD_DECOMPRESS +!ifdef BACKWARD_DECOMPRESS { ; Backward decompression - substract match offset @@ -157,7 +157,7 @@ OFFSHI = *+1 STA COPY_MATCH_LOOP+2 ; store high 8 bits of address SEC -else +} else { ; Forward decompression - add match offset @@ -171,7 +171,7 @@ OFFSHI = *+1 ADC PUTDST+2 STA COPY_MATCH_LOOP+2 ; store high 8 bits of address -endif +} PLA ; retrieve token from stack again AND #$07 ; isolate match len (MMM) @@ -208,7 +208,7 @@ COPY_MATCH_LOOP LDA $AAAA ; get one byte of backreference JSR PUTDST ; copy to destination -ifdef BACKWARD_DECOMPRESS +!ifdef BACKWARD_DECOMPRESS { ; Backward decompression -- put backreference bytes backward @@ -218,7 +218,7 @@ ifdef BACKWARD_DECOMPRESS GETMATCH_DONE DEC COPY_MATCH_LOOP+1 -else +} else { ; Forward decompression -- put backreference bytes forward @@ -227,7 +227,7 @@ else INC COPY_MATCH_LOOP+2 GETMATCH_DONE -endif +} DEX BNE COPY_MATCH_LOOP @@ -266,7 +266,7 @@ HAS_NIBBLES AND #$0F ; isolate low 4 bits of nibble RTS -ifdef BACKWARD_DECOMPRESS +!ifdef BACKWARD_DECOMPRESS { ; Backward decompression -- get and put bytes backward @@ -301,7 +301,7 @@ GETSRC_DONE PLA RTS -else +} else { ; Forward decompression -- get and put bytes forward @@ -332,4 +332,5 @@ LZSA_SRC_HI = *+2 GETSRC_DONE RTS -endif +} + From b613d01565fa820317c430be9e6584cfa78f6a8a Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Fri, 26 Jul 2019 13:30:41 +0200 Subject: [PATCH 4/8] Test incompressible data with raw blocks --- src/lzsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lzsa.c b/src/lzsa.c index 4fdf773..fe067ea 100755 --- a/src/lzsa.c +++ b/src/lzsa.c @@ -486,7 +486,7 @@ static int do_self_test(const unsigned int nOptions, const int nMinMatchSize, in float fMatchProbability; fprintf(stdout, "size %zd", nGeneratedDataSize); - for (fMatchProbability = ((nOptions & OPT_RAW) ? 0.5f : 0); fMatchProbability <= 0.995f; fMatchProbability += fProbabilitySizeStep) { + for (fMatchProbability = 0; fMatchProbability <= 0.995f; fMatchProbability += fProbabilitySizeStep) { int nNumLiteralValues[12] = { 1, 2, 3, 15, 30, 56, 96, 137, 178, 191, 255, 256 }; float fXorProbability; From 82edcb8bb53b9c1e1a95b157f446d5fc3fc8dde0 Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Sat, 27 Jul 2019 01:35:46 +0200 Subject: [PATCH 5/8] Fix literal runs that are multiple of 256 bytes --- asm/6502/decompress_v1.asm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asm/6502/decompress_v1.asm b/asm/6502/decompress_v1.asm index 445c7f6..e49a595 100755 --- a/asm/6502/decompress_v1.asm +++ b/asm/6502/decompress_v1.asm @@ -71,7 +71,8 @@ LARGE_VARLEN_LITERALS ; handle 16 bits literals count ; literals count = directly these 16 bits JSR GETLARGESRC ; grab low 8 bits in X, high 8 bits in A TAY ; put high 8 bits in Y - !byte $A9 ; mask TAX (faster than BCS) + TXA + PREPARE_COPY_LITERALS TAX BEQ COPY_LITERALS From 0a04796b199a955062d934b772f70024acd224dc Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Sat, 27 Jul 2019 15:39:44 +0200 Subject: [PATCH 6/8] Fix for z80 LZSA2 fast backward depacker --- asm/z80/unlzsa2_fast_v1.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asm/z80/unlzsa2_fast_v1.asm b/asm/z80/unlzsa2_fast_v1.asm index 7274e68..56734ca 100644 --- a/asm/z80/unlzsa2_fast_v1.asm +++ b/asm/z80/unlzsa2_fast_v1.asm @@ -110,7 +110,7 @@ LongMatch: ;ld a,24 : ManyLiterals: ld a,18 : add (hl) : NEXT_HL : jr nc,CopyLiterals ld c,(hl) : NEXT_HL - ld a,b : ld b,(hl) : inc hl + ld a,b : ld b,(hl) : NEXT_HL jr CopyLiterals.useBC From b3aae36ecc823851a239a3be3224c0c8106e1edc Mon Sep 17 00:00:00 2001 From: Emmanuel Marty Date: Sun, 28 Jul 2019 00:25:51 +0200 Subject: [PATCH 7/8] Bump version --- src/lzsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lzsa.c b/src/lzsa.c index fe067ea..b517179 100755 --- a/src/lzsa.c +++ b/src/lzsa.c @@ -47,7 +47,7 @@ #define OPT_FAVOR_RATIO 4 #define OPT_RAW_BACKWARD 8 -#define TOOL_VERSION "1.0.5" +#define TOOL_VERSION "1.0.6" /*---------------------------------------------------------------------------*/ From 8d0528fddc0d124a5fdb04581247dd7acb4ccf2e Mon Sep 17 00:00:00 2001 From: uniabis Date: Wed, 31 Jul 2019 01:39:27 +0900 Subject: [PATCH 8/8] hd64180 support a bit faster, a bit smaller --- asm/z80/unlzsa1_fast_v1.asm | 10 +++---- asm/z80/unlzsa1_small_v1.asm | 10 +++---- asm/z80/unlzsa2_fast_v1.asm | 51 ++++++++++++++++++++++++------------ asm/z80/unlzsa2_small_v1.asm | 51 +++++++++++++++++++++++++++++------- 4 files changed, 85 insertions(+), 37 deletions(-) diff --git a/asm/z80/unlzsa1_fast_v1.asm b/asm/z80/unlzsa1_fast_v1.asm index b8443cd..c3bbfca 100644 --- a/asm/z80/unlzsa1_fast_v1.asm +++ b/asm/z80/unlzsa1_fast_v1.asm @@ -1,5 +1,5 @@ ; -; Speed-optimized LZSA decompressor by spke (v.1 03-25/04/2019, 110 bytes) +; Speed-optimized LZSA decompressor by spke (v.1 03-25/04/2019 +patch1-30/07/2019, 109 bytes) ; ; The data must be compressed using the command line compressor by Emmanuel Marty ; The compression is done as follows: @@ -56,7 +56,7 @@ ENDM MACRO ADD_OFFSET - or a : sbc hl,de + push hl : or a : sbc hl,de : pop de ENDM MACRO BLOCKCOPY @@ -70,7 +70,7 @@ ENDM MACRO ADD_OFFSET - add hl,de + ex de,hl : add hl,de ENDM MACRO BLOCKCOPY @@ -90,8 +90,8 @@ ShortOffset: ld d,#FF : add 3 : cp 15+3 : jr nc,LongerMatch ; placed here this saves a JP per iteration CopyMatch: ld c,a -.UseC ex (sp),hl : push hl ; BC = len, DE = offset, HL = dest, SP ->[dest,src] - ADD_OFFSET : pop de ; BC = len, DE = dest, HL = dest-offset, SP->[src] +.UseC ex (sp),hl ; BC = len, DE = offset, HL = dest, SP ->[src] + ADD_OFFSET ; BC = len, DE = dest, HL = dest-offset, SP->[src] BLOCKCOPY : pop hl ; BC = 0, DE = dest, HL = src ReadToken: ; first a byte token "O|LLL|MMMM" is read from the stream, diff --git a/asm/z80/unlzsa1_small_v1.asm b/asm/z80/unlzsa1_small_v1.asm index df4dfc5..6568660 100644 --- a/asm/z80/unlzsa1_small_v1.asm +++ b/asm/z80/unlzsa1_small_v1.asm @@ -1,5 +1,5 @@ ; -; Size-optimized LZSA decompressor by spke (v.1 23/04/2019, 69 bytes) +; Size-optimized LZSA decompressor by spke (v.1 23/04/2019 +patch1-30/07/2019, 68 bytes) ; ; The data must be compressed using the command line compressor by Emmanuel Marty ; The compression is done as follows: @@ -56,7 +56,7 @@ ENDM MACRO ADD_OFFSET - or a : sbc hl,de + push hl : or a : sbc hl,de : pop de ENDM MACRO BLOCKCOPY @@ -70,7 +70,7 @@ ENDM MACRO ADD_OFFSET - add hl,de + ex de,hl : add hl,de ENDM MACRO BLOCKCOPY @@ -106,8 +106,8 @@ ShortOffset: and #0F : add 3 ; MMMM<15 means match lengths 0+3..14+3 cp 15+3 : call z,ReadLongBA ; MMMM=15 means lengths 14+3+ ld c,a - ex (sp),hl : push hl ; BC = len, DE = -offset, HL = dest, SP ->[dest,src] - ADD_OFFSET : pop de ; BC = len, DE = dest, HL = dest+(-offset), SP->[src] + ex (sp),hl ; BC = len, DE = -offset, HL = dest, SP ->[src] + ADD_OFFSET ; BC = len, DE = dest, HL = dest+(-offset), SP->[src] BLOCKCOPY : pop hl ; BC = 0, DE = dest, HL = src jr ReadToken diff --git a/asm/z80/unlzsa2_fast_v1.asm b/asm/z80/unlzsa2_fast_v1.asm index 56734ca..04d8668 100644 --- a/asm/z80/unlzsa2_fast_v1.asm +++ b/asm/z80/unlzsa2_fast_v1.asm @@ -1,5 +1,5 @@ ; -; Speed-optimized LZSA2 decompressor by spke (v.1 02-07/06/2019, 218 bytes) +; Speed-optimized LZSA2 decompressor by spke (v.1 02-07/06/2019 +patch1-30/07/2019, 213/211(hd64180) bytes) ; ; The data must be compressed using the command line compressor by Emmanuel Marty ; The compression is done as follows: @@ -56,7 +56,7 @@ ENDM MACRO ADD_OFFSET - or a : sbc hl,de + push hl : or a : sbc hl,de : pop de ENDM MACRO BLOCKCOPY @@ -70,7 +70,7 @@ ENDM MACRO ADD_OFFSET - add hl,de + ex de,hl : add hl,de ENDM MACRO BLOCKCOPY @@ -79,16 +79,32 @@ ENDIF + IFDEF HD64180 + MACRO LD_IX_DE + push de : pop ix + ENDM + MACRO LD_DE_IX + push ix : pop de + ENDM + ELSE + MACRO LD_IX_DE + ld ixl,e : ld ixh,d + ENDM + MACRO LD_DE_IX + ld e,ixl : ld d,ixh + ENDM + ENDIF + @DecompressLZSA2: ; A' stores next nibble as %1111.... or assumed to contain trash ; B is assumed to be 0 - xor a : ld b,a : exa : jr ReadToken + xor a : ld b,a : scf : exa : jr ReadToken -LongerMatch: exa : jp m,.noUpdate +LongerMatch: scf : exa : jr nc,.noUpdate ld a,(hl) : or #F0 : exa ld a,(hl) : NEXT_HL : or #0F @@ -110,14 +126,14 @@ LongMatch: ;ld a,24 : ManyLiterals: ld a,18 : add (hl) : NEXT_HL : jr nc,CopyLiterals ld c,(hl) : NEXT_HL - ld a,b : ld b,(hl) : NEXT_HL - jr CopyLiterals.useBC + ld a,b : ld b,(hl) + jr ReadToken.useBC MoreLiterals: ld b,(hl) : NEXT_HL - exa : jp m,.noUpdate + scf : exa : jr nc,.noUpdate ld a,(hl) : or #F0 : exa ld a,(hl) : NEXT_HL : or #0F @@ -148,13 +164,13 @@ CASE01x: cp %01100000 : rl d ReadOffsetE: ld e,(hl) : NEXT_HL -SaveOffset: ld ixl,e : ld ixh,d +SaveOffset: LD_IX_DE MatchLen: inc a : and %00000111 : jr z,LongerMatch : inc a CopyMatch: ld c,a -.useC ex (sp),hl : push hl ; BC = len, DE = offset, HL = dest, SP ->[dest,src] - ADD_OFFSET : pop de ; BC = len, DE = dest, HL = dest-offset, SP->[src] +.useC ex (sp),hl ; BC = len, DE = offset, HL = dest, SP ->[src] + ADD_OFFSET ; BC = len, DE = dest, HL = dest-offset, SP->[src] BLOCKCOPY : pop hl ; compressed data stream contains records @@ -164,7 +180,8 @@ ReadToken: ld a,(hl) : and %00011000 : jr z,NoLiterals jp pe,MoreLiterals ; 00 has already been processed; this identifies the case of 11 rrca : rrca : rrca - ld c,a : ld a,(hl) : NEXT_HL ; token is re-read for further processing + ld c,a : ld a,(hl) ; token is re-read for further processing +.useBC NEXT_HL BLOCKCOPY ; the token and literals are followed by the offset @@ -173,8 +190,8 @@ ReadToken: ld a,(hl) : and %00011000 : jr z,NoLiterals CASE1xx cp %11000000 : jr nc,CASE11x ; "10x": the case of the 5-bit offset -CASE10x: ld c,a : xor a - exa : jp m,.noUpdate +CASE10x: ld c,a + exa : jr nc,.noUpdate ld a,(hl) : or #F0 : exa ld a,(hl) : NEXT_HL : or #0F @@ -185,8 +202,8 @@ CASE10x: ld c,a : xor a dec d : dec d : jr ReadOffsetE ; "00x": the case of the 5-bit offset -CASE00x: ld c,a : xor a - exa : jp m,.noUpdate +CASE00x: ld c,a + exa : jr nc,.noUpdate ld a,(hl) : or #F0 : exa ld a,(hl) : NEXT_HL : or #0F @@ -199,7 +216,7 @@ CASE00x: ld c,a : xor a CASE11x cp %11100000 : jr c,CASE110 ; "111": repeated offset -CASE111: ld e,ixl : ld d,ixh : jr MatchLen +CASE111: LD_DE_IX : jr MatchLen ; "110": 16-bit offset CASE110: ld d,(hl) : NEXT_HL : jr ReadOffsetE diff --git a/asm/z80/unlzsa2_small_v1.asm b/asm/z80/unlzsa2_small_v1.asm index a2697e7..c73a50b 100644 --- a/asm/z80/unlzsa2_small_v1.asm +++ b/asm/z80/unlzsa2_small_v1.asm @@ -1,5 +1,5 @@ ; -; Size-optimized LZSA2 decompressor by spke (v.1 02-09/06/2019, 145 bytes) +; Size-optimized LZSA2 decompressor by spke (v.1 02-09/06/2019 +patch1-30/07/2019, 144 bytes) ; ; The data must be compressed using the command line compressor by Emmanuel Marty ; The compression is done as follows: @@ -57,7 +57,7 @@ ENDM MACRO ADD_OFFSET - or a : sbc hl,de + push hl : or a : sbc hl,de : pop de ENDM MACRO BLOCKCOPY @@ -71,7 +71,7 @@ ENDM MACRO ADD_OFFSET - add hl,de + ex de,hl : add hl,de ENDM MACRO BLOCKCOPY @@ -80,6 +80,37 @@ ENDIF + IFDEF HD64180 + MACRO LD_IY_DE + push de : pop iy + ENDM + MACRO LD_DE_IY + push iy : pop de + ENDM + MACRO LD_IXL_A + exx : ld l,a : exx + ENDM + MACRO LD_A_IXL + exx : ld a,l : exx + ENDM + ELSE + MACRO LD_IY_DE + ;push de : pop iy + ld iyl,e : ld iyh,d + ENDM + MACRO LD_DE_IY + ;push iy : pop de + ld e,iyl : ld d,iyh + ENDM + MACRO LD_IXL_A + ld ixl,a + ENDM + MACRO LD_A_IXL + ld a,ixl + ENDM + ENDIF + + @DecompressLZSA2: xor a : ld b,a : exa : jr ReadToken @@ -88,17 +119,17 @@ CASE0xx ld d,#FF : cp %01000000 : jr c,CASE00x CASE01x: cp %01100000 : rl d OffsetReadE: ld e,(hl) : NEXT_HL - -SaveOffset: ld iyl,e : ld iyh,d + +SaveOffset: LD_IY_DE MatchLen: and %00000111 : add 2 : cp 9 : call z,ExtendedCode CopyMatch: ld c,a - ex (sp),hl : push hl ; BC = len, DE = offset, HL = dest, SP ->[dest,src] - ADD_OFFSET : pop de ; BC = len, DE = dest, HL = dest-offset, SP->[src] + ex (sp),hl ; BC = len, DE = offset, HL = dest, SP ->[src] + ADD_OFFSET ; BC = len, DE = dest, HL = dest-offset, SP->[src] BLOCKCOPY : pop hl -ReadToken: ld a,(hl) : ld ixl,a : NEXT_HL +ReadToken: ld a,(hl) : LD_IXL_A : NEXT_HL and %00011000 : jr z,NoLiterals rrca : rrca : rrca @@ -107,7 +138,7 @@ ReadToken: ld a,(hl) : ld ixl,a : NEXT_HL ld c,a BLOCKCOPY -NoLiterals: push de : ld a,ixl +NoLiterals: push de : LD_A_IXL or a : jp p,CASE0xx CASE1xx cp %11000000 : jr nc,CASE11x @@ -123,7 +154,7 @@ CASE00x: call ReadNibble CASE11x cp %11100000 : jr c,CASE110 -CASE111: ld e,iyl : ld d,iyh : jr MatchLen +CASE111: LD_DE_IY : jr MatchLen CASE110: ld d,(hl) : NEXT_HL : jr OffsetReadE