ECC校验原理

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

ecc算法 swift ecc算法verilog实现_数据


列校验如上图所示:

CP0 == 所有的 Bit0 ^ Bit2 ^ Bit4 ^ Bit6

CP1 == 所有的 Bit1 ^ Bit3 ^ Bit5 ^ Bit7

CP2 == 所有的 Bit0 ^ Bit1 ^ Bit4 ^ Bit5

CP3 == 所有的 Bit2 ^ Bit3 ^ Bit6 ^ Bit7

CP4 == 所有的 Bit0 ^ Bit1 ^ Bit2 ^ Bit3

CP5 == 所有的 Bit4 ^ Bit5 ^ Bit6 ^ Bit7

--> 每个列校验都是 1024 位异或的结果

--> 如果结果为1,说明有奇数个1位,结果如果为0,说明为偶数个1.

--> 列校验结果一共有上面6位

行校验如上图所示:
RP0 第0行以及每隔 1 行所有位的异或结果。
RP1 第1行以及每隔 1 行所有位的异或结果。
RP2,RP3 是间隔 2 行所有位的异或结果。
RP4,RP5 是间隔 4 行所有位的异或结果。
RP6,RP7 是间隔 8 行所有位的异或结果。
RP8,RP9 是间隔 16 行所有位的异或结果。
RP10,RP11 是间隔 32 行所有位的异或结果。
RP12,RP13 是间隔 64 行所有位的异或结果。
RP14,RP15 是间隔 128 行所有位的异或结果。

--> 这些结果都是8 * 128 = 1024 位的异或结果。
--> 如果结果为1,说明有奇数个1位,结果如果为0,说明为偶数个1.
--> 行校验一共有16位。

综上所示,8位宽的256字节数据生成6个bit的列校验数据,16个bit的行校验数据,总共22个bit,可得512字节的数据生成6个bit的列校验数据,18个行校验数据,总共24bit。同理,16位宽的256字节数据生成8个bit的列校验数据,14个bit的行校验数据,可得512字节的数据生成8个bit的列校验数据,16个bit的行校验数据。

ECC校验纠错

当往NAND Flash的page中写入数据的时候,每256字节我们生成一个ECC校验和,称之为原ECC校验和,保存起来。当从NAND Flash中读取数据的时候,每256字节我们生成一个ECC校验和,称之为新ECC校验和。将原ECC校验和与新ECC校验和按位异或,若结果为0,则表示不存在错误(或是出现了ECC无法检测的错误);若22个bit校验和结果中存在11个bit为1,表示存在一个bit数据错误,且可以纠正;若结果中只存在1个bit为1,表示出现了无法纠正的错误。因为每个字节中的每个bit至少会参加列校验总数(CP0…CPn)n/2次列校验计算和行校验总是(RP0…RPm)m/2次行校验校验。因此当256字节的数据校验和结果22个bit校验和结果中存在11个bit为1时,才会表示一个bit数据发送错误。

定位出错的bit位的方式为:先确定行地址(即哪个字节出错),再确定列地址(即该字节的哪一个bit位出错)。将原ECC校验和与新ECC校验和按位异或之后,得到新的“RP15,RP14…RP1,RP0,CP5,CP4…CP1,CP0”校验和结果。抽取RP15,RP13,RP11,RP9,RP7,RP5,RP3,RP1组成新的8bit数据,表示的值就是出错的字节的行地址(范围0~ 255)。抽取CP5,CP3,CP1组成新的3bit数据,表示的值就是出错的字节的列地址(范围0~ 7)。

ecc算法 swift ecc算法verilog实现_nand_02

