package yaffs2.port;
import yaffs2.utils.*;
public class ECC_C
{
/*
* YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
* Copyright (C) 2002-2007 Aleph One Ltd.
* for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This code implements the ECC algorithm used in SmartMedia.
*
* The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
* The two unused bit are set to 1.
* The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
* blocks are used on a 512-byte NAND page.
*
*/
/* Table generated by gen-ecc.c
* Using a table means we do not have to calculate p1..p4 and p1'..p4'
* for each byte of data. These are instead provided in a table in bits7..2.
* Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
* this bytes influence on the line parity.
*/
static final String yaffs_ecc_c_version =
"$Id: ECC_C.java,v 1.5 2007/09/24 13:30:33 peter.hilber Exp $";
static final byte[] column_parity_table = {
(byte)0x00, (byte)0x55, (byte)0x59, (byte)0x0c, (byte)0x65, (byte)0x30, (byte)0x3c, (byte)0x69,
(byte)0x69, (byte)0x3c, (byte)0x30, (byte)0x65, (byte)0x0c, (byte)0x59, (byte)0x55, (byte)0x00,
(byte)0x95, (byte)0xc0, (byte)0xcc, (byte)0x99, (byte)0xf0, (byte)0xa5, (byte)0xa9, (byte)0xfc,
(byte)0xfc, (byte)0xa9, (byte)0xa5, (byte)0xf0, (byte)0x99, (byte)0xcc, (byte)0xc0, (byte)0x95,
(byte)0x99, (byte)0xcc, (byte)0xc0, (byte)0x95, (byte)0xfc, (byte)0xa9, (byte)0xa5, (byte)0xf0,
(byte)0xf0, (byte)0xa5, (byte)0xa9, (byte)0xfc, (byte)0x95, (byte)0xc0, (byte)0xcc, (byte)0x99,
(byte)0x0c, (byte)0x59, (byte)0x55, (byte)0x00, (byte)0x69, (byte)0x3c, (byte)0x30, (byte)0x65,
(byte)0x65, (byte)0x30, (byte)0x3c, (byte)0x69, (byte)0x00, (byte)0x55, (byte)0x59, (byte)0x0c,
(byte)0xa5, (byte)0xf0, (byte)0xfc, (byte)0xa9, (byte)0xc0, (byte)0x95, (byte)0x99, (byte)0xcc,
(byte)0xcc, (byte)0x99, (byte)0x95, (byte)0xc0, (byte)0xa9, (byte)0xfc, (byte)0xf0, (byte)0xa5,
(byte)0x30, (byte)0x65, (byte)0x69, (byte)0x3c, (byte)0x55, (byte)0x00, (byte)0x0c, (byte)0x59,
(byte)0x59, (byte)0x0c, (byte)0x00, (byte)0x55, (byte)0x3c, (byte)0x69, (byte)0x65, (byte)0x30,
(byte)0x3c, (byte)0x69, (byte)0x65, (byte)0x30, (byte)0x59, (byte)0x0c, (byte)0x00, (byte)0x55,
(byte)0x55, (byte)0x00, (byte)0x0c, (byte)0x59, (byte)0x30, (byte)0x65, (byte)0x69, (byte)0x3c,
(byte)0xa9, (byte)0xfc, (byte)0xf0, (byte)0xa5, (byte)0xcc, (byte)0x99, (byte)0x95, (byte)0xc0,
(byte)0xc0, (byte)0x95, (byte)0x99, (byte)0xcc, (byte)0xa5, (byte)0xf0, (byte)0xfc, (byte)0xa9,
(byte)0xa9, (byte)0xfc, (byte)0xf0, (byte)0xa5, (byte)0xcc, (byte)0x99, (byte)0x95, (byte)0xc0,
(byte)0xc0, (byte)0x95, (byte)0x99, (byte)0xcc, (byte)0xa5, (byte)0xf0, (byte)0xfc, (byte)0xa9,
(byte)0x3c, (byte)0x69, (byte)0x65, (byte)0x30, (byte)0x59, (byte)0x0c, (byte)0x00, (byte)0x55,
(byte)0x55, (byte)0x00, (byte)0x0c, (byte)0x59, (byte)0x30, (byte)0x65, (byte)0x69, (byte)0x3c,
(byte)0x30, (byte)0x65, (byte)0x69, (byte)0x3c, (byte)0x55, (byte)0x00, (byte)0x0c, (byte)0x59,
(byte)0x59, (byte)0x0c, (byte)0x00, (byte)0x55, (byte)0x3c, (byte)0x69, (byte)0x65, (byte)0x30,
(byte)0xa5, (byte)0xf0, (byte)0xfc, (byte)0xa9, (byte)0xc0, (byte)0x95, (byte)0x99, (byte)0xcc,
(byte)0xcc, (byte)0x99, (byte)0x95, (byte)0xc0, (byte)0xa9, (byte)0xfc, (byte)0xf0, (byte)0xa5,
(byte)0x0c, (byte)0x59, (byte)0x55, (byte)0x00, (byte)0x69, (byte)0x3c, (byte)0x30, (byte)0x65,
(byte)0x65, (byte)0x30, (byte)0x3c, (byte)0x69, (byte)0x00, (byte)0x55, (byte)0x59, (byte)0x0c,
(byte)0x99, (byte)0xcc, (byte)0xc0, (byte)0x95, (byte)0xfc, (byte)0xa9, (byte)0xa5, (byte)0xf0,
(byte)0xf0, (byte)0xa5, (byte)0xa9, (byte)0xfc, (byte)0x95, (byte)0xc0, (byte)0xcc, (byte)0x99,
(byte)0x95, (byte)0xc0, (byte)0xcc, (byte)0x99, (byte)0xf0, (byte)0xa5, (byte)0xa9, (byte)0xfc,
(byte)0xfc, (byte)0xa9, (byte)0xa5, (byte)0xf0, (byte)0x99, (byte)0xcc, (byte)0xc0, (byte)0x95,
(byte)0x00, (byte)0x55, (byte)0x59, (byte)0x0c, (byte)0x65, (byte)0x30, (byte)0x3c, (byte)0x69,
(byte)0x69, (byte)0x3c, (byte)0x30, (byte)0x65, (byte)0x0c, (byte)0x59, (byte)0x55, (byte)0x00
};
/* Count the bits in an unsigned char or a U32 */
static int yaffs_CountBits(byte x)
{
int r = 0;
while (x != 0) {
if ((x & 1) != 0)
r++;
x = (byte)((x & 0xff) >>> 1);
}
return r;
}
static int yaffs_CountBits32(int x)
{
int r = 0;
while (x != 0) {
if ((x & 1) != 0)
r++;
x >>>= 1;
}
return r;
}
/* Calculate the ECC for a 256-byte block of data */
public static void yaffs_ECCCalculate(byte[] data, int dataIndex,
byte[] ecc, int eccIndex)
{
int i;
int col_parity = 0;
int line_parity = 0;
int line_parity_prime = 0;
int t;
int b;
for (i = 0; i < 256; i++) {
b = column_parity_table[Utils.byteAsUnsignedByte(data[dataIndex+i])];
col_parity ^= b;
if ((b & 0x01) != 0) // odd number of bits in the byte
{
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
ecc[eccIndex+2] = (byte)((~col_parity) | 0x03);
t = 0;
if ((line_parity & 0x80) != 0)
t |= 0x80;
if ((line_parity_prime & 0x80) != 0)
t |= 0x40;
if ((line_parity & 0x40) != 0)
t |= 0x20;
if ((line_parity_prime & 0x40) != 0)
t |= 0x10;
if ((line_parity & 0x20) != 0)
t |= 0x08;
if ((line_parity_prime & 0x20) != 0)
t |= 0x04;
if ((line_parity & 0x10) != 0)
t |= 0x02;
if ((line_parity_prime & 0x10) != 0)
t |= 0x01;
ecc[eccIndex+1] = (byte)~t;
t = 0;
if ((line_parity & 0x08) != 0)
t |= 0x80;
if ((line_parity_prime & 0x08) != 0)
t |= 0x40;
if ((line_parity & 0x04) != 0)
t |= 0x20;
if ((line_parity_prime & 0x04) != 0)
t |= 0x10;
if ((line_parity & 0x02) != 0)
t |= 0x08;
if ((line_parity_prime & 0x02) != 0)
t |= 0x04;
if ((line_parity & 0x01) != 0)
t |= 0x02;
if ((line_parity_prime & 0x01) != 0)
t |= 0x01;
ecc[eccIndex+0] = (byte)~t;
/*#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// Swap the bytes into the wrong order
t = ecc[0];
ecc[0] = ecc[1];
ecc[1] = t;
#endif*/
}
/* Correct the ECC on a 256 byte block of data */
public static int yaffs_ECCCorrect(byte[] data, int dataIndex,
byte[] read_ecc, int read_eccIndex,
byte[] test_ecc, int test_eccIndex)
{
int d0, d1, d2; /* deltas */
d0 = (read_ecc[read_eccIndex+0] ^ test_ecc[test_eccIndex+0]);
d1 = (read_ecc[read_eccIndex+1] ^ test_ecc[test_eccIndex+1]);
d2 = (read_ecc[read_eccIndex+2] ^ test_ecc[test_eccIndex+2]);
if ((d0 | d1 | d2) == 0)
return 0; /* no error */
if (((d0 ^ (d0 >>> 1)) & 0x55) == 0x55 &&
((d1 ^ (d1 >>> 1)) & 0x55) == 0x55 &&
((d2 ^ (d2 >>> 1)) & 0x54) == 0x54) {
/* Single bit (recoverable) error in data */
int _byte;
int bit;
/*#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
// swap the bytes to correct for the wrong order
unsigned char t;
t = d0;
d0 = d1;
d1 = t;
#endif*/
bit = _byte = 0;
if ((d1 & 0x80) != 0)
_byte |= 0x80;
if ((d1 & 0x20) != 0)
_byte |= 0x40;
if ((d1 & 0x08) != 0)
_byte |= 0x20;
if ((d1 & 0x02) != 0)
_byte |= 0x10;
if ((d0 & 0x80) != 0)
_byte |= 0x08;
if ((d0 & 0x20) != 0)
_byte |= 0x04;
if ((d0 & 0x08) != 0)
_byte |= 0x02;
if ((d0 & 0x02) != 0)
_byte |= 0x01;
if ((d2 & 0x80) != 0)
bit |= 0x04;
if ((d2 & 0x20) != 0)
bit |= 0x02;
if ((d2 & 0x08) != 0)
bit |= 0x01;
/*data[_byte] ^= (1 << bit);*/ data[dataIndex + _byte] ^= (1 << bit);
return 1; /* Corrected the error */
}
if ((yaffs_CountBits((byte)d0) +
yaffs_CountBits((byte)d1) +
yaffs_CountBits((byte)d2)) == 1) {
/* Reccoverable error in ecc */
read_ecc[read_eccIndex+0] = test_ecc[test_eccIndex+0];
read_ecc[read_eccIndex+1] = test_ecc[test_eccIndex+1];
read_ecc[read_eccIndex+2] = test_ecc[test_eccIndex+2];
return 1; /* Corrected the error */
}
/* Unrecoverable error */
return -1;
}
/*
* ECCxxxOther does ECC calcs on arbitrary n bytes of data
*/
public static void yaffs_ECCCalculateOther(SerializableObject data/*, int nBytes*/ ,
yaffs_ECCOther eccOther)
{
int nBytes = data.getSerializedLength(); // PORT
int i;
int col_parity = 0;
int line_parity = 0;
int line_parity_prime = 0;
int b;
for (i = 0; i < nBytes; i++) {
b = column_parity_table[Utils.byteAsUnsignedByte(data.serialized[data.offset+i])];
col_parity ^= b;
if ((b & 0x01) != 0) {
/* odd number of bits in the byte */
line_parity ^= i;
line_parity_prime ^= ~i;
}
}
eccOther.setcolParity((byte)((col_parity >>> 2) & 0x3f));
eccOther.setlineParity(line_parity);
eccOther.setlineParityPrime(line_parity_prime);
}
public static int yaffs_ECCCorrectOther(SerializableObject data/*, int nBytes*/ ,
yaffs_ECCOther read_ecc,
yaffs_ECCOther test_ecc)
{
int nBytes = data.getSerializedLength();
int cDelta; /* column parity delta */
int lDelta; /* line parity delta */
int lDeltaPrime; /* line parity delta */
int bit;
cDelta = read_ecc.colParity() ^ test_ecc.colParity();
lDelta = read_ecc.lineParity() ^ test_ecc.lineParity();
lDeltaPrime = read_ecc.lineParityPrime() ^ test_ecc.lineParityPrime();
if ((cDelta | lDelta | lDeltaPrime) == 0)
return 0; /* no error */
if (lDelta == ~lDeltaPrime &&
(((cDelta ^ (cDelta >>> 1)) & 0x15) == 0x15))
{
/* Single bit (recoverable) error in data */
bit = 0;
if ((cDelta & 0x20) != 0)
bit |= 0x04;
if ((cDelta & 0x08) != 0)
bit |= 0x02;
if ((cDelta & 0x02) != 0)
bit |= 0x01;
if(lDelta >= nBytes)
return -1;
data.serialized[data.offset+(int)lDelta] ^= (1 << bit);
return 1; /* corrected */
}
if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
yaffs_CountBits((byte)cDelta)) == 1) {
/* Reccoverable error in ecc */
read_ecc = test_ecc;
return 1; /* corrected */
}
/* Unrecoverable error */
return -1;
}
}