分享

ECC的代码实现

 leon0821 2014-04-23

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(&reg1,&reg2,&reg3);

 // 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晚

/*************************************************************************************************************/
/**********************************************
* 如有疑问,欢迎联系guopeixin@126.com
***********************************************/

/*************************************************************************************************************/

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多