ECC的代码实现

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243387.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FPGA图像处理的开发流程

FPGA图像处理的开发流程 1、需求分析及问题描述 问题描述应该清楚地描述问题而不是解决方法。它应该包括系统需要做什么、为什么要做,而不包括怎么做。 为了描述更具体,至少需要讨论三个方面。 第一是系统功能,也就是系统需要做什么。在一个图像处理应用中,需要详细说明图…

C/C++实现模糊控制,借助MATLAB辅助设计和fis.c文件

上一篇文章&#xff08;C /C语言实现模糊控制&#xff09;介绍了C/C中实现模糊控制该怎么做&#xff0c;开始提到的MATLAB模糊控制的C/C模糊控制接口fis.c库&#xff0c;不过这个文件有点老&#xff0c;在用VS2010编译的时候一大堆错误&#xff0c;在网上找关于C中使用 fis.c 的…

转载:Windows CE内存管理

内存管理如果你在写Windows CE 程序中遇到的最重要的问题&#xff0c;那一定是内存问题。一个WinCE 系统可能只有4MB 的RAM&#xff0c;这相对于个人电脑来说是十分少的&#xff0c;因为个人电脑的标准配置已经到了128MB 甚至更多。事实上&#xff0c;运行WinCE 的机器的内存十…

一些比较使用的技巧

一些比较使用的技巧 1、如何得到一个信号的上升沿 注意:时序逻辑有打一拍的特性,组合逻辑没有。 input vsync; reg vsync_r; reg vsync_r2; wire vsync_r2_n; wire vsync_rise;always@(posedge clk) beginvsync_r <= vsync;vsync_r2 <= vsync_r; endassign vsync_r2_…

2012年我读过的十本好书

1、《世上的光》是俄罗斯导演安德烈塔可夫斯基的拍立得摄影集。从中我们可以感受他在拍电影之余的个人生活&#xff0c;他的妻子&#xff0c;他的爱子以及梦幻般的乡村景色。而他配的文字更是让我们笃信他的确是个电影诗人。“影像&#xff0c;是真理的印记”“影像是谷粒&…

MFC界面编程新思路--模仿MATLAB式的界面

像下面的这个图片一样&#xff0c;做一个图像测量的软件&#xff0c;界面需要模仿MATLAB&#xff0c;以前老是新建一个对话框式的MFC应用程序&#xff0c;或者是一个SDI的应用程序&#xff0c;搞了一年&#xff0c;慢慢的也想到了一种新的思路&#xff0c;而且今天也做了一个De…

敏捷是如何使你跑得更快?

对于为何采用敏捷软件开发这个问题&#xff0c;企业经常提到的原因之一是希望能够更快地交付软件。研究表明敏捷项目能够进行地更快&#xff0c;例如《敏捷项目的成功证据》一文中描述的哥伦布市敏捷工作效率基准项目。\u0026#xD;\n在博文《谁说敏捷项目不能更快一些》中&#…

WinCE电源管理的简单介绍

电源管理的目的是节能,基本的节能方法是使系统适时的进出休眠状态.比如用户按下On/Off按钮,或者监视用户活动的定时器超时,或者应用呼叫api都可以使得系统休眠,用户再次按下On/Off或者其他唤醒中断将使得系统退出休眠.从而可见,电源管理模块和用户活动情况密不可分,电源管理是用…

算法映射技术

算法映射技术 将图像处理的算法转换为FPGA系统设计的过程为算法映射。 映射过程的首要目标便是确定系统设计的结构,在图像处理中常用的两种系统设计结构:流水线结构和并行阵列结构 1、流水线设计 (1)基本概念 流水线处理源自现代工业生产装配线上的流水作业,是指将待处理…

WS_EX_COMPOSITED是个BUG?

新建的SDI应用程序&#xff0c;在删除 文档视图结构以后&#xff0c;突然出现资源文件(*.rc)错误&#xff0c;说是WS_EX_COMPOSITED没有定义&#xff0c;只好删除了事&#xff0c;不知道怎么回事。

