You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
197 lines
4.6 KiB
197 lines
4.6 KiB
3 months ago
|
/*
|
||
|
* CRC32 (Castagnoli 1993)
|
||
|
*
|
||
|
* Based on Michael E. Kounavis and Frank L. Berry: A Systematic Approach
|
||
|
* to Building High Performance Software-based CRC Generators
|
||
|
* (Proceedings of the 10th IEEE Symposium on Computers and Communications 2005)
|
||
|
*
|
||
|
* Includes code from http://sourceforge.net/projects/slicing-by-8/,
|
||
|
* which carried the following copyright notice:
|
||
|
*
|
||
|
* Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved
|
||
|
*
|
||
|
* This software program is licensed subject to the BSD License,
|
||
|
* available at http://www.opensource.org/licenses/bsd-license.html
|
||
|
*
|
||
|
* Adapted for LibUCW by Martin Mares <mj@ucw.cz> in 2012.
|
||
|
*/
|
||
|
|
||
|
#include <ucw/lib.h>
|
||
|
#include <ucw/crc.h>
|
||
|
#include <ucw/crc-tables.h>
|
||
|
|
||
|
static void crc32_update_by1(crc32_context *ctx, const byte *buf, uint len)
|
||
|
{
|
||
|
u32 crc = ctx->state;
|
||
|
while (len--)
|
||
|
crc = crc_tableil8_o32[(crc ^ *buf++) & 0x000000FF] ^ (crc >> 8);
|
||
|
ctx->state = crc;
|
||
|
}
|
||
|
|
||
|
static void crc32_update_by4(crc32_context *ctx, const byte *buf, uint len)
|
||
|
{
|
||
|
uint init_bytes, words;
|
||
|
u32 crc = ctx->state;
|
||
|
u32 term1, term2;
|
||
|
const u32 *buf32;
|
||
|
|
||
|
// Special case
|
||
|
if (len < 4)
|
||
|
goto small;
|
||
|
|
||
|
// Align start address to a multiple of 4 bytes
|
||
|
init_bytes = ((uintptr_t) buf) & 3;
|
||
|
if (init_bytes)
|
||
|
{
|
||
|
init_bytes = 4 - init_bytes;
|
||
|
len -= init_bytes;
|
||
|
while (init_bytes--)
|
||
|
crc = crc_tableil8_o32[(crc ^ *buf++) & 0x000000FF] ^ (crc >> 8);
|
||
|
}
|
||
|
|
||
|
// Process 4 bytes at a time
|
||
|
words = len/4;
|
||
|
len -= 4*words;
|
||
|
buf32 = (const u32 *) buf;
|
||
|
while (words--)
|
||
|
{
|
||
|
crc ^= *buf32++;
|
||
|
term1 = crc_tableil8_o56[crc & 0x000000FF] ^ crc_tableil8_o48[(crc >> 8) & 0x000000FF];
|
||
|
term2 = crc >> 16;
|
||
|
crc = term1 ^
|
||
|
crc_tableil8_o40[term2 & 0x000000FF] ^
|
||
|
crc_tableil8_o32[(term2 >> 8) & 0x000000FF];
|
||
|
}
|
||
|
|
||
|
// Process remaining up to 7 bytes
|
||
|
buf = (const byte *) buf32;
|
||
|
small:
|
||
|
while (len--)
|
||
|
crc = crc_tableil8_o32[(crc ^ *buf++) & 0x000000FF] ^ (crc >> 8);
|
||
|
|
||
|
ctx->state = crc;
|
||
|
}
|
||
|
|
||
|
static void crc32_update_by8(crc32_context *ctx, const byte *buf, uint len)
|
||
|
{
|
||
|
uint init_bytes, quads;
|
||
|
u32 crc = ctx->state;
|
||
|
u32 term1, term2;
|
||
|
const u32 *buf32;
|
||
|
|
||
|
// Special case
|
||
|
if (len < 8)
|
||
|
goto small;
|
||
|
|
||
|
// Align start address to a multiple of 8 bytes
|
||
|
init_bytes = ((uintptr_t) buf) & 7;
|
||
|
if (init_bytes)
|
||
|
{
|
||
|
init_bytes = 8 - init_bytes;
|
||
|
len -= init_bytes;
|
||
|
while (init_bytes--)
|
||
|
crc = crc_tableil8_o32[(crc ^ *buf++) & 0x000000FF] ^ (crc >> 8);
|
||
|
}
|
||
|
|
||
|
// Process 8 bytes at a time
|
||
|
quads = len/8;
|
||
|
len -= 8*quads;
|
||
|
buf32 = (const u32 *) buf;
|
||
|
while (quads--)
|
||
|
{
|
||
|
crc ^= *buf32++;
|
||
|
term1 = crc_tableil8_o88[crc & 0x000000FF] ^
|
||
|
crc_tableil8_o80[(crc >> 8) & 0x000000FF];
|
||
|
term2 = crc >> 16;
|
||
|
crc = term1 ^
|
||
|
crc_tableil8_o72[term2 & 0x000000FF] ^
|
||
|
crc_tableil8_o64[(term2 >> 8) & 0x000000FF];
|
||
|
term1 = crc_tableil8_o56[*buf32 & 0x000000FF] ^
|
||
|
crc_tableil8_o48[(*buf32 >> 8) & 0x000000FF];
|
||
|
|
||
|
term2 = *buf32 >> 16;
|
||
|
crc = crc ^
|
||
|
term1 ^
|
||
|
crc_tableil8_o40[term2 & 0x000000FF] ^
|
||
|
crc_tableil8_o32[(term2 >> 8) & 0x000000FF];
|
||
|
buf32++;
|
||
|
}
|
||
|
|
||
|
// Process remaining up to 7 bytes
|
||
|
buf = (const byte *) buf32;
|
||
|
small:
|
||
|
while (len--)
|
||
|
crc = crc_tableil8_o32[(crc ^ *buf++) & 0x000000FF] ^ (crc >> 8);
|
||
|
|
||
|
ctx->state = crc;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
crc32_init(crc32_context *ctx, uint crc_mode)
|
||
|
{
|
||
|
ctx->state = 0xffffffff;
|
||
|
switch (crc_mode)
|
||
|
{
|
||
|
case CRC_MODE_DEFAULT:
|
||
|
ctx->update_func = crc32_update_by4;
|
||
|
break;
|
||
|
case CRC_MODE_SMALL:
|
||
|
ctx->update_func = crc32_update_by1;
|
||
|
break;
|
||
|
case CRC_MODE_BIG:
|
||
|
ctx->update_func = crc32_update_by8;
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
u32
|
||
|
crc32_hash_buffer(const byte *buf, uint len)
|
||
|
{
|
||
|
crc32_context ctx;
|
||
|
crc32_init(&ctx, CRC_MODE_DEFAULT);
|
||
|
crc32_update(&ctx, buf, len);
|
||
|
return crc32_final(&ctx);
|
||
|
}
|
||
|
|
||
|
#ifdef TEST
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
if (argc != 5)
|
||
|
die("Usage: crc-t <alg> <len> <block> <iters>");
|
||
|
uint alg = atoi(argv[1]);
|
||
|
uint len = atoi(argv[2]);
|
||
|
uint block = atoi(argv[3]);
|
||
|
uint iters = atoi(argv[4]);
|
||
|
|
||
|
byte *buf = xmalloc(len);
|
||
|
for (uint i=0; i<len; i++)
|
||
|
buf[i] = i ^ (i >> 5) ^ (i >> 11);
|
||
|
|
||
|
for (uint i=0; i<iters; i++)
|
||
|
{
|
||
|
crc32_context ctx;
|
||
|
uint modes[] = { CRC_MODE_DEFAULT, CRC_MODE_SMALL, CRC_MODE_BIG };
|
||
|
ASSERT(alg < ARRAY_SIZE(modes));
|
||
|
crc32_init(&ctx, modes[alg]);
|
||
|
for (uint p=0; p<len;)
|
||
|
{
|
||
|
uint l = MIN(len-p, block);
|
||
|
crc32_update(&ctx, buf+p, l);
|
||
|
p += l;
|
||
|
}
|
||
|
uint crc = crc32_final(&ctx);
|
||
|
if (!i)
|
||
|
printf("%08x\n", crc);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#endif
|