ecc8.c 2.12 KB
#include "ecc256.h"

void
ecc8_calculate(const unsigned char buf[8], unsigned char ecc[2]) {
    int i;
    unsigned char x1, x2, a0, a1, b, e0, e1;
    e1 = x1 = x2 = 0;
    for(i = 0; i < 8; i++) {
	unsigned char z = buf[i], cp0, cp1, cp2, cp3, cp4, cp5;
	cp0 = (z&1) ^ ((z>>2)&1) ^ ((z>>4)&1) ^ ((z>>6)&1);      /* xx0 */
	cp1 = ((z>>1)&1) ^ ((z>>3)&1) ^ ((z>>5)&1) ^ ((z>>7)&1); /* xx1 */
	cp2 = (z&1) ^ ((z>>1)&1) ^ ((z>>4)&1) ^ ((z>>5)&1);      /* x0x */
	cp3 = ((z>>2)&1) ^ ((z>>3)&1) ^ ((z>>6)&1) ^ ((z>>7)&1); /* x1x */
	cp4 = (z&1) ^ ((z>>1)&1) ^ ((z>>2)&1) ^ ((z>>3)&1);      /* 0xx */
	cp5 = ((z>>4)&1) ^ ((z>>5)&1) ^ ((z>>6)&1) ^ ((z>>7)&1); /* 1xx */
	e1 ^= cp0|(cp1<<1)|(cp2<<2)|(cp3<<3)|(cp4<<4)|(cp5<<6);	/* column parity */
	if (cp4^cp5) { /* odd byte parity */
	    x1 ^= ~i;
	    x2 ^= i;
	}
    }

    a1 = b = 0x80; a0 = 0x8;
    e0 = 0;
    for(i = 0; i < 4; i++) { /* compute ecc[0] */
	if (x2 & a0) e0 |= b; /* line parity 7, 5, 3, 1 */
	b >>= 1;
	if (x1 & a0) e0 |= b; /* line parity 6, 4, 2, 0 */
	a0 >>= 1; a1 >>= 1; b >>= 1;
    }

    ecc[0] = ~e0;		/* lp7..lp0 */
    ecc[1] = ~(e1 << 2);	/* cp5..cp0 0 0 */
}

int
ecc8_correct(unsigned char buf[8], unsigned char read_ecc[2], const unsigned char calc_ecc[2]) {
    unsigned char a, b, c, d, x0, x1;
	
    x0 = calc_ecc[0] ^ read_ecc[0];
    x1 = calc_ecc[1] ^ read_ecc[1];
	
    if ((x0 | x1) == 0)	/* No errors */
	return ECC_ERROR_NONE;

    a = (x0 ^ (x0 >> 1)) & 0x55;
    b = (x1 ^ (x1 >> 1)) & 0x54;
		
    /* Check for and correct single bit error in the data */
    if (a == 0x55 && b == 0x54) {
	unsigned char i, address = 0, bit = 0;
	a = c = 0x8; d = 0x4;
	for (i = 0; i < 4; i++) { /* compute bit address */
	    if (x0 & c) address |= a;
	    if (x1 & c) bit |= d;
	    a >>= 1; d >>= 1;
	    c >>= 2;
	}
	buf[address] ^= 1 << bit;
	return ECC_ERROR_CORRECTED;
    } else {
	/* count bits */
	c = 0;
	while (x0 | x1) {
	    c += x0 & 1;
	    c += x1 & 1;
	    x0 >>= 1;
	    x1 >>= 1;
	}
	if (c == 1) { read_ecc[0] = calc_ecc[0]; read_ecc[1] = calc_ecc[1]; }
	/* Error in the ECC code : Uncorrectable error */
	return (c == 1) ? ECC_ERROR_ECC : ECC_ERROR_UNCORRECTABLE;
    }
}