《北妹》:中国七零后作家的一次火山喷发(答记者问)

1&#xff0c;您是如何留意到盛可以及其创作的&#xff1f;是她在哪个方面的特质或者特点很突出呢&#xff1f; 答&#xff1a;我很早就知道盛可以&#xff0c;但是真正读她的作品是从《道德颂》开始的&#xff0c;当时我被她对人性尤其是男性的思考和揭示深深地震撼了。她对生…

windowsCE异常和中断服务程序初探

windowsCE异常和中断服务程序初探 ---------by nasiry 转载请说明出处 1。中断/异常相量的装入和执行方式。 中断和异常都是异步发生的事件&#xff0c;当该事件发生&#xff0c;系统将停止目前正在执行的代码转而执行事件响应的服务程序。而事件服务程序的入口点就…

ISERDES Guidelines

ISERDES Guidelines ISERDES模块的作用在于实现高速源同步输入数据的串并转换。 OSERDES模块的作用在于实现高速源同步输出数据的并串转换。 SERDES支持SDR和DDR两个模式。 SDR模式支持2、3、4、5、6、7、8bit位宽; DDR模式支持4、6、8bit位宽,10或14bit位宽需要两个模块级…

VC 2010的MFC函数,CMFCVisualManager::GetInstance()可能导致内存泄露

今天在网上看到一篇文章&#xff0c;关于CMFCVisualManager的内存泄露问题&#xff08; 链接是 http://zhanyonhu.blog.163.com/blog/static/1618604420113208121859/&#xff09;&#xff0c;当然还有其他的关于CMFCButton控件也有内存泄露问题&#xff0c;乱七八糟扯蛋&#…

SRX alarm: Autorecovery information needs to be saved

One of our srx system alarm light is on. Check system alarms and fond this:[email protected]> show system alarms node0:————————————————————————–1 alarms currently activeAlarm time Class Description2013-03-13 16:50…

简单深入两个虚拟内存API VirtualAlloc及VritualCopy

VirtualAlloc : (配置虛擬記憶體) [MSDN] http://msdn.microsoft.com/en-us/library/aa366887(VS.85).aspx LPVOID WINAPI VirtualAlloc (LPVOID lpAddress, //所要分配記憶體區域虛擬位址的起始位址DWORD dwSize, //要分配或者保留的區域的大小DWORD flAllocationType, //分…

对传统视觉惯性的颠覆

何汶玦[日常影像]艺术展昨天在798白盒子艺术馆开幕。评论界认为&#xff1a;何汶玦的作品是对电影影像的摆脱&#xff0c;回归日常影像。我的理解是&#xff0c;或许电影影像是被导演、演员和摄影既定的&#xff0c;没有了我们自己的观察和省略。所谓日常就是我们每个人目光所及…

映射之计算技术

映射之计算技术 1、算法转换 (1)、定常数转换 对于定常数,可以通过一定的转换将其转换为移位和加法运算,从而减少乘法器和除法器的使用。 考虑以下乘法运算的实现 dout = din x 255 转换后 dout = din x (256 - 1) = (din << 8) - din dout = din x 123 转换后 do…

Digimeter 软件

这是新做的一款对图像进行测量分析的软件。可以对图像内容进行手工精确测量&#xff0c;进行自动对象识别&#xff1b;图像可以是X光图片、显微照片等&#xff0c;支持JPG、GIF、TIFF、BMP、PNG、WMF、EMF和DICOM多种格式&#xff1b;图片可以旋转、反转、拉伸&#xff0c;明暗…

由中行IBM大型机宕机谈银行系统运维

12月15日中行IBM大型机宕机&#xff0c;系统没有第一时间切换到热备或者异地容灾上&#xff0c;直接影响中行的信用卡支付相关业务&#xff0c;直到4小时之后才恢复服务。由于银行业务的特殊性&#xff0c;对于系统的可用性要求极高&#xff0c;就此事件&#xff0c;我们采访了…