horusdemodlib/src/golay23.c

312 wiersze
7.6 KiB
C

/*---------------------------------------------------------------------------*\
FILE........: golay23.c
AUTHOR......: Tomas Härdin & David Rowe
DATE CREATED: 3 March 2013
To test:
src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_UNITTEST && ./golay23
src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_UNITTEST -DRUN_TIME_TABLES && ./golay23
src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_UNITTEST -DNO_TABLES && ./golay23
To generate tables:
src$ gcc golay23.c -o golay23 -Wall -O3 -DGOLAY23_MAKETABLES && ./golay23
\*---------------------------------------------------------------------------*/
/*
Copyright (C) 2016 Tomas Härdin & David Rowe
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 2.1, as
published by the Free Software Foundation. This program is
distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not,see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#ifdef GOLAY23_MAKETABLES
#define RUN_TIME_TABLES
#endif
#ifndef NO_TABLES
#ifdef RUN_TIME_TABLES
int static encoding_table[4096];
int static decoding_table[2048];
static int inited = 0;
#else
//default is to use precomputed tables
#include "golayenctable.h"
#include "golaydectable.h"
#endif
#endif
//since we want to avoid bit-reversing inside syndrome() we bit-reverse the polynomial instead
#define GOLAY_POLYNOMIAL 0xC75 //AE3 reversed
int golay23_syndrome(int c) {
//could probably be done slightly smarter, but works
int x;
for (x = 11; x >= 0; x--) {
if (c & ((1<<11) << x)) {
c ^= GOLAY_POLYNOMIAL << x;
}
}
return c;
}
#ifdef __GNUC__
#define popcount __builtin_popcount
#elif defined(__MSC_VER)
#include <intrin.h>
#define popcount __popcnt
#else
static int popcount(unsigned int c) {
int ret = 0;
while (c) {
if (c & 1) {
ret++;
}
c >>= 1;
}
return ret;
}
#endif
#if defined(NO_TABLES) || defined(RUN_TIME_TABLES)
static int golay23_encode_no_tables(int c) {
c <<= 11;
return golay23_syndrome(c) | c;
}
#endif
#ifdef NO_TABLES
static int unrotate(unsigned int c, int x) {
return ((c << x) & 0x7FFFFF) | (c >> (23 - x));
}
static int golay23_decode_no_tables(int c) {
//TODO: optimize?
int x;
c = unrotate(c, 12);
for (x = 0; x < 23; x++) {
int t;
int s = golay23_syndrome(c);
if (popcount(s) <= 3) {
return unrotate(c ^ s, x) & 0xFFF;
}
for (t = 0; t < 23; t++) {
int c2 = c ^ (1 << t);
int s = golay23_syndrome(c2);
if (popcount(s) <= 2) {
return unrotate(c2 ^ s, x) & 0xFFF;
}
}
//rotate
c = (c >> 1) | ((c & 1) << 22);
}
//shouldn't reach here..
assert("Something is wrong with golay23_decode_no_tables()..");
return c & 0xFFF;
}
#endif
void golay23_init(void) {
#ifdef RUN_TIME_TABLES
int x, y, z;
inited = 1;
for (x = 0; x < 4096; x++) {
encoding_table[x] = golay23_encode_no_tables(x);
}
decoding_table[0] = 0;
//1-bit errors
for (x = 0; x < 23; x++) {
int d = 1<<x;
decoding_table[golay23_syndrome(d)] = d;
}
//2-bit errors
for (x = 0; x < 22; x++) {
for (y = x+1; y < 23; y++) {
int d = (1<<x) | (1<<y);
decoding_table[golay23_syndrome(d)] = d;
}
}
//3-bit errors
for (x = 0; x < 21; x++) {
for (y = x+1; y < 22; y++) {
for (z = y+1; z < 23; z++) {
int d = (1<<x) | (1<<y) | (1<<z);
decoding_table[golay23_syndrome(d)] = d;
}
}
}
#endif
}
int golay23_encode(int c) {
assert(c >= 0 && c <= 0xFFF);
#ifdef RUN_TIME_TABLES
assert(inited);
#endif
#ifdef NO_TABLES
return golay23_encode_no_tables(c);
#else
return encoding_table[c];
#endif
}
int golay23_decode(int c) {
assert(c >= 0 && c <= 0x7FFFFF);
#ifdef RUN_TIME_TABLES
assert(inited);
#endif
#ifdef NO_TABLES
//duplicate old golay23_decode()'s shift
return unrotate(golay23_decode_no_tables(c), 11);
#else
//message is shifted 11 places left in the return value
return c ^ decoding_table[golay23_syndrome(c)];
#endif
}
int golay23_count_errors(int recd_codeword, int corrected_codeword) {
return popcount(recd_codeword ^ corrected_codeword);
}
/**
* Table generation and testing code below
*/
#ifdef GOLAY23_MAKETABLES
#include <stdio.h>
int main() {
int x;
//generate and dump
golay23_init();
FILE *enc = fopen("golayenctable.h", "w");
FILE *dec = fopen("golaydectable.h", "w");
fprintf(enc, "/* Generated by golay23.c -DGOLAY23_MAKETABLE */\n\
\n\
const int static encoding_table[]={\n");
for (x = 0; x < 4096; x++) {
fprintf(enc, x < 4095 ? " 0x%x,\n" : " 0x%x\n", encoding_table[x]);
}
fprintf(enc, "};\n");
fprintf(dec, "/* Generated by golay23.c -DGOLAY23_MAKETABLE */\n\
\n\
const int static decoding_table[]={\n");
for (x = 0; x < 2048; x++) {
fprintf(dec, x < 2047 ? " 0x%x,\n" : " 0x%x\n", decoding_table[x]);
}
fprintf(dec, "};\n");
fclose(enc);
fclose(dec);
return 0;
}
#elif defined(GOLAY23_UNITTEST)
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int main() {
int c;
golay23_init();
//keep track of whether every single codeword has been checked
char *checkmask = malloc(1<<23);
memset(checkmask, 0, 1<<23);
//step through all possible messages
for (c = 0; c < (1<<12); c++) {
int g23 = golay23_encode(c);
int x,y,z;
checkmask[g23] = 1;
int c2 = golay23_decode(g23) >> 11;
printf("%03x -> %06x %03x\n", c, g23, c2);
if (c != c2) {
printf("Bad!\n");
exit(1);
}
//test the code by flipping every combination of one, two and three bits
for (x = 0; x < 23; x++) {
int flipped = g23 ^ (1<<x);
checkmask[flipped] = 1;
int c2 = golay23_decode(flipped) >> 11;
if (c != c2) {
printf("Bad!\n");
exit(1);
}
}
for (x = 0; x < 22; x++) {
for (y = x+1; y < 23; y++) {
int flipped = g23 ^ (1<<x) ^ (1<<y);
checkmask[flipped] = 1;
int c2 = golay23_decode(flipped) >> 11;
if (c != c2) {
printf("Bad!\n");
exit(1);
}
}
}
for (x = 0; x < 21; x++) {
for (y = x+1; y < 22; y++) {
for (z = y+1; z < 23; z++) {
int flipped = g23 ^ (1<<x) ^ (1<<y) ^ (1<<z);
checkmask[flipped] = 1;
int c2 = golay23_decode(flipped) >> 11;
if (c != c2) {
printf("Bad!\n");
exit(1);
}
}
}
}
}
//did we check every codeword?
for (c = 0; c < (1<<23); c++) {
if (checkmask[c] != 1) {
printf("%06x unchecked!\n", c);
exit(1);
}
}
printf("Everything checks out\n");
free(checkmask);
return 0;
}
#endif