如上图列地址为例:若CP5发生变化(异或后的CP5=1),则出错处肯定在 Bit 4 ~ Bit 7中;若CP5无变化(异或后的CP5=0),则出错处在 Bit 0 ~ Bit 3 中,这样就筛选掉了一半的Bit位。剩下的4个Bit位中,再看CP3是否发生变化,又选出2个Bit位。剩下的2Bit位中再看CP1是否发生变化,则最终可定位1个出错的Bit位。从异或结果中抽取CP5,CP3,CP1位,便可定位出错bit位的列地址。同理行校验抽取异或结果的RP15,RP13,RP11,RP9,RP7,RP5,RP3,RP1位便可定位出哪个Byte出错,再用CP5,CP3,CP1定位哪个Bit出错。

ECC校验示例:

assign CP0 = ecc_data[14] ^ ecc_data[12] ^ ecc_data[10] ^ ecc_data[8] ^ ecc_data[6] ^ ecc_data[4] ^ ecc_data[2] ^ ecc_data[0];
  assign CP1 = ecc_data[15] ^ ecc_data[13] ^ ecc_data[11] ^ ecc_data[9] ^ ecc_data[7] ^ ecc_data[5] ^ ecc_data[3] ^ ecc_data[1];
  assign CP2 = ecc_data[13] ^ ecc_data[12] ^ ecc_data[9] ^ ecc_data[8] ^ ecc_data[5] ^ ecc_data[4] ^ ecc_data[1] ^ ecc_data[0];
  assign CP3 = ecc_data[15] ^ ecc_data[14] ^ ecc_data[11] ^ ecc_data[10] ^ ecc_data[7] ^ ecc_data[6] ^ ecc_data[3] ^ ecc_data[2];
  assign CP4 = ecc_data[11] ^ ecc_data[10] ^ ecc_data[9] ^ ecc_data[8] ^ ecc_data[3] ^ ecc_data[2] ^ ecc_data[1] ^ ecc_data[0];
  assign CP5 = ecc_data[15] ^ ecc_data[14] ^ ecc_data[13] ^ ecc_data[12] ^ ecc_data[7] ^ ecc_data[6] ^ ecc_data[5] ^ ecc_data[4];
  assign CP6 = ecc_data[7] ^ ecc_data[6] ^ ecc_data[5] ^ ecc_data[4] ^ ecc_data[3] ^ ecc_data[2] ^ ecc_data[1] ^ ecc_data[0];
  assign CP7 = ecc_data[15] ^ ecc_data[14] ^ ecc_data[13] ^ ecc_data[12] ^ ecc_data[11] ^ ecc_data[10] ^ ecc_data[9] ^ ecc_data[8];
	       
  assign RP = CP6 ^ CP7;
  assign ecc_precalc = {CP7, CP6, CP5, CP4, CP3, CP2, CP1, CP0};

always @(posedge ahb3_hclk or negedge ahb3_hresetn)
  begin : b_counter_eccps
    if (!ahb3_hresetn) begin
      /*AUTORESET*/
      // Beginning of autoreset for uninitialized flops
      counter_eccps <= 16'h0;
      // End of automatics
    end else begin
      if (ecc_cnt_clear) begin
		counter_eccps <= eccps;
      end else if (ecc_cnt) begin
		counter_eccps <= counter_eccps - 1;
      end
    end
  end // block: b_counter_eccps

always @(posedge ahb3_hclk or negedge ahb3_hresetn)
  begin : b_ecc_column
    if (!ahb3_hresetn) begin
      /*AUTORESET*/
      // Beginning of autoreset for uninitialized flops
      ecc_column <= 8'h0;
      // End of automatics
    end else begin
      if (ecc_cnt_clear) begin
  		ecc_column <= 8'h0;
      end else if (ecc_cnt) begin
  		ecc_column <= ecc_column ^ ecc_precalc;
      end      
    end
  end // block: b_ecc_column


always @(posedge ahb3_hclk or negedge ahb3_hresetn)
  begin : b_ecc_raw1
    if (!ahb3_hresetn) begin
      /*AUTORESET*/
      // Beginning of autoreset for uninitialized flops
      ecc_raw1 <= 13'h0;
      // End of automatics
    end else begin
      if (ecc_cnt_clear) begin
  		ecc_raw1 <= 13'h0;
      end else if (ecc_cnt & RP) begin
  		ecc_raw1 <= ecc_raw1 ^ (eccps - counter_eccps);
      end      
    end
  end // block: b_ecc_raw1
  
