From ff02cd753c5802c25f770a788eba329ddb668d13 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 8 Jan 2017 13:09:09 +0100 Subject: [PATCH] Added icecompr --- icecompr/.gitignore | 5 + icecompr/Makefile | 31 ++++ icecompr/README | 52 +++++++ icecompr/example_1k.bin | Bin 0 -> 32220 bytes icecompr/example_8k.bin | Bin 0 -> 135100 bytes icecompr/icecompr.cc | 316 ++++++++++++++++++++++++++++++++++++++++ icecompr/iceuncompr.c | 162 ++++++++++++++++++++ 7 files changed, 566 insertions(+) create mode 100644 icecompr/.gitignore create mode 100644 icecompr/Makefile create mode 100644 icecompr/README create mode 100644 icecompr/example_1k.bin create mode 100644 icecompr/example_8k.bin create mode 100644 icecompr/icecompr.cc create mode 100644 icecompr/iceuncompr.c diff --git a/icecompr/.gitignore b/icecompr/.gitignore new file mode 100644 index 0000000..1ebf48a --- /dev/null +++ b/icecompr/.gitignore @@ -0,0 +1,5 @@ +icecompr +iceuncompr +example_?k.compr +example_?k.ok +example_?k.uncompr diff --git a/icecompr/Makefile b/icecompr/Makefile new file mode 100644 index 0000000..88512f0 --- /dev/null +++ b/icecompr/Makefile @@ -0,0 +1,31 @@ + +all: icecompr iceuncompr + +test: example_1k.ok example_8k.ok + +icecompr: icecompr.cc + clang++ -o icecompr -Wall -Wextra -std=c++11 icecompr.cc + +iceuncompr: iceuncompr.c + clang -o iceuncompr -Wall -Wextra iceuncompr.c + +%.compr: %.bin icecompr + ./icecompr -v $< $@ + + +%.uncompr: %.compr iceuncompr + ./iceuncompr $< $@ + +%.ok: %.uncompr %.bin + cmp $^ + touch $@ + +clean: + rm -f icecompr iceuncompr + rm -f example_1k.compr example_8k.compr + rm -f example_1k.uncompr example_8k.uncompr + rm -f example_1k.ok example_8k.ok + +.SECONDARY: +.PHONY: all test clean + diff --git a/icecompr/README b/icecompr/README new file mode 100644 index 0000000..5e04bb5 --- /dev/null +++ b/icecompr/README @@ -0,0 +1,52 @@ + +A simple compression algorithm for iCE40 bit-streams +==================================================== + +This directory contains tools for compressing and uncompressing +iCE40 bit-streams. The motivation is to reduce the bandwidth +requirements for bit-stream upload. + +Note that iCE40 FPGAs can not uncompress this compressed bit-streams! +Uncompression must be performed by e.g. a uC on the FPGA board. + +This compression algorithm uses the fact that most bits in an iCE40 +bit-stream are cleared. + +The bit-stream is encoded as the distances between set bits (i.e. +the length of runs of ZERO bits between two ONE bits). This sequence +of integers is stored using a simple prefix code to spend fewer bits +on smaller (more frequent) numbers. + +The algorithm includes an escape-mechanism to mix uncompressed binary +data with compressed bit-streams. This is useful when the bit-stream +contains sections that do not compress well with this algorithm, for +example in BRAM initialization data. + +The compressed bitstream starts with the ASCII string "ICECOMPR", i.e. +the hex values 0x49434543 and 0x4f4d5052 (stored as big-endian numbers). + +After the 8 bytes magic the compressed bitstream is a stream of the +following opcodes that must be interpreted by the decompressor. The +notation ZERO and ONE is used for zero and one bits. The notation foo[N] +is used for an N bit value "foo", transmitted MSB first. + + ONE count[2] + ZERO ONE count[5] + ZERO ZERO ONE count[8] + ZERO ZERO ZERO ZERO ONE count[23] + output count ZERO bits followed by a single ONE bit + + ZERO ZERO ZERO ONE count[6] data[count] + output the count data bits followed by a single ONE bit + + ZERO ZERO ZERO ZERO ZERO count[23] + output count ZERO bits and stop decompressing. (end of file) + +The program "icecompr" (C++11, ISC license) contains an implementation of a +compressor and a decompressor. The decompressor in this program however is +only used for integrity checking the compressed bit-stream. + +The program "iceuncompr" (plain C, public domain) contains an implementation +of a stand-alone decompressor. Simply copy&paste this implementation into +your uC firmware. + diff --git a/icecompr/example_1k.bin b/icecompr/example_1k.bin new file mode 100644 index 0000000000000000000000000000000000000000..0321b9ab8deafc84aace0058163391b70d0872bc GIT binary patch literal 32220 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 literal 0 HcmV?d00001 diff --git a/icecompr/example_8k.bin b/icecompr/example_8k.bin new file mode 100644 index 0000000000000000000000000000000000000000..8b6c7c54ade5c442f81ffcd7463b3ca1ef63ced4 GIT binary patch literal 135100 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 + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +int verbose = 0; + +static void push_int_bits(std::vector &outbits, int value, int bits) +{ + while (bits-- > 0) + outbits.push_back((value >> bits) & 1); +} + +static void push_zero_bits(std::vector &outbits, int bits) +{ + while (bits-- > 0) + outbits.push_back(false); +} + +static int decode_int_from_bits(const std::vector &inbits, int &cursor, int bits) +{ + int ret = 0; + while (bits-- > 0) + if (inbits.at(cursor++)) + ret |= 1 << bits; + return ret; +} + +void ice_compress(std::vector &outbits, const std::vector &inbits) +{ + int opcode_stats_d4 = 0; + int opcode_stats_d32 = 0; + int opcode_stats_d256 = 0; + int opcode_stats_raw = 0; + int opcode_stats_d8M = 0; + int opcode_stats_end = 0; + + std::vector deltas; + int numzeros = 0; + + for (auto bit : inbits) + { + if (bit) { + deltas.push_back(numzeros); + numzeros = 0; + } else { + numzeros++; + } + } + + for (int i = 0; i < int(deltas.size()); i++) + { + int raw_len = 0; + int compr_len = 0; + int best_compr_raw_diff = -1; + int best_compr_raw_idx = -1; + int best_compr_raw_len = -1; + + for (int j = 0; j+i < int(deltas.size()); j++) + { + int delta = deltas.at(i + j); + raw_len += delta + 1; + + if (delta < 4) + compr_len += 3; + else if (delta < 32) + compr_len += 7; + else if (delta < 256) + compr_len += 11; + else + compr_len += 26; + + if (compr_len - raw_len < std::max(best_compr_raw_diff - 4, 0) || raw_len > 64) + break; + + if (compr_len - raw_len > best_compr_raw_diff) { + best_compr_raw_diff = compr_len - raw_len; + best_compr_raw_idx = j; + best_compr_raw_len = raw_len; + } + } + + if (best_compr_raw_diff > 9) + { + opcode_stats_raw++; + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(true); + push_int_bits(outbits, best_compr_raw_len-1, 6); + + for (int j = 0; j <= best_compr_raw_idx; j++) { + int delta = deltas.at(i + j); + for (int k = 0; k < delta; k++) + outbits.push_back(false); + if (j < best_compr_raw_idx) + outbits.push_back(true); + } + + i += best_compr_raw_idx; + continue; + } + + int delta = deltas.at(i); + + if (delta < 4) { + opcode_stats_d4++; + outbits.push_back(true); + push_int_bits(outbits, delta, 2); + } else + if (delta < 32) { + opcode_stats_d32++; + outbits.push_back(false); + outbits.push_back(true); + push_int_bits(outbits, delta, 5); + } else + if (delta < 256) { + opcode_stats_d256++; + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(true); + push_int_bits(outbits, delta, 8); + } else { + opcode_stats_d8M++; + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(true); + push_int_bits(outbits, delta, 23); + } + } + + opcode_stats_end++; + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(false); + outbits.push_back(false); + push_int_bits(outbits, numzeros, 23); + + if (verbose > 1) { + fprintf(stderr, "opcode d4 %5d\n", opcode_stats_d4); + fprintf(stderr, "opcode d32 %5d\n", opcode_stats_d32); + fprintf(stderr, "opcode d256 %5d\n", opcode_stats_d256); + fprintf(stderr, "opcode raw %5d\n", opcode_stats_raw); + fprintf(stderr, "opcode d8M %5d\n", opcode_stats_d8M); + fprintf(stderr, "opcode end %5d\n", opcode_stats_end); + } +} + +void ice_uncompress(std::vector &outbits, const std::vector &inbits) +{ + int cursor = 0; + + while (cursor < int(inbits.size())) + { + if (inbits.at(cursor++)) { + int zeros = decode_int_from_bits(inbits, cursor, 2); + push_zero_bits(outbits, zeros); + outbits.push_back(true); + } else + if (inbits.at(cursor++)) { + int zeros = decode_int_from_bits(inbits, cursor, 5); + push_zero_bits(outbits, zeros); + outbits.push_back(true); + } else + if (inbits.at(cursor++)) { + int zeros = decode_int_from_bits(inbits, cursor, 8); + push_zero_bits(outbits, zeros); + outbits.push_back(true); + } else + if (inbits.at(cursor++)) { + int raw_len = decode_int_from_bits(inbits, cursor, 6); + while (raw_len--) + outbits.push_back(inbits.at(cursor++)); + outbits.push_back(true); + } else + if (inbits.at(cursor++)) { + int zeros = decode_int_from_bits(inbits, cursor, 23); + push_zero_bits(outbits, zeros); + outbits.push_back(true); + } else { + int zeros = decode_int_from_bits(inbits, cursor, 23); + push_zero_bits(outbits, zeros); + } + } +} + +void help() +{ + printf("\n"); + printf("Usage: icecompr [-v] [input-file [output-file]]\n"); + printf("\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + FILE *input_file = stdin; + FILE *output_file = stdout; + + int opt; + while ((opt = getopt(argc, argv, "v")) != -1) + { + switch (opt) + { + case 'v': + verbose++; + break; + default: + help(); + } + } + + if (optind < argc) { + input_file = fopen(argv[optind], "rb"); + if (input_file == NULL) { + fprintf(stderr, "Failed to open input file `%s': %s\n", argv[optind], strerror(errno)); + return 1; + } + optind++; + } + + if (optind < argc) { + output_file = fopen(argv[optind], "wb"); + if (output_file == NULL) { + fprintf(stderr, "Failed to open output file `%s': %s\n", argv[optind], strerror(errno)); + return 1; + } + optind++; + } + + if (optind != argc) + help(); + + std::vector original_bits; + int count_set_bits = 0; + + while (1) + { + int byte = fgetc(input_file); + + if (byte < 0) + break; + + // MSB first + for (int i = 7; i >= 0; i--) { + bool bit = (byte >> i) & 1; + if (bit) count_set_bits++; + original_bits.push_back(bit); + } + } + + int uncompressed_size = original_bits.size(); + + if (verbose > 0) { + fprintf(stderr, "Percentage of set bits: %.2f%%\n", (100.0*count_set_bits) / uncompressed_size); + fprintf(stderr, "Uncompressed size: %8d bits\n", uncompressed_size); + } + + std::vector compressed_bits; + ice_compress(compressed_bits, original_bits); + + int compressed_size = compressed_bits.size(); + + if (verbose > 0) { + fprintf(stderr, "Compressed size: %8d bits\n", compressed_size); + fprintf(stderr, "Space savings: %.2f%%\n", 100 - (100.0*compressed_size) / uncompressed_size); + } + + std::vector uncompressed_bits; + ice_uncompress(uncompressed_bits, compressed_bits); + + bool check_ok = original_bits == uncompressed_bits; + + if (verbose > 0 || !check_ok) { + fprintf(stderr, "Integrity check: %s\n", check_ok ? "OK" : "ERROR"); + if (!check_ok) + return 1; + } + + fprintf(output_file, "ICECOMPR"); + for (int i = 0; i < int(compressed_bits.size()); i += 8) { + int value = 0; + for (int j = 0; j < 8 && i+j < int(compressed_bits.size()); j++) + if (compressed_bits.at(i+j)) + value |= 1 << (7-j); + fputc(value, output_file); + } + + return 0; +} + diff --git a/icecompr/iceuncompr.c b/icecompr/iceuncompr.c new file mode 100644 index 0000000..04e7dc8 --- /dev/null +++ b/icecompr/iceuncompr.c @@ -0,0 +1,162 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. + +#include +#include +#include +#include +#include + +FILE *input_file; +FILE *output_file; + +int read_bitcounter; +int read_buffer; + +int write_bitcounter; +int write_buffer; + +static int read_bit() +{ + if (read_bitcounter == 0) { + read_bitcounter = 8; + read_buffer = fgetc(input_file); + } + + read_bitcounter--; + return (read_buffer >> read_bitcounter) & 1; +} + +static void write_bit(int value) +{ + write_bitcounter--; + + if (value) + write_buffer |= 1 << write_bitcounter; + + if (write_bitcounter == 0) { + fputc(write_buffer, output_file); + write_bitcounter = 8; + write_buffer = 0; + } +} + +static int read_int(int bits) +{ + int ret = 0; + while (bits-- > 0) + if (read_bit()) + ret |= 1 << bits; + return ret; +} + +static void write_zeros(int bits) +{ + while (bits-- > 0) + write_bit(0); +} + +int ice_uncompress() +{ + read_bitcounter = 0; + read_buffer = 0; + + write_bitcounter = 8; + write_buffer = 0; + + int magic1_ok = read_int(32) == 0x49434543; + int magic2_ok = read_int(32) == 0x4f4d5052; + + if (!magic1_ok || !magic2_ok) { + fprintf(stderr, "Missing ICECOMPR magic. Abort!\n"); + return 1; + } + + while (1) + { + if (read_bit()) { + write_zeros(read_int(2)); + write_bit(1); + } else + if (read_bit()) { + write_zeros(read_int(5)); + write_bit(1); + } else + if (read_bit()) { + write_zeros(read_int(8)); + write_bit(1); + } else + if (read_bit()) { + int n = read_int(6); + while (n--) + write_bit(read_bit()); + write_bit(1); + } else + if (read_bit()) { + write_zeros(read_int(23)); + write_bit(1); + } else { + write_zeros(read_int(23)); + break; + } + } + + return 0; +} + +void help() +{ + printf("\n"); + printf("Usage: iceuncompr [input-file [output-file]]\n"); + printf("\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + input_file = stdin; + output_file = stdout; + + int opt; + while ((opt = getopt(argc, argv, "v")) != -1) + { + switch (opt) + { + case 'v': + break; + default: + help(); + } + } + + if (optind < argc) { + input_file = fopen(argv[optind], "rb"); + if (input_file == NULL) { + fprintf(stderr, "Failed to open input file `%s': %s\n", argv[optind], strerror(errno)); + return 1; + } + optind++; + } + + if (optind < argc) { + output_file = fopen(argv[optind], "wb"); + if (output_file == NULL) { + fprintf(stderr, "Failed to open output file `%s': %s\n", argv[optind], strerror(errno)); + return 1; + } + optind++; + } + + if (optind != argc) + help(); + + if (optind != argc) + help(); + + return ice_uncompress(); +} +