xref: /inferno-os/libnandfs/ecc.c (revision 28942ead413418b56c5be78e8c4c400881fba72e)
1*28942eadSforsyth #include "logfsos.h"
237da2899SCharles.Forsyth #include "nandecc.h"
337da2899SCharles.Forsyth 
437da2899SCharles.Forsyth static uchar ecctab[] = {
537da2899SCharles.Forsyth 	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
637da2899SCharles.Forsyth 	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
737da2899SCharles.Forsyth 	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
837da2899SCharles.Forsyth 	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
937da2899SCharles.Forsyth 	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1037da2899SCharles.Forsyth 	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1137da2899SCharles.Forsyth 	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1237da2899SCharles.Forsyth 	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1337da2899SCharles.Forsyth 	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1437da2899SCharles.Forsyth 	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1537da2899SCharles.Forsyth 	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1637da2899SCharles.Forsyth 	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1737da2899SCharles.Forsyth 	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1837da2899SCharles.Forsyth 	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1937da2899SCharles.Forsyth 	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
2037da2899SCharles.Forsyth 	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
2137da2899SCharles.Forsyth };
2237da2899SCharles.Forsyth 
2337da2899SCharles.Forsyth ulong
nandecc(uchar * buf)2437da2899SCharles.Forsyth nandecc(uchar *buf)
2537da2899SCharles.Forsyth {
2637da2899SCharles.Forsyth 	int cp, zeros, ones, im;
2737da2899SCharles.Forsyth 	int lp, om;
2837da2899SCharles.Forsyth 	int i;
2937da2899SCharles.Forsyth 
3037da2899SCharles.Forsyth 	cp = 0xff;
3137da2899SCharles.Forsyth 	zeros = 0xff;
3237da2899SCharles.Forsyth 	ones = 0xff;
3337da2899SCharles.Forsyth 	for (i = 0; i < 256; i++) {
3437da2899SCharles.Forsyth 		int tabent = ecctab[buf[i]];
3537da2899SCharles.Forsyth 		cp ^= tabent;
3637da2899SCharles.Forsyth 		if (tabent & 1) {
3737da2899SCharles.Forsyth 			zeros ^= ~i;
3837da2899SCharles.Forsyth 			ones ^= i;
3937da2899SCharles.Forsyth 		}
4037da2899SCharles.Forsyth 	}
4137da2899SCharles.Forsyth 	lp = 0;
4237da2899SCharles.Forsyth 	for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
4337da2899SCharles.Forsyth 		if (ones & im)
4437da2899SCharles.Forsyth 			lp |= om;
4537da2899SCharles.Forsyth 		om >>= 1;
4637da2899SCharles.Forsyth 		if (zeros & im)
4737da2899SCharles.Forsyth 			lp |= om;
4837da2899SCharles.Forsyth 	}
4937da2899SCharles.Forsyth 	return (((cp & 0xff) | 3) << 16) | lp;
5037da2899SCharles.Forsyth }
5137da2899SCharles.Forsyth 
5237da2899SCharles.Forsyth #define CORRECTABLEMASK 0x545555
5337da2899SCharles.Forsyth 
5437da2899SCharles.Forsyth NandEccError
nandecccorrect(uchar * buf,ulong calcecc,ulong * storedecc,int reportbad)5537da2899SCharles.Forsyth nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
5637da2899SCharles.Forsyth {
5737da2899SCharles.Forsyth 	ulong xorecc;
5837da2899SCharles.Forsyth 	ulong mask;
5937da2899SCharles.Forsyth 	int k;
6037da2899SCharles.Forsyth 
6137da2899SCharles.Forsyth 	if (calcecc == *storedecc)
6237da2899SCharles.Forsyth 		return NandEccErrorGood;
6337da2899SCharles.Forsyth 	if (reportbad)
6437da2899SCharles.Forsyth 		print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc);
6537da2899SCharles.Forsyth 	xorecc = calcecc ^ *storedecc;
6637da2899SCharles.Forsyth 	if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
6737da2899SCharles.Forsyth 		ulong imask;
6837da2899SCharles.Forsyth 		ushort out;
6937da2899SCharles.Forsyth 		ushort omask;
7037da2899SCharles.Forsyth 		int line, col;
7137da2899SCharles.Forsyth 
7237da2899SCharles.Forsyth 		for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) {
7337da2899SCharles.Forsyth 			if (xorecc & imask)
7437da2899SCharles.Forsyth 				out |= omask;
7537da2899SCharles.Forsyth 		}
7637da2899SCharles.Forsyth 		line = out & 0xff;
7737da2899SCharles.Forsyth 		col = out >> 9;
7837da2899SCharles.Forsyth 		if (reportbad)
7937da2899SCharles.Forsyth 			print("nandecccorrect: single bit error line %d col %d\n", line, col);
8037da2899SCharles.Forsyth 		buf[line] ^= (1 << col);
8137da2899SCharles.Forsyth 		*storedecc = calcecc;
8237da2899SCharles.Forsyth 		return NandEccErrorOneBit;
8337da2899SCharles.Forsyth 	}
8437da2899SCharles.Forsyth 	for (mask = 0x800000, k = 0; mask; mask >>= 1)
8537da2899SCharles.Forsyth 		if (mask & xorecc)
8637da2899SCharles.Forsyth 			k++;
8737da2899SCharles.Forsyth 	if (k == 1) {
8837da2899SCharles.Forsyth 		if (reportbad)
8937da2899SCharles.Forsyth 			print("nandecccorrect: single bit error in ecc\n");
9037da2899SCharles.Forsyth 		// assume the stored ecc was wrong
9137da2899SCharles.Forsyth 		*storedecc = calcecc;
9237da2899SCharles.Forsyth 		return NandEccErrorOneBitInEcc;
9337da2899SCharles.Forsyth 	}
9437da2899SCharles.Forsyth 	if (reportbad)
9537da2899SCharles.Forsyth 		print("nandecccorrect: 2 bit error\n");
9637da2899SCharles.Forsyth 	return NandEccErrorBad;
9737da2899SCharles.Forsyth }
9837da2899SCharles.Forsyth 
99