plan9fox/sys/src/9/port/ecc.c
2011-03-30 19:35:09 +03:00

120 lines
3.3 KiB
C

/* error correcting code for nand flash */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "nandecc.h"
#define CORRECTABLEMASK 0x545555
static uchar ecctab[] = {
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
};
ulong
nandecc(uchar *buf)
{
int cp, zeros, ones, im, lp, om, i;
cp = 0xff;
zeros = 0xff;
ones = 0xff;
for (i = 0; i < 256; i++) {
int tabent = ecctab[buf[i]];
cp ^= tabent;
if (tabent & 1) {
zeros ^= ~i;
ones ^= i;
}
}
lp = 0;
for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
if (ones & im)
lp |= om;
om >>= 1;
if (zeros & im)
lp |= om;
}
return (((cp & 0xff) | 3) << 16) | lp;
}
NandEccError
nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
{
ulong xorecc, mask;
int k;
if (calcecc == *storedecc)
return NandEccErrorGood;
if (reportbad)
print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n",
calcecc, *storedecc);
xorecc = calcecc ^ *storedecc;
if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
ulong imask;
ushort out, omask;
int line, col;
for (imask = 0x800000, omask = 0x800, out = 0; imask;
imask >>= 2, omask >>= 1)
if (xorecc & imask)
out |= omask;
line = out & 0xff;
col = out >> 9;
if (reportbad)
print("nandecccorrect: single bit error line %d col %d\n",
line, col);
buf[line] ^= (1 << col);
*storedecc = calcecc;
return NandEccErrorOneBit;
}
for (mask = 0x800000, k = 0; mask; mask >>= 1)
if (mask & xorecc)
k++;
if (k == 1) {
if (reportbad)
print("nandecccorrect: single bit error in ecc\n");
/* assume the stored ecc was wrong */
*storedecc = calcecc;
return NandEccErrorOneBitInEcc;
}
if (reportbad)
print("nandecccorrect: 2 bit error\n");
return NandEccErrorBad;
}