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晚
/*************************************************************************************************************/ /********************************************** * 如有疑问,欢迎联系guopeixin@126.com ***********************************************/
/*************************************************************************************************************/
|