always @(posedge ahb3_hclk or negedge ahb3_hresetn)
  begin : b_ecc_raw2
    if (!ahb3_hresetn) begin
      /*AUTORESET*/
      // Beginning of autoreset for uninitialized flops
      ecc_raw2 <= 13'h0;
      // End of automatics
    end else begin
      if (ecc_cnt_clear) begin
  		ecc_raw2 <= 13'h0;
      end else if (ecc_cnt & RP) begin
  		ecc_raw2 <= ecc_raw2 ^ ~(eccps - counter_eccps);
      end      
    end
  end // block: b_ecc_raw2

ecc_data[15:0]为需要进行校验的数据,若外部nand flash的I/O宽度为16位,那么ecc_data[15:0]全部有效,如果外部nand flash的I/O宽度为8位,那么ecc_data[15:0]只有低8位有效。CPx为每个字节列校验值,RP为每个字节行校验的值。ecc_cnt代表每次ecc_data数据有效表示位,counter_eccps为数据传输计数,当counter_eccps==0时,数据全部传输完成。

b_ecc_column是计算列校验过程,ecc_precalc为每个字节内部计算CP7~CP0,每次ecc_data数据有效时,与上一次ecc_precalc进行异或计算。当最后一个字节传输结束时,ecc_column中bit7代表CP7,bit6代表CP6,bit5代表CP5,bit4代表CP4,bit3代表CP3,bit2代表CP2,bit1代表CP1,bit0代表CP0。

b_ecc_raw1和b_ecc_raw2是计算行校验过程,eccps代表要传输的数据字节总数,counter_eccps为递减计数,得(eccps-counter_eccps)为第n(n<eccps)次传输,(eccps-counter_eccps)称为行索引。通过行校验规律得到:将行号编成二进制后从右往左,如果第一位是0,例如行号0,2,4,…,252,254就列入RP0;如果第一位是1,例如行号1,3,5,…,253,255就列入RP1,如果第二位是0,例如行号0,1,4,6,…,252,253就列入RP2;如果第二位是1,例如行号2,3,6,7,…,254,255就列入RP3,以此类推。

行号

0

1

2

3


252

253

254

255

二进制

0000

0001

0010

0011


11111100

11111101

11111110

11111111

因此可以得到:

RP0只计算行索引的Bit0为0的行,RP1只计算行索引的Bit0为1的行;

RP2只计算行索引的Bit1为0的行,RP3只计算行索引的Bit1为1的行; RP4只计算行索引的Bit2为0的行,RP5只计算行索引的Bit2为1的行; RP6只计算行索引的Bit3为0的行,RP7只计算行索引的Bit3为1的行; RP8只计算行索引的Bit4为0的行,RP9只计算行索引的Bit4为1的行; RP10只计算行索引的Bit5为0的行,RP11只计算行索引的Bit5为1的行; RP12只计算行索引的Bit6为0的行,RP13只计算行索引的Bit6为1的行; RP14只计算行索引的Bit7为0的行,RP15只计算行索引的Bit7为1的行; ...

ecc_cnt & RP作用为只判断每个字节RP为1的个数,和RP为0的字节没有关系。如果有偶数个1则,异或结果为0,如果有奇数个1则异或结果为1。因此b_ecc_raw1判断所有RP为1的行中,

属于RP1计算范围内的行有多少个由ecc_raw1的Bit 0指示,0表示有偶数个,1表示有奇数个;

属于RP3计算范围内的行有多少个由ecc_raw1的Bit 1指示,0表示有偶数个,1表示有奇数个; 属于RP5计算范围内的行有多少个由ecc_raw1的Bit 2指示,0表示有偶数个,1表示有奇数个; 属于RP7计算范围内的行有多少个由ecc_raw1的Bit 3指示,0表示有偶数个,1表示有奇数个; 属于RP9计算范围内的行有多少个由ecc_raw1的Bit 4指示,0表示有偶数个,1表示有奇数个; 属于RP11计算范围内的行有多少个由ecc_raw1的Bit 5指示,0表示有偶数个,1表示有奇数个; 属于RP13计算范围内的行有多少个由ecc_raw1的Bit 6指示,0表示有偶数个,1表示有奇数个; 属于RP15计算范围内的行有多少个由ecc_raw1的Bit 7指示,0表示有偶数个,1表示有奇数个; ...

b_ecc_raw2判断所有RP为1的行中,

属于RP0计算范围内的行有多少个由ecc_raw2的Bit 0指示,0表示有偶数个,1表示有奇数个;

属于RP2计算范围内的行有多少个由ecc_raw2的Bit 1指示,0表示有偶数个,1表示有奇数个; 属于RP4计算范围内的行有多少个由ecc_raw2的Bit 2指示,0表示有偶数个,1表示有奇数个; 属于RP6计算范围内的行有多少个由ecc_raw2的Bit 3指示,0表示有偶数个,1表示有奇数个; 属于RP8计算范围内的行有多少个由ecc_raw2的Bit 4指示,0表示有偶数个,1表示有奇数个; 属于RP10计算范围内的行有多少个由ecc_raw2的Bit 5指示,0表示有偶数个,1表示有奇数个; 属于RP12计算范围内的行有多少个由ecc_raw2的Bit 6指示,0表示有偶数个,1表示有奇数个; 属于RP14计算范围内的行有多少个由ecc_raw2的Bit 7指示,0表示有偶数个,1表示有奇数个; ...

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

RP25

RP24

RP23

RP22

RP21

RP20

RP19

RP18

RP17

RP16

RP15

RP14

RP13

RP12

RP11

RP10

raw1[12]

raw2[12]

raw1[11]

raw2[11]

raw1[10]

raw2[10]

raw1[9]

raw2[9]

raw1[8]

raw2[8]

raw1[7]

raw1[7]

raw1[6]

raw2[6]

raw1[5]

raw2[5]

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

RP9

RP8

RP7

RP6

RP5

RP4

RP3

RP2

RP1

RP0

CP5

CP4

CP3

CP2

CP1

CP0

raw1[4]

raw2[4]

raw1[3]

raw2[3]

raw1[2]

raw2[2]

raw1[1]

raw2[1]

raw1[0]

raw1[0]

column[5]

column[4]

column[3]

column[2]

column[1]

column[0]

上表所示为当外部nand flash的I/O宽度为8bit时,eccr寄存器中校验位放置顺序,其中raw1为ecc_raw1,raw2为ecc_raw2,column为ecc_column。

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

RP23

RP22

RP21

RP20

RP19

RP18

RP17

RP16

RP15

RP14

RP13

RP12

RP11

RP10

RP9

RP8

raw1[11]

raw2[11]

raw1[10]

raw2[10]

raw1[9]

raw2[9]

raw1[8]

raw2[8]

raw1[7]

raw2[7]

raw1[6]

raw1[6]

raw1[5]

raw2[5]

raw1[4]

raw2[4]

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

RP7

RP6

RP5

RP4

RP3

RP2

RP1

RP0

CP7

CP6

CP5

CP4

CP3

CP2

CP1

CP0

raw1[3]

raw2[3]

raw1[2]

raw2[2]

raw1[1]

raw2[1]

raw1[0]

raw2[0]

column[7]

column[6]

column[5]

column[4]

column[3]

column[2]

column[1]

column[0]

上表所示为当外部nand flash的I/O宽度为16bit时,eccr寄存器中校验位放置顺序,其中raw1为ecc_raw1,raw2为ecc_raw2,column为ecc_column。