分类:
2009-01-28 11:40:59
ECC的代码实现
数据校验介绍:
通俗的说,就是为保证数据的完整性,用一种指定的算法对原始数据计算出的一个校验值。接收方用同样的算法计算一次校验值,如果和随数据提供的校验值一样,就说明数据是完整的。
如果是时序或者电路方面有什么问题的话,错误数据的发生是无法通过数据校验来进行弥补的,而对于受外界干扰而产生的位翻转错误,则可以一定程度上通过HW或者SW的数据校验来进行数据的检测和纠正。
常用的数据校验算法有CRC校验和ECC校验等,它们的基本原理很相似。
ECC介绍:
ECC(错误检查和纠正),这种技术也是在原来的数据位上外加校验位来实现的,具体的原理不再描述,大致的描述可以参照:http://blog.csdn.net/nhczp/archive/2007/07/20/1700031.aspx.
它有一个规律:数据位每增加一倍,ECC只增加一位检验位,也就是说当数据位为16位时ECC位为6位,32位时ECC位为7位,数据位为64位时ECC位为8位,依此类推,数据位每增加一倍,ECC位只增加一位。
附件说明:
附件1:256字节ECC校正1比特错误代码实现
附件2:512字节ECC校正1比特错误代码实现
/*************************************************************************************************************/
附件1:256字节ECC校正1比特错误代码实现
// 256ByteECC071123.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
//071126
unsigned char dat[]={
0x0 ,0x0 ,0x0 ,0x0 ,0x0 ,0x0 ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0
};
//071123
unsigned char ECCTable[]={
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0
};
//计算ECC代码
void NandTranResult(unsigned char reg2,unsigned char reg3,unsigned char *ECCCode)
{
unsigned char temp1,temp2,i,a,b;
temp1=temp2=0;
a=b=0x80;
for(i=0;i<4;i++)
{
if(reg3&a)
temp1|=b;
b>>=1;
if(reg2&a)
temp1|=b;
b>>=1;
a>>=1;
}
b=0x80;
for(i=0;i<4;i++)
{
if(reg3&a)
temp2|=b;
b>>=1;
if(reg2&a)
temp2|=b;
b>>=1;
a>>=1;
}
//将最终的ECC存入数组ECCCode
ECCCode[0]=temp1;//存放高8bit
ECCCode[1]=temp2;//存放中间的8bit
}
void NandCalECC(const unsigned char *dat,unsigned char *ECCCode)
{
unsigned char reg1,reg2,reg3,temp;
int j;
reg1=reg2=reg3=0;
for(j=0;j<256;j++)
{
temp=ECCTable[dat[j]];
reg1^=(temp&0x3f);
if(temp&0x40)
{
reg3^=(unsigned char)j;
reg2^=(~((unsigned char)j));
}
}
NandTranResult(reg2,reg3,ECCCode);
//计算最终的ECC码
//此处为什么要做一个求非的操作呢?
//不取非也行,对结果没有影响
ECCCode[0]=~ECCCode[0];
ECCCode[1]=~ECCCode[1];
ECCCode[2]=(((~reg1)<<2)|0x03);
}
/*
* 参数解释
* dat[]:实际读取的数据
* ReadECC[]:保存数据时根据原始数据产生的ECC码
* CalECC[]:读取数据的同时产生的ECC码
*/
int NandCorrectData(unsigned char *dat,unsigned char *ReadECC,unsigned char *CalECC)
{
unsigned char a,b,c,bit,add,i,d1,d2,d3;
//计算
d1=ReadECC[0]^CalECC[0];
d2=ReadECC[1]^CalECC[1];
d3=ReadECC[2]^CalECC[2];
//printf("d1=0x%0x,d2=0x%0x,d3=0x%0x\n",d1,d2,d3);
if((d1|d2|d3) == 0)
{
//无错误发生
printf("无错误发生\n");
return 0;
}
else
{
a=((d1>>1)^d1)&0x55;
b=((d2>>1)^d2)&0x55;
c=((d3>>1)^d3)&0x54;
//此处的理论依据是:如果发生了1bit的ECC错误,那么ECC异或地结果是--每个配对的bit数据相反,即为0&1或者1&0
if((a == 0x55)&(b == 0x55)&(c == 0x54))
{
//可校正的1bit ECC错误
//首先计算错误的Byte
a=b=c=0x80;
add=0;
for(i=0;i<4;i++)
{
if(d1&a)
add|=b;
a>>=2;
b>>=1;
}
for(i=0;i<4;i++)
{
if(d2&c)
add|=b;
c>>=2;
b>>=1;
}
//计算发生错误的Bit
bit=0;
a=0x80;
b=0x04;
// printf("d3 = 0x%0x\n",d3);
for(i=0;i<3;i++)
{
if(d3&a)
{
bit|=b;
// printf("Detected!\n");
}
else
{
//printf("d3=0x%0x,a=0x%0x,d3&a=0x%0x\n",d3,a,d3&a);
// printf("Not Detected!\n");
}
a>>=2;
b>>=1;
}
//进行数据纠正
// printf("开始进行数据纠正\n");
// printf("Error byte: %2d,Error bit: %2d\n",add,bit);
b=0x01;
b<<=bit;
a=dat[add];
a^=b;
dat[add]=a;
return 1;
}
else
{
i=0;
// printf("计算异或结果d1,d2,d3中1的个数\n");
//计算异或结果d1,d2,d3中1的个数
while(d1)
{
if(d1&0x01)
i++;
d1>>=1;
}
while(d2)
{
if(d2&0x01)
i++;
d3>>=1;
}
while(d3)
{
if(d3&0x01)
i++;
d3>>=1;
}
if(i == 1)
{
//发生了ECC错误,即存放ECC数据的区域发生了错误,正常的情况下,无论多少
//bit发生了反转,都不会出现i=1的情况,出现了这种情况的原因只可能是ECC代码本身有问题
// printf("存放ECC数据的区域发生了错误\n");
return 2;
}
else
{
//不可校正的ECC错误,即Uncorrectable Error
// printf("Uncorrectable Error\n");
return -1;
}
}
}
return -1;
}
int main(int argc, char* argv[])
{
int temp,i,j,k,l,m=0;
unsigned char ReadECC[3]={0,0,0},CalECC[3]={0,0,0};
NandCalECC(dat,CalECC);
for(i=0;i<256;i++)
{
j=0x80;
l=dat[i];
for(k=0;k<8;k++)
{
m++;
dat[i]^=j;
j>>=1;
NandCalECC(dat,ReadECC);
temp=NandCorrectData(dat,ReadECC,CalECC);
if(temp == 1)
{
if(dat[i]==l)
printf("Success\n");
else
printf("Failed\n");
// printf("可以校正的错误\n");
// printf("dat[0]=0x%0x\n",dat[0]);
}
else if(temp == -1)
{
//printf("不可以校正的错误");
}
else if(temp == 0)
{
//printf("无错误");
}
else
{
// printf("数据区发生了错误");
}
//////////////////
/*
dat[5]=0x02;
NandCalECC(dat,ReadECC);
temp=NandCorrectData(dat,ReadECC,CalECC);
if(temp == 1)
{
printf("可以校正的错误\n");
printf("dat[0]=0x%0x\n",dat[0]);
}
else if(temp == -1)
{
printf("不可以校正的错误");
}
else if(temp == 0)
{
printf("无错误");
}
else
{
printf("数据区发生了错误");
}
*/
//////////////////////////
}
}
printf("rotate times:%5d\n",m);
return 0;
}
附件2:512字节ECC校正1比特错误的代码实现
// 512ByteECC071127.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
// 256ByteECC071123.cpp : Defines the entry point for the console application.
//
//071127
unsigned char dat[]={
0x0 ,0x0 ,0x0 ,0x0 ,0x0 ,0x0 ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0 ,
0x0 ,0x0 ,0x0 ,0x0 ,0x0 ,0x0 ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0
};
//071123
unsigned char ECCTable[]={
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0x6a ,0x3f ,0x3c ,0x69 ,0x33 ,0x66 ,0x65 ,0x30 ,0x30 ,0x65 ,0x66 ,0x33 ,0x69 ,0x3c ,0x3f ,0x6a ,
0xf ,0x5a ,0x59 ,0xc ,0x56 ,0x3 ,0x0 ,0x55 ,0x55 ,0x0 ,0x3 ,0x56 ,0xc ,0x59 ,0x5a ,0xf ,
0xc ,0x59 ,0x5a ,0xf ,0x55 ,0x0 ,0x3 ,0x56 ,0x56 ,0x3 ,0x0 ,0x55 ,0xf ,0x5a ,0x59 ,0xc ,
0x69 ,0x3c ,0x3f ,0x6a ,0x30 ,0x65 ,0x66 ,0x33 ,0x33 ,0x66 ,0x65 ,0x30 ,0x6a ,0x3f ,0x3c ,0x69 ,
0x3 ,0x56 ,0x55 ,0x0 ,0x5a ,0xf ,0xc ,0x59 ,0x59 ,0xc ,0xf ,0x5a ,0x0 ,0x55 ,0x56 ,0x3 ,
0x66 ,0x33 ,0x30 ,0x65 ,0x3f ,0x6a ,0x69 ,0x3c ,0x3c ,0x69 ,0x6a ,0x3f ,0x65 ,0x30 ,0x33 ,0x66 ,
0x65 ,0x30 ,0x33 ,0x66 ,0x3c ,0x69 ,0x6a ,0x3f ,0x3f ,0x6a ,0x69 ,0x3c ,0x66 ,0x33 ,0x30 ,0x65 ,
0x0 ,0x55 ,0x56 ,0x3 ,0x59 ,0xc ,0xf ,0x5a ,0x5a ,0xf ,0xc ,0x59 ,0x3 ,0x56 ,0x55 ,0x0
};
//计算ECC代码
void NandTranResult(unsigned int *reg1,unsigned int *reg2,unsigned int *reg3)
{
unsigned char i,a,b;
unsigned int temp1,temp2,temp3;
temp1=temp2=temp3=0;
a=b=0x80;
for(i=0;i<4;i++)
{
if((*reg3)&a)
temp1|=b;
b>>=1;
if((*reg2)&a)
temp1|=b;
b>>=1;
a>>=1;
}
b=0x80;
for(i=0;i<4;i++)
{
if((*reg3)&a)
temp2|=b;
b>>=1;
if((*reg2)&a)
temp2|=b;
b>>=1;
a>>=1;
}
temp3|=((*reg1)&0x3f);
temp3<<=2;
if((*reg3)&0x100)
temp3|=0x2;
if((*reg2)&0x100)
temp3|=0x1;
*reg1=temp1;
*reg2=temp2;
*reg3=temp3;
}
void NandCalECC(const unsigned char *dat,unsigned char *ECCCode)
{
unsigned int reg1,reg2,reg3,temp;
unsigned int j;
reg1=reg2=reg3=0;
for(j=0;j<512;j++)
{
temp=ECCTable[dat[j]];
reg1^=(temp&0x3f);
if(temp&0x40)
{
reg3^=(j&0x1ff); //取出变量j低9个bit的数据
reg2^=(~(j&0x1ff));//同样的道理取出9的bit数据
// if(j==0||j==256)
// printf("[NandCalECC] Byte:%3d,reg3:0x%0x,reg2:0x%0x\n",j,reg3,reg2);
}
}
//printf("[NandCalECC] reg1=0x%0x,reg2=0x%0x,reg3=0x%0x\n",reg1,reg2,reg3);
NandTranResult(®1,®2,®3);
// printf("[NandCalECC] reg1=0x%0x,reg2=0x%0x,reg3=0x%0x\n",reg1,reg2,reg3);
ECCCode[0]=~((unsigned char)reg1);
ECCCode[1]=~((unsigned char)reg2);
ECCCode[2]=~((unsigned char)reg3);
//计算最终的ECC码
//此处为什么要做一个求非的操作呢??????,如果不做非操作也没有问题
/*
ECCCode[0]=~ECCCode[0];
ECCCode[1]=~ECCCode[1];
ECCCode[2]=(((~reg1)<<2)|0x03);
*/
/*
ECCCode[0]=ECCCode[0];
ECCCode[1]=ECCCode[1];
ECCCode[2]=(((reg1)<<2)|0x03);
*/
}
/*
* 参数解释
* dat[]:实际读取的数据
* ReadECC[]:保存数据时根据原始数据产生的ECC码
* CalECC[]:读取数据的同时产生的ECC码
*/
int NandCorrectData(unsigned char *dat,unsigned char *ReadECC,unsigned char *CalECC)
{
unsigned char bit,i;
unsigned int add,a,b,c,d1,d2,d3;
add=a=b=c=d1=d3=d2=0;
//计算
d1=ReadECC[0]^CalECC[0];
d2=ReadECC[1]^CalECC[1];
d3=ReadECC[2]^CalECC[2];
//printf("[NandCorrectData] d1=0x%0x,d2=0x%0x,d3=0x%0x\n",d1,d2,d3);
if((d1|d2|d3) == 0)
{
//无错误发生
printf("无错误发生\n");
return 0;
}
else
{
a=((d1>>1)^d1)&0x55;
b=((d2>>1)^d2)&0x55;
//c=((d3>>1)^d3)&0x54;
c=((d3>>1)^d3)&0x55;
//此处的理论依据是:如果发生了1bit的ECC错误,那么ECC异或地结果是--每个配对的bit数据相反,即为0&1或者1&0
if((a == 0x55)&(b == 0x55)&(c == 0x55))
{
//可校正的1bit ECC错误
//首先计算错误的Byte
a=b=c=0x80;
add=0;
for(i=0;i<4;i++)
{
if(d1&a)
add|=b;
a>>=2;
b>>=1;
}
for(i=0;i<4;i++)
{
if(d2&c)
add|=b;
c>>=2;
b>>=1;
}
//检查P2048对应位置的值
if(d3&0x2)
{
add|=0x100;
// printf("[NandCorrectData] add|=0x100\n");
}
//计算发生错误的Bit
bit=0;
a=0x80;
b=0x04;
// printf("d3 = 0x%0x\n",d3);
for(i=0;i<3;i++)
{
if(d3&a)
{
bit|=b;
// printf("Detected!\n");
}
else
{
//printf("d3=0x%0x,a=0x%0x,d3&a=0x%0x\n",d3,a,d3&a);
// printf("Not Detected!\n");
}
a>>=2;
b>>=1;
}
//进行数据纠正
//printf("开始进行数据纠正\n");
//printf("[NandCorrectData] Error byte: %5d,Error bit: %5d\n",add,bit);
b=0x01;
b<<=bit;
a=dat[add];
a^=b;
dat[add]=a;
return 1;
}
else
{
i=0;
//printf("计算异或结果d1,d2,d3中1的个数\n");
//计算异或结果d1,d2,d3中1的个数
while(d1)
{
if(d1&0x01)
i++;
d1>>=1;
}
while(d2)
{
if(d2&0x01)
i++;
d3>>=1;
}
while(d3)
{
if(d3&0x01)
i++;
d3>>=1;
}
if(i == 1)
{
//发生了ECC错误,即存放ECC数据的区域发生了错误,正常的情况下,无论多少
//bit发生了反转,都不会出现i=1的情况,出现了这种情况的原因只可能是ECC代码本身有问题
//printf("存放ECC数据的区域发生了错误\n");
return 2;
}
else
{
//不可校正的ECC错误,多于1比特的错误即Uncorrectable Error
//printf("Uncorrectable Error\n");
return -1;
}
}
}
return -1;
}
int main(int argc, char* argv[])
{
int temp,i,j,k,l,m=0,n=0;
unsigned char ReadECC[3]={0,0,0},CalECC[3]={0,0,0};
printf("*****************Program start******************\n");
NandCalECC(dat,CalECC);
printf("\n\n");
for(i=0;i<512;i++)
{
j=0x80;
l=dat[i];//记录下人为修改之前的数据
for(k=0;k<8;k++)
{
//m++;//记录该循环执行的次数
dat[i]^=j;//改变原始数据的某一个Bit
j>>=1; //为改变原始数据的下一个Bit做准备
NandCalECC(dat,ReadECC);//计算修改过512字节数据的ECC值
temp=NandCorrectData(dat,ReadECC,CalECC);//对数据进行ECC
if(temp == 1)
{
if(dat[i]==l)
// printf("Success\n");
n++;
else
{
m++;
printf("Failed at byte:%5d,bit:%5d\n",i,k);
}
// printf("可以校正的错误\n");
// printf("dat[0]=0x%0x\n",dat[0]);
}
else if(temp == -1)
{
//printf("不可以校正的错误");
}
else if(temp == 0)
{
//printf("无错误");
}
else
{
// printf("数据区发生了错误");
}
//printf("\n\n");
}
}
printf("Success times:%5d,failed times:%5d\n",n,m);
printf("*******************Program end******************\n");
return 0;
}
- -20071127晚
/*************************************************************************************************************/
/**********************************************
* 如有疑问,欢迎联系
***********************************************/