word下载

ECC的全称是Error Checking and Correction,是一种用于Nand的差错检测和修正算法。如果操作时序和电路稳定性不存在问题的话,NAND Flash出错的时候一般不会造成整个Block或是Page不能读取或是全部出错,而是整个Page(例如512Bytes)中只有一个或几个bit出错。ECC能纠正1个比特错误和检测2个比特错误,而且计算速度很快,但对1比特以上的错误无法纠正,对2比特以上的错误不保证能检测。
校验码生成算法:ECC校验每次对256字节的数据进行操作,包含列校验和行校验。对每个待校验的Bit位求异或,若结果为0,则表明含有偶数个1;若结果为1,则表明含有奇数个1。列校验规则如表1所示。256字节数据形成256行、8列的矩阵,矩阵每个元素表示一个Bit位。

其中CP0 ~ CP5 为六个Bit位,表示Column Parity(列极性),
CP0
为第0246列的极性,CP1为第1357列的极性,
CP2
为第0145列的极性,CP3为第2367列的极性,
CP4
为第0123列的极性,CP5为第4567列的极性。
用公式表示就是:CP0=Bit0^Bit2^Bit4^Bit6表示第0列内部256Bit位异或之后再跟第2256Bit位异或,再跟第4列、第6列的每个Bit位异或,这样,CP0其实是256*4=1024Bit位异或的结果。CP1 ~ CP5 依此类推。
行校验如下图所示

其中RP0 ~ RP15 为十六个Bit位,表示Row Parity(行极性),
RP0
为第0246….252254 个字节的极性
RP1-----1
357……253255
RP2----0
14589…..252253 (处理2Byte,跳过2Byte
RP3---- 2
3671011…..254255 (跳过2Byte,处理2Byte
RP4----
处理4Byte,跳过4Byte
RP5----
跳过4Byte,处理4Byte
RP6----
处理8Byte,跳过8Byte
RP7----
跳过8Byte,处理8Byte
RP8----
处理16Byte,跳过16Byte
RP9----
跳过16Byte,处理16Byte
RP10----
处理32Byte,跳过32Byte
RP11----
跳过32Byte,处理32Byte
RP12----
处理64Byte,跳过64Byte
RP13----
跳过64Byte,处理64Byte
RP14----
处理128Byte,跳过128Byte
RP15----
跳过128Byte,处理128Byte
可见,RP0 ~ RP15 每个Bit位都是128个字节(也就是128行)即128*8=1024Bit位求异或的结果。
综上所述,对256字节的数据共生成了6Bit的列校验结果,16Bit的行校验结果,共22Bit。在Nand中使用3个字节存放校验结果,多余的两个Bit位置1。存放次序如下表所示:

K9F1208为例,每个Page页包含512字节的数据区和16字节的OOB区。前256字节数据生成3字节ECC校验码,后256字节数据生成3字节ECC校验码,共6字节ECC校验码存放在OOB区中,存放的位置为OOB区的第012367字节。

文件:

MakeEccTable.rar

大小:

0KB

下载:

下载

校验码生成算法的C语言实现
Linux内核中ECC校验算法所在的文件为drivers/mtd/nand/nand_ecc.c,其实现有新、旧两种,在2.6.27及更早的内核中使用的程序,从2.6.28开始已经不再使用,而换成了效率更高的程序。可以在Documentation/mtd/nand_ecc.txt 文件中找到对新程序的详细介绍。
首先分析一下2.6.27内核中的ECC实现,源代码见:
http://lxr.linux.no/linux+v2.6.27/drivers/mtd/nand/nand_ecc.c


43/*
44 * Pre-calculated 256-way 1 byte column parity
45 */
46static const u_char
     nand_ecc_precalc_table[] = {
47   0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
48   0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
49   0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
50   0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
51   0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
52   0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
53   0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
54   0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
55   0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
56   0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
57   0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
58   0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
59   0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
60   0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
61   0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
62   0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
63  };
为了加快计算速度,程序中使用了一个预先计算好的列极性表。这个表中每一个元素都是unsigned char类型,表示8位二进制数。
表中8位二进制数每位的含义:

这个表的意思是:对0~255256个数,计算并存储每个数的列校验值和行校验值,以数作数组下标。比如 nand_ecc_precalc_table[ 13 ]  存储13的列校验值和行校验值,13的二进制表示为 00001101CP0 = Bit0^Bit2^Bit4^Bit6 = 0
CP1 = Bit1^Bit3^Bit5^Bit7 = 1

CP2 = Bit0^Bit1^Bit4^Bit5 = 1;
CP3 = Bit2^Bit3^Bit6^Bit7 = 0;
CP4 = Bit0^Bit1^Bit2^Bit3 = 1;
CP5 = Bit4^Bit5^Bit6^Bit7 = 0;
其行极性RP = Bit0^Bit1^Bit2^Bit3^Bit4^Bit5^Bit6^Bit7 = 1
nand_ecc_precalc_table[ 13 ] 处存储的值应该是 0101 0110,即0x56.
注意,数组nand_ecc_precalc_table的下标其实是我们要校验的一个字节数据。
理解了这个表的含义,也就很容易写个程序生成这个表了。程序见附件中的 MakeEccTable.c文件。
有了这个表,对单字节数据dat,可以直接查表 nand_ecc_precalc_table[ dat ] 得到 dat的行校验值和列校验值。但是ECC实际要校验的是256字节的数据,需要进行256次查表,对得到的256个查表结果进行按位异或,最终结果的 Bit0 ~ Bit5 即是256字节数据的 CP0 ~ CP5.
/* Build up column parity */
81        for(i = 0; i < 256; i++) {
82
                  /* Get CP0 - CP5 from table */
83
                      idx = nand_ecc_precalc_table[*dat++];
84
                      reg1 ^= (idx & 0x3f);
85
86            //
这里省略了一些,后面会介绍
91        }
Reg1

在这里,计算列极性的过程其实是先在一个字节数据的内部计算CP0 ~ CP5, 每个字节都计算完后再与其它字节的计算结果求异或。而表1中是先对一列Bit0求异或,再去异或一列Bit2这两种只是计算顺序不同,结果是一致的。因为异或运算的顺序是可交换的。
行极性的计算要复杂一些。
nand_ecc_precalc_table[]
表中的 Bit6 已经保存了每个单字节数的行极性值。对于待校验的256字节数据,分别查表,如果其行极性为1,则记录该数据所在的行索引(也就是for循环的i值),这里的行索引是很重要的,因为RP0 ~ RP15 的计算都是跟行索引紧密相关的,如RP0只计算偶数行,RP1只计算奇数行,等等。
/* Build up column parity */
81        for(i = 0; i < 256; i++) {
82      /* Get CP0 - CP5 from table */
83      idx = nand_ecc_precalc_table[*dat++];
84      reg1 ^= (idx & 0x3f);
85
86        /* All bit XOR = 1 ? */
87                if (idx & 0x40) {
88                           reg3 ^= (uint8_t) i;
89                           reg2 ^= ~((uint8_t) i);
90                }
91        }
这里的关键是理解第8889行。Reg3reg2都是unsigned char 型的变量,并都初始化为零。
行索引(也就是for循环里的i)的取值范围为0~255,根据表2可以得出以下规律:
RP0
只计算行索引的Bit00的行,RP1只计算行索引的Bit01的行;
RP2
只计算行索引的Bit10的行,RP3只计算行索引的Bit11的行;
RP4
只计算行索引的Bit20的行,RP5只计算行索引的Bit21的行;
RP6
只计算行索引的Bit30的行,RP7只计算行索引的Bit31的行;
RP8
只计算行索引的Bit40的行,RP9只计算行索引的Bit41的行;
RP10
只计算行索引的Bit50的行,RP11只计算行索引的Bit51的行;
RP12
只计算行索引的Bit60的行,RP13只计算行索引的Bit61的行;
RP14
只计算行索引的Bit70的行,RP15只计算行索引的Bit71的行;


已经知道,异或运算的作用是判断比特位为1的个数,跟比特位为0的个数没有关系。如果有偶数个1则异或的结果为0,如果有奇数个1则异或的结果为1
那么,程序第88行,对所有行校验为1的行索引按位异或运算,作用便是:
判断在所有行校验为1的行中,
属于RP1计算范围内的行有多少个------reg3Bit 0指示,0表示有偶数个,1表示有奇数个;
属于RP3计算范围内的行有多少个------reg3Bit 1指示,0表示有偶数个,1表示有奇数个;
属于RP5计算范围内的行有多少个------reg3Bit 2指示,0表示有偶数个,1表示有奇数个;
属于RP7计算范围内的行有多少个------reg3Bit 3指示,0表示有偶数个,1表示有奇数个;
属于RP9计算范围内的行有多少个------reg3Bit 4指示,0表示有偶数个,1表示有奇数个;
属于RP11计算范围内的行有多少个------reg3Bit 5指示,0表示有偶数个,1表示有奇数个;
属于RP13计算范围内的行有多少个------reg3Bit 6指示,0表示有偶数个,1表示有奇数个;
属于RP15计算范围内的行有多少个------reg3Bit 7指示,0表示有偶数个,1表示有奇数个;
所以,reg3每个Bit位的作用如下表所示:
Reg3

89行,对所有行校验为1的行索引按位取反之后,再按位异或,作用就是判断比特位为0的个数。比如reg2Bit00表示:所有行校验为1的行中,行索引的Bit00的行有偶数个,也就是落在RP0计算范围内的行有偶数个。所以得到结论:
在所有行校验为1的行中,
属于RP0计算范围内的行有多少个------reg2Bit 0指示,0表示有偶数个,1表示有奇数个;
属于RP2计算范围内的行有多少个------reg2Bit 1指示,0表示有偶数个,1表示有奇数个;
属于RP4计算范围内的行有多少个------reg2Bit 2指示,0表示有偶数个,1表示有奇数个;
属于RP6计算范围内的行有多少个------reg2Bit 3指示,0表示有偶数个,1表示有奇数个;
属于RP8计算范围内的行有多少个------reg2Bit 4指示,0表示有偶数个,1表示有奇数个;
属于RP10计算范围内的行有多少个------reg2Bit 5指示,0表示有偶数个,1表示有奇数个;
属于RP12计算范围内的行有多少个------reg2Bit 6指示,0表示有偶数个,1表示有奇数个;
属于RP14计算范围内的行有多少个------reg2Bit 7指示,0表示有偶数个,1表示有奇数个;
所以,reg2每个Bit位的作用如下表所示:
Reg2

至此,只用了一个查找表和一个for循环,就把所有的校验位CP0 ~ CP5 RP0 ~ RP15全都计算出来了。下面的任务只是按照表3的格式,把这些比特位重新排列一下顺序而已。
reg2reg3中抽取出 RP8~RP15放在tmp1中,抽取出RP0~RP7放在tmp2中,
Reg1
左移两位,低两位置1
然后把tmp2, tmp1, reg1 放在 ECC码的三个字节中。
程序中还有CONFIG_MTD_NAND_ECC_SMC又进行了一次取反操作,暂时还不知为何。


 ECC
纠错算法


当往NAND Flashpage中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存到PAGEOOBout-of-band)数据区中。当从NAND Flash中读取数据的时候,每256字节我们生成一个ECC校验和,称之为新ECC校验和。
将从OOB区中读出的原ECC校验和新ECC校验和按位异或,若结果为0,则表示不存在错(或是出现了 ECC无法检测的错误);若3个字节异或结果中存在11个比特位为1,表示存在一个比特错误,且可纠正;若3个字节异或结果中只存在1个比特位为1,表示 OOB区出错;其他情况均表示出现了无法纠正的错误。
假设ecc_code_raw[3] 保存原始的ECC校验码,ecc_code_new[3] 保存新计算出的ECC校验码,其格式如下表所示:

ecc_code_raw[3] ecc_code_new[3] 按位异或,得到的结果三个字节分别保存在s0,s1,s2中,如果s0s1s2中共有11Bit位为1,则表示出现了一个比特位错误,可以修正。定位出错的比特位的方法是,先确定行地址(即哪个字节出错),再确定列地址(即该字节中的哪一个Bit位出错)。
确定行地址的方法是,设行地址为unsigned char byteoffs,抽取s1中的Bit7,Bit5,Bit3,Bit1,作为 byteoffs的高四位,抽取s0中的Bit7,Bit5,Bit3,Bit1 作为byteoffs的低四位,byteoffs的值就表示出错字节的行地址(范围为0 ~ 255)。
确定列地址的方法是:抽取s2中的Bit7,Bit5,Bit3 作为 bitnum 的低三位,bitnum其余位置0,则bitnum的表示出错Bit位的列地址(范围为0 ~ 7)。
下面以一个简单的例子探索一下这其中的奥妙。
假设待校验的数据为两个字节,0x45(二进制为0100 0101)和0x38(二进制为0011 1000),其行列校验码如下表所示:

从表中可以计算出CP5 ~ CP0的值,列在下表的第一行(原始数据)。假设现在有一个数据位发生变化,0x38变为0x3A,也就是Byte
1
Bit 10变成了1,计算得到新的CP5 ~ CP0值放在下表第2行(变化后数据)。新旧校验码求异或的结果放在下表第三行。
可见,当 Bit
1
发生变化时,列校验值中只有CP1CP2CP4发生了变化,而CP0CP3CP5没变化,也就是说6Bit校验码有一半发生变化,则求异或的结果中有一半为1。同理,行校验求异或的结果也有一半为1。这就是为什么前面说256字节数据中的一个Bit位发生变化时,新旧22Bit校验码求异或的结果中会有11Bit 位为1

再来看怎么定位出错的Bit位。以列地址为例,若CP5发生变化(异或后的CP5=1),则出错处肯定在 Bit 4 ~ Bit 7中;若CP5无变化(异或后的CP5=0,则出错处在 Bit 0 ~ Bit 3 中,这样就筛选掉了一半的Bit位。剩下的4Bit位中,再看CP3是否发生变化,又选出2Bit位。剩下的2Bit位中再看CP1是否发生变化,则最终可定位1个出错的Bit位。下面的树形结构更清晰地展示了这个判决过程:

图表出错Bit列地址定位的判决树

注意:图中的CP指的是求异或之后的结果中的CP
为什么只用CP4CP2CP0呢?其实这里面包含冗余信息,因为CP5=1则必有CP4=0CP5=0则必有CP4=1,也就是CP5CP4一定相反,同理,CP3CP2一定相反,CP1CP0一定相反。所以只需要用一半就行了。
这样,我们从异或结果中抽取出CP5CP3CP1位,便可定位出错Bit位的列地址。比如上面的例子中CP5/CP3/CP1 = 001,表示Bit 1出错。
同理,行校验RP1发生变化,抽取RP1,可知Byte 1发生变化。这样定位出Byte 1Bit 0出错。
当数据位256字节时,行校验使用RP0 ~ RP15,抽取异或结果的RP15RP13RP11RP9RP7RP5RP3RP1位便可定位出哪个Byte出错,再用CP5,CP3,CP1定位哪个Bit出错。

文件:

TestEcc.rar

大小:

2KB

下载:

下载

原文地址 http://linux.chinaunix.net/bbs/viewthread.php?tid=1116253&extra=page%3D1

终于基本看懂了。。。。
下面解释一下,也许可以给和我曾经一样迷茫的人一点帮助:
对于这个,别人总结出来的规则:
RP0
只计算行索引的Bit00的行,RP1只计算行索引的Bit01的行;
RP2
只计算行索引的Bit10的行,RP3只计算行索引的Bit11的行;
RP4
只计算行索引的Bit20的行,RP5只计算行索引的Bit21的行;
RP6
只计算行索引的Bit30的行,RP7只计算行索引的Bit31的行;
RP8
只计算行索引的Bit40的行,RP9只计算行索引的Bit41的行;
RP10
只计算行索引的Bit50的行,RP11只计算行索引的Bit51的行;
RP12
只计算行索引的Bit60的行,RP13只计算行索引的Bit61的行;
RP14
只计算行索引的Bit70的行,RP15只计算行索引的Bit71的行;
在接下来的描述中,称为行与位的对应关系
另注:
1.
上述规则中的RP意思是Row Parity,更多的叫法叫做LPLine Parity)。为了解释更容易看懂,依旧采用RP的说法。
2.
对于第几行,采用Line的说法,比如第1行,其实就是行号为0Line0.
3.
对于行的奇偶性,此处采用Line Parity的说法。
Line5Line Parity1的时候,
首先最简单的理解,也是最直接的理解,那就是,要把所有RP0~RP14中,对应包含着此行的那些最后要计算的值找出来,
我们可以先手动地根据下图:

一点点,掰手指头,慢慢地写出来,那就是:
RP1
RP2RP5RP6RP8RP10RP12RP14
换句话说,如果Line5Line Parity1的时候,
我们应该要计算RP1RP2RP5RP6RP8RP10RP12RP14
关于这点,我想大家没有什么好疑问的吧,因为这就是按照其规则的最简单,最通俗的理解。
所以,不论你用什么复杂的算法,反正是要记录并且计算这些RP的值,以便和后面的值进行计算。
但是,程序在此处,并没有将这些RP找出来,而只是直接对行号进行XOR异或:
reg3 ^= (uint8_t) i;
表面上看,这和我们要找出来,并计算的那些RP,并没啥关系,这也是我开始很困惑的问题。
按理来说,应该是找出那些行号,然后计算对应的RP的值,并保存,这样才对。
而此处之所以可以这么处理,主要是有以下原因:
1.       
行与位的有如下对应关系:
RP0
只计算行索引的Bit00的行,RP1只计算行索引的Bit01的行;
RP2
只计算行索引的Bit10的行,RP3只计算行索引的Bit11的行;
RP4
只计算行索引的Bit20的行,RP5只计算行索引的Bit21的行;
RP6
只计算行索引的Bit30的行,RP7只计算行索引的Bit31的行;
RP8
只计算行索引的Bit40的行,RP9只计算行索引的Bit41的行;
RP10
只计算行索引的Bit50的行,RP11只计算行索引的Bit51的行;
RP12
只计算行索引的Bit60的行,RP13只计算行索引的Bit61的行;
RP14
只计算行索引的Bit70的行,RP15只计算行索引的Bit71的行;
2.       
某一行号的二进制分解的对应bit,对应了所要计算的RP
比如是第6行,也就是Line55的二进制是:

Bit7

Bit6

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

0

0

0

0

0

1

0

1


5
的二进制值
而根据上面别人分析出来的,行与位的对应关系,我们可以找出,此二进制的每一位所对应了哪些RP
bit
1的位,分别是02,对应代表的是RP1RP5
bit
0的位,分别是134567,对应代表的是RP2RP6RP8RP10RP12RP14
用表格表示为:

Bit7

Bit6

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

0

0

0

0

0

1

0

1

RP14

RP12

RP10

RP8

RP6

RP5

RP2

RP1


5
的二进制值和二进制对应的行
上表中,比如bit21,而别人说了“RP5只计算行索引的Bit21的行
所以,此处如果bit21,对应着RP5将要被计算,
那么我们可以肯定地得出来的是,
如果此行,Line5,的Line Parity1的话,RP5是要被计算的。
而仔细观察就会发现,RP5,就包含在我们上面自己手动找出来的那些LP中:
RP1
RP2RP5RP6RP8RP10RP12RP14
而,剩下的bit位,也依次对应着这些LP。比如bit01,对应RP1.
这就是我们上面说的某一行号的二进制分解的对应bit,对应了所要计算的RP”
也是理解如此处理的关键点之一。
同样地,除了bit1bit0bit2,对应的RP1RP5之外,
剩下的几个bit对应的RP2RP6RP8RP10RP12RP14,由于对应位是0,所以,即使拿过来抑或,也还是0,无法记住这些bit的值,所以,采用将其取反,这样,对应这些为0bit,就变成1了,就可以记住这些对应的bit了:
reg2 ^= ~((uint8_t) i);
这样,当从0255检测的过程中,如果发现某行的Line Parity1
那么就将其行号数值进行抑或,以存储奇数的LP,将行号取反,以保存偶数的LP
也就是:
Reg3
对应的就是RP1RP3RP5,。。。,RP15
Reg2
对应的就是RP0RP2RP4,。。。,RP14
然后再调用函数nand_trans_result(reg2, reg3, ecc_code);去将reg3reg2中存储的信息,
重新组织到ecc[1]ecc[2]中去。
最后的感慨是:
此处仅仅是通过对行号的数值抑或,以保存所要求的各个RP的值,之所以让人很难理解:
一是由于我们之前不知道上面的那个规则:行与位的对应关系
二是我们不知道,行号按位分解后,对应的bit位对应着所要计算的那些RP某一行号的二进制分解的对应bit,对应了所要计算的RP”
最后感谢各位作者和分享其分析过程的朋友。

代码:

Testecc.c

  1. /*
  2.  
  3. * =====================================================================================
  4.  
  5. *
  6.  
  7. * Filename: TestEcc.c
  8.  
  9. *
  10.  
  11. * Description:
  12.  
  13. *
  14.  
  15. * Version: 1.0
  16.  
  17. * Created: 2009年06月04日 20时15分54秒
  18.  
  19. * Revision: none
  20.  
  21. * Compiler: gcc
  22.  
  23. *
  24.  
  25. * Author: Li Hongwang (mn), hoakee@gmail.com
  26.  
  27. * Company: University of Science and Technology of China
  28.  
  29. *
  30.  
  31. * =====================================================================================
  32.  
  33. */
  34.  
  35. #include <stdio.h>
  36.  
  37. typedef unsigned char u_char;
  38.  
  39. typedef unsigned char uint8_t;
  40.  
  41. typedef unsigned int uint32_t;
  42.  
  43. /*
  44.  
  45. * Pre-calculated 256-way 1 byte column parity
  46.  
  47. */
  48.  
  49. static const u_char nand_ecc_precalc_table[] = {
  50.  
  51. 0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00,
  52.  
  53. 0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65,
  54.  
  55. 0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66,
  56.  
  57. 0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03,
  58.  
  59. 0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69,
  60.  
  61. 0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C,
  62.  
  63. 0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F,
  64.  
  65. 0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A,
  66.  
  67. 0x6A,0x3F,0x3C,0x69,0x33,0x66,0x65,0x30,0x30,0x65,0x66,0x33,0x69,0x3C,0x3F,0x6A,
  68.  
  69. 0x0F,0x5A,0x59,0x0C,0x56,0x03,0x00,0x55,0x55,0x00,0x03,0x56,0x0C,0x59,0x5A,0x0F,
  70.  
  71. 0x0C,0x59,0x5A,0x0F,0x55,0x00,0x03,0x56,0x56,0x03,0x00,0x55,0x0F,0x5A,0x59,0x0C,
  72.  
  73. 0x69,0x3C,0x3F,0x6A,0x30,0x65,0x66,0x33,0x33,0x66,0x65,0x30,0x6A,0x3F,0x3C,0x69,
  74.  
  75. 0x03,0x56,0x55,0x00,0x5A,0x0F,0x0C,0x59,0x59,0x0C,0x0F,0x5A,0x00,0x55,0x56,0x03,
  76.  
  77. 0x66,0x33,0x30,0x65,0x3F,0x6A,0x69,0x3C,0x3C,0x69,0x6A,0x3F,0x65,0x30,0x33,0x66,
  78.  
  79. 0x65,0x30,0x33,0x66,0x3C,0x69,0x6A,0x3F,0x3F,0x6A,0x69,0x3C,0x66,0x33,0x30,0x65,
  80.  
  81. 0x00,0x55,0x56,0x03,0x59,0x0C,0x0F,0x5A,0x5A,0x0F,0x0C,0x59,0x03,0x56,0x55,0x00
  82.  
  83. };
  84.  
  85. /**
  86.  
  87. * * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
  88.  
  89. * * @mtd: MTD block structure
  90.  
  91. * * @dat: raw data
  92.  
  93. * * @ecc_code: buffer for ECC
  94.  
  95. * */
  96.  
  97. int nand_calculate_ecc(const u_char *dat, u_char *ecc_code)
  98.  
  99. {
  100.  
  101. uint8_t idx, reg1, reg2, reg3, tmp1, tmp2;
  102.  
  103. int i;
  104.  
  105. /* Initialize variables */
  106.  
  107. reg1 = reg2 = reg3 = ;
  108.  
  109. /* Build up column parity */
  110.  
  111. for(i = ; i < ; i++) {
  112.  
  113. /* Get CP0 - CP5 from table */
  114.  
  115. idx = nand_ecc_precalc_table[*dat++];
  116.  
  117. reg1 ^= (idx & 0x3f);
  118.  
  119. /* All bit XOR = 1 ? */
  120.  
  121. if (idx & 0x40) {
  122.  
  123. reg3 ^= (uint8_t) i;
  124.  
  125. reg2 ^= ~((uint8_t) i);
  126.  
  127. }
  128.  
  129. }
  130.  
  131. /* Create non-inverted ECC code from line parity */
  132.  
  133. tmp1 = (reg3 & 0x80) >> ; /* B7 -> B7 */
  134.  
  135. tmp1 |= (reg2 & 0x80) >> ; /* B7 -> B6 */
  136.  
  137. tmp1 |= (reg3 & 0x40) >> ; /* B6 -> B5 */
  138.  
  139. tmp1 |= (reg2 & 0x40) >> ; /* B6 -> B4 */
  140.  
  141. tmp1 |= (reg3 & 0x20) >> ; /* B5 -> B3 */
  142.  
  143. tmp1 |= (reg2 & 0x20) >> ; /* B5 -> B2 */
  144.  
  145. tmp1 |= (reg3 & 0x10) >> ; /* B4 -> B1 */
  146.  
  147. tmp1 |= (reg2 & 0x10) >> ; /* B4 -> B0 */
  148.  
  149. tmp2 = (reg3 & 0x08) << ; /* B3 -> B7 */
  150.  
  151. tmp2 |= (reg2 & 0x08) << ; /* B3 -> B6 */
  152.  
  153. tmp2 |= (reg3 & 0x04) << ; /* B2 -> B5 */
  154.  
  155. tmp2 |= (reg2 & 0x04) << ; /* B2 -> B4 */
  156.  
  157. tmp2 |= (reg3 & 0x02) << ; /* B1 -> B3 */
  158.  
  159. tmp2 |= (reg2 & 0x02) << ; /* B1 -> B2 */
  160.  
  161. tmp2 |= (reg3 & 0x01) << ; /* B0 -> B1 */
  162.  
  163. tmp2 |= (reg2 & 0x01) << ; /* B7 -> B0 */
  164.  
  165. /* Calculate final ECC code */
  166.  
  167. #ifdef CONFIG_MTD_NAND_ECC_SMC
  168.  
  169. //ecc_code[0] = ~tmp2;
  170.  
  171. //ecc_code[1] = ~tmp1;
  172.  
  173. #else
  174.  
  175. //ecc_code[0] = ~tmp1;
  176.  
  177. //ecc_code[1] = ~tmp2;
  178.  
  179. #endif
  180.  
  181. ecc_code[] = tmp2;
  182.  
  183. ecc_code[] = tmp1;
  184.  
  185. //ecc_code[2] = ((~reg1) << 2) | 0x03;
  186.  
  187. ecc_code[] = ((reg1) << ) | 0x03;
  188.  
  189. return ;
  190.  
  191. }
  192.  
  193. static inline int countbits(uint32_t byte)
  194.  
  195. {
  196.  
  197. int res = ;
  198.  
  199. for (;byte; byte >>= )
  200.  
  201. res += byte & 0x01;
  202.  
  203. return res;
  204.  
  205. }
  206.  
  207. int nand_correct_data( u_char *read_ecc, u_char *calc_ecc)
  208.  
  209. {
  210.  
  211. uint8_t s0, s1, s2;
  212.  
  213. s0 = calc_ecc[] ^ read_ecc[];
  214.  
  215. s1 = calc_ecc[] ^ read_ecc[];
  216.  
  217. s2 = calc_ecc[] ^ read_ecc[];
  218.  
  219. if ((s0 | s1 | s2) == )
  220.  
  221. return ;
  222.  
  223. /* Check for a single bit error */
  224.  
  225. if( ((s0 ^ (s0 >> )) & 0x55) == 0x55 &&
  226.  
  227. ((s1 ^ (s1 >> )) & 0x55) == 0x55 &&
  228.  
  229. ((s2 ^ (s2 >> )) & 0x54) == 0x54) {
  230.  
  231. uint32_t byteoffs, bitnum;
  232.  
  233. byteoffs = (s1 << ) & 0x80;
  234.  
  235. byteoffs |= (s1 << ) & 0x40;
  236.  
  237. byteoffs |= (s1 << ) & 0x20;
  238.  
  239. byteoffs |= (s1 << ) & 0x10;
  240.  
  241. byteoffs |= (s0 >> ) & 0x08;
  242.  
  243. byteoffs |= (s0 >> ) & 0x04;
  244.  
  245. byteoffs |= (s0 >> ) & 0x02;
  246.  
  247. byteoffs |= (s0 >> ) & 0x01;
  248.  
  249. bitnum = (s2 >> ) & 0x04;
  250.  
  251. bitnum |= (s2 >> ) & 0x02;
  252.  
  253. bitnum |= (s2 >> ) & 0x01;
  254.  
  255. printf("Error Bit at: Byte %d, Bit %d.\n", byteoffs, bitnum);
  256.  
  257. return ;
  258.  
  259. }
  260.  
  261. if(countbits(s0 | ((uint32_t)s1 << ) | ((uint32_t)s2 <<)) == )
  262.  
  263. return ;
  264.  
  265. return -;
  266.  
  267. }
  268.  
  269. //
  270.  
  271. static const u_char raw_data[] = {
  272.  
  273. 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
  274.  
  275. 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
  276.  
  277. 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
  278.  
  279. 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
  280.  
  281. 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  282.  
  283. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
  284.  
  285. 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
  286.  
  287. 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
  288.  
  289. 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
  290.  
  291. 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
  292.  
  293. 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
  294.  
  295. 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
  296.  
  297. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
  298.  
  299. 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
  300.  
  301. 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
  302.  
  303. 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
  304.  
  305. };
  306.  
  307. // changed data. 0x34==>0x74
  308.  
  309. static const u_char new_data[] = {
  310.  
  311. 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
  312.  
  313. 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
  314.  
  315. 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
  316.  
  317. 0x30,0x31,0x32,0x33,0x74,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
  318.  
  319. 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
  320.  
  321. 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
  322.  
  323. 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
  324.  
  325. 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
  326.  
  327. 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
  328.  
  329. 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
  330.  
  331. 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
  332.  
  333. 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
  334.  
  335. 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
  336.  
  337. 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
  338.  
  339. 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
  340.  
  341. 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
  342.  
  343. };
  344.  
  345. static uint8_t ecc_code_raw[];
  346.  
  347. static uint8_t ecc_code_new[];
  348.  
  349. int main()
  350.  
  351. {
  352.  
  353. int i=;
  354.  
  355. nand_calculate_ecc( raw_data, ecc_code_raw );
  356.  
  357. nand_calculate_ecc( new_data, ecc_code_new );
  358.  
  359. printf("\nRaw ECC Code: ");
  360.  
  361. for( i=; i< ; i++)
  362.  
  363. {
  364.  
  365. printf("0x%02X ", ecc_code_raw[i] );
  366.  
  367. }
  368.  
  369. printf("\nNew ECC Code: ");
  370.  
  371. for( i=; i< ; i++)
  372.  
  373. {
  374.  
  375. printf("0x%02X ", ecc_code_new[i] );
  376.  
  377. }
  378.  
  379. printf("\n");
  380.  
  381. nand_correct_data( ecc_code_raw, ecc_code_new );
  382.  
  383. printf("\n");
  384.  
  385. }

Nand_ECC_校验和纠错_详解的更多相关文章

  1. shell-的特殊变量-进程状态变量$$ $! $? $_详解

    一:shell的特殊变量-进程状态变量详解  1. 进程状态变量 $$ 获取当前shell的进程号(pid) $! 执行上一个指令的pid,上一个后台运行进程的进程号 $? 获取执行上一个指令的返回值 ...

  2. 【NOIP2015普及组】推销员_详解

    题目 题目大意 阿明是一名推销员--螺丝街是一条直线,一端有入口,一共有 \(N(<100,000)\) 家住户,第 \(i\) 家住户到入口的距离为 \(S_i\) 米.由于同一栋房子里可以有 ...

  3. Spring注解_详解

    @Autowired 注释 将 @Autowired 注释标注在成员变量上   import org.springframework.beans.factory.annotation.Autowire ...

  4. TCP头校验和计算算法详解

    我就不管是按“位”(bit)取反相加,还是 按“1的补码”相加了,总之就是把需要进行校验的“字串”加(+)起来,把这相加的 结果取反当做“校验和” (Checksum), 比如,相加的结果是0101, ...

  5. 终极优化_详解Win7旗舰版系统中可以关闭的服务

    Win7旗舰版系统是一款功能强大的系统,不过对于很多用户很多功能却使用不上,而支持功能的很多服务也多少占用了系统资源,那么我们可以通过关闭一些不使用的服务来达到让win7系统运行速度加快的目的.下面小 ...

  6. phpcms v9联动菜单的调用方法_详解get_linkage函数

    phpcms v9联动菜单调用方法[此为内容页调用方法]: {get_linkage($areaid,1,' >> ',1)} 显示效果: phpcms吧 >> 模板下载 &g ...

  7. confirm("确定要删除吗?") _详解

    具体代码如下: html代码: <div class="deletes">删除</div> js代码: <script type="text ...

  8. Python说文解字_详解元类

    1.深入理解一切接对象: 1.1 什么是类和对象? 首先明白元类之前要明白什么叫做类.类是面向对象object oriented programming的重要概念.在面向对象中类和对象是最基本的两个概 ...

  9. Android:TextView跑马灯-详解

    Android:TextView跑马灯_详解 引言: TextView之所以需要跑马灯,是由于文字太长,或者是吸引眼球. 关键代码如下: android:singleLine="true&q ...

随机推荐

  1. stl测试

    以下测试都在学校电脑进行 我觉得应该比考试机器慢一点.. 1.map map的速度测出来和放入数值大小有很大关系 比如 #include <bits/stdc++.h> using nam ...

  2. 清北合肥day2-day5

    day2:215这一天的题目相对比较模板化t1:50看错了数据范围求n个点到给出的点哈夫曼距离的最小值我想到的是一种非常zz的做法我们二分答案,然后判断是否在这个距离内有点但是这样前缀和不是很好维护于 ...

  3. JMeter非GUI模式下日志介绍

    Creating summariser <summary> Created the tree successfully using /opt/JMeter/TestPlan/test.jm ...

  4. 006 使用SpringMVC开发restful API四--用户信息的修复与删除,重在注解的定义

    一:任务 1.任务 常用的验证注解 自定义返回消息 自定义校验注解 二:Hibernate Validator 1.常见的校验注解 2.程序 测试类 /** * @throws Exception * ...

  5. Machine Learning 算法可视化实现2 - Apriori算法实现

    目录 关联分析 Apriori原理 Apriori算法实现 - 频繁项集 Apriori算法实现 - 从频繁项集挖掘关联规则 一.关联分析 关联分析是一种在大规模数据集中寻找有趣关系的任务. 这些关系 ...

  6. metasploit支持利用的CVE

    因为需要添加许多漏洞的流量检测,所以需要模拟很多漏洞的利用过程,简单来说,就是抓漏洞利用过程的流量. 一个脚本对metasploit中的module中包含的cve字段进行提取,而后去重,得出metas ...

  7. redis初步入门(2)

    一.redis持久化 1.redis是一个内存数据库,当redis服务器重启,或者电脑关机重启,数据会丢失,所以需要将redis内存中的数据持久化保存到硬盘文件中. 2.redis持久化机制 (1)R ...

  8. 大数据技术 - MapReduce 作业的运行机制

    前几章我们介绍了 Hadoop 的 MapReduce 和 HDFS 两大组件,内容比较基础,看完后可以写简单的 MR 应用程序,也能够用命令行或 Java API 操作 HDFS.但要对 Hadoo ...

  9. Linux开源监控平台归总

    Linux开源监控平台归总 Cacti 偏向于基础监控.成图非常漂亮,需要php环境支持,并且需要mysql作为数据存储 Cacti是一个性能广泛的图表和趋势分析工具,可以用来跟踪并几乎可以绘制出任何 ...

  10. Linux学习笔记10

    创建文件 touch touch filenames 创建文件夹 mkdir mkdir dir3 dir4 dir5 建立多个文件夹 mkdir ~/games  在登录用户的本目录之下建立game ...