打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
ECC/EDC算法
ECC/EDC算法
 

理论:

4字节检错码EDC:

CD-ROM扇区中,有一个4字节共32位的EDC字域,它就是用来存放CRC码。

CD-ROM的CRC校验码生成多项式是32阶的,P(x) = (x16+x15+x2+1)(x16+x2+x+1)。

计算CRC码时用的数据块是从扇区的开头到用户数据区结束为止的数据字节,以Mode1为例,

即字节0—2063共2064个字节。将数据加上4个字节0,然后除多项式,得到的余数为校验码。

在EDC中存放的CRC码的次序如下:

EDC: x24-x31 x16-x23 x8-x15 x0-x7
字节号: 2064 2065 2066 2067

 

 

276字节纠错码ECC:

CD-ROM中的数据、地址、校验码等都可以看成是属于GF(2m) = GF(28)中的元素或称符号。

GF(28)表示域中有256个元素,除0,1之外的254个元素由本原多项式P(x)生成。

CD-ROM用来构造GF(28)域的P(x)是:P(x)=X8+X4+X3+X2+1。

而GF(28)域中的本原元素为:α = (0 0 0 0 0 0 1 0)。

按ISO/IEC10149的规定,CD-ROM扇区中的ECC码采用GF(28)域上的RSPC码产生172个字节

的P校验符号和104个字节的Q校验符号。在每个扇区中,#12字节到#2075字节和ECC域中

#2076字节到#2351字节共2340个字节组成1170个字(word)。每个字s(n)由两个字节B组成,

一个称为最高有效位字节MSB,另一个叫做最低有效位字节LSB。第n个字由下面的字节组成,

s(n) = MSB[B(2n+13)]+LSB[B(2n+12)],其中n = 0,1,2,…,1169。

从#12字节开始到#2075字节共2064个字节组成的数据块排列成24×43的矩阵,如下所示:

                NP    
    0 1 2 3     41 42  
  0 000 0001 0002 0041 0042  
  1 0043 0044 0045 0084 0085 HEADER
  2 0086 0087 0088 0127 0128 +
    P       Q       用户数据
                   
MP 22 0946 0947 0948 0987 0988 部分辅助数据
  23 0989 0990 0991 1030 1031  
  24 1032 1033 1034       1073 1074 P-校验
  25 1075 1076 1077 1116 1117  
  26 1118 1119 1120 1143       Q-校验
  27 1144 1145 1146 1169        
    0 1 2 25      

(ISO /IEC1049)

 

矩阵中的元素是字。这个矩阵要把它想象成两个独立的矩阵才比较好理解和分析,

一个是由MSB字节组成的24×43矩阵,另一个是由LSB字节组成的24×43矩阵。

(1) P校验符号用(26,24)RS码产生

43列的每一列用矢量表示,记为Vp。每列有24个字节的数据再加2个字节的P校验字节,用下式表示:

Vp= s(43*0+Np)
s(43*1+Np)
s(43*2+Np)
s(....)
s(43*Mp+Np)
s(....)
s(43*22+Np)
s(43*23+Np)
s(43*24+Np)
s(43*25+Np)

 

其中:Np = 0,1,2,……,42; Mp = 0,1,2,……,25

s(43*24+Np)s(43*25+Np)是P校验字节。对这列字节计算得到的是两个P校验字节,称为P校验符号。

两个P校验字节加到24行和25行的对应列上,这样构成了一个26×43的矩阵,并且满足方程HP×Vp=0。

其中HP校验矩阵为

HP= 1 1 ...... 1 1 1
a25 a24 ...... a2 a1 1

 

(2) Q校验符号用(45,43)RS码产生

增加P校验字节之后得到了一个26×43矩阵,该矩阵按对角线元素重新排列后得到一个新的矩阵:

                  MQ    
    0 1 2     40 41 42 Q0 Q1
  0 0000 0044 0088 0642 0686 0730 1118 1144
  1 0043 0087 0131 0685 0729 0773 1119 1145
  2 0086 0130 0147 0728 0772 0816 1120 1146
  3 0129 0137 0217 0771 0815 0859 1121 1147
  4 0172 0216 0260 0814 0858 0902 1122 1148
                       
  22 0946 0990 1034 0470 0514 0558 1140 1166
NQ 23 0989 1033 1077 0513 0557 0601 1141 1167
  24 1032 1076 0002 0556 0600 0644 1142 1168
  25 1075 0001 0045 0599 0643 0687 1143 1169

 

每条对角线上的43个MSB字节和LSB字节组成的矢量记为VQVQ在26×43矩阵中变成行矢量。

第NQ行上的VQ矢量包含的字节如下:

VQ = s(44*0+43*NQ)
s(44*1+43*NQ)
s(44*2+43*NQ)
s(....)
s(44*MQ+43*NQ)
s(....)
s(44*41+43*NQ)
s(44*42+43*NQ)
s(43*26+NQ)
s(44*26+NQ)

其中:NQ = 0,1,2,…,25;MQ = 0,1,2,…,42

s(43*26+NQ)s(44*26+NQ)是Q校验字节。VQ中的(44*MQ+43*NQ)字节号运算结果要做mod(1118)运算。

用(45,43)RS码产生的两个Q校验字节放到对应VQ矢量的末端,并且满足下面的方程:HQ×VQ=0

其中HQ校验矩阵为

 

HQ= 1 1 ...... 1 1 1
a44 a43 ...... a2 a1 1

 

 

(26,24)RS码和(45,43)RS码可以纠正出现在任何一行和任何一列上的一个错误,并且能相当可靠地

检测出行、列中的多重错误。如果在一个阵列中出现多重错误,Reference Technology公司提供有一

种名叫Layered ECC的算法,它可以取消多重错误。它的核心思想是交替执行行纠错和列纠错。

ECC算法首先计算MSB矩阵和LSB矩阵中每一行的校正子Sri(i = 0,1,…,25),以及每一列的校正

Scj(j = 0,1,…,44)。因为用(45,43)RS码,所以每一个Sri和每一个Scj都有两个校正子分量。

如果Sri = 0,则说明第i行无错;如Scj = 0,说明第j行无错。

ECC算法首先纠正只有一个的错误的行。这些错误取消后就纠正只有一个的错误的。经过一次行列交

替纠错后,只剩下很少错误。再进行一次行列交替纠错后,就可以消除全部错误。

因为RS码纠错算法本身包含找错误的位置和错误值,而错误位置已经由校正子Sr(i-k)SriSr(i+m)

ScjSc(j+l)确定,所以只剩下求错误值的问题。这个问题在讨论RS码时已经解决。

对CD-ROM存储器的数据,经CIRC校正后可以使以字节做单位的误码率小于10-9,再经RSPC进行纠错后,

字节误码率可以小于10-13,这样就满足了计算机要求误码率小于10-12的要求。 

对于Mode1 EDC计算范围是从#0字节开始到#2063字节共2064字节。

对于Mode2 form1 EDC计算范围是从#16字节开始到#2071字节共2056字节。

对于Mode2 form2 EDC计算范围是从#16字节开始到第2347字节共2332字节。

ECC计算范围都是从#12字节开始到#2075字节共2064字节。

程序:

/* LUTs used for computing ECC/EDC */ static BYTE ecc_f_lut[256]; 
static BYTE ecc_b_lut[256]; 
static DWORD edc_lut[256]; /* Init routine */ 
static void eccedc_init(void) 
{ 
DWORD i, j, edc; for(i = 0; i < 256; i++) { j = (i << 1) ^ (i & 0x80 ? 0x11D : 0); 
ecc_f_lut[i] = j; 
ecc_b_lut[i ^ j] = i; 
edc = i; 
for(j = 0; j < 8; j++) edc = (edc >> 1) ^ (edc & 1 ? 0xD8018001 : 0); edc_lut[i] = edc; } } 
/***************************************************************************/ //Compute EDC for a block 
void edc_computeblock( const BYTE *src, WORD size, DWORD *dest )
{
   DWORD edc=0x00000000;
 while(size--) edc = (edc >> 8) ^ edc_lut[(edc ^ (*src++)) & 0xFF]; 
dest[0] = (edc >> 0) & 0xFF; 
dest[1] = (edc >> 8) & 0xFF;
 dest[2] = (edc >> 16) & 0xFF; 
dest[3] = (edc >> 24) & 0xFF; } 
/***************************************************************************/ // Compute ECC for a block (can do either P or Q) static 
void ecc_computeblock( BYTE *src, DWORD major_count, DWORD minor_count, DWORD major_mult, DWORD minor_inc, BYTE *dest) 
{
    DWORD size = major_count * minor_count; 
   DWORD major, minor; 
   for(major = 0; major < major_count; major++) 
   { 
      DWORD index = (major >> 1) * major_mult + (major & 1);
       BYTE ecc_a = 0; 
      BYTE ecc_b = 0;
      for(minor = 0; minor < minor_count; minor++) 
      { 
         BYTE temp = src[index]; 
         index += minor_inc;
         if(index >= size) index -= size; 
         ecc_a ^= temp; ecc_b ^= temp; 
         ecc_a = ecc_f_lut[ecc_a]; 
      } 
   ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b];
    dest[major ] = ecc_a;
    dest[major + major_count] = ecc_a ^ ecc_b; 
   } 
} 
// Generate ECC P and Q codes for a block static 
void ecc_generate( BYTE *sector, int zeroaddress) 
{ 
   BYTE address[4], i; /* Save the address and zero it out */ 
   if(zeroaddress)
    for(i = 0; i < 4; i++) 
     { 
      address[i] = sector[12 + i]; 
      sector[12 + i] = 0;
     } /* Compute ECC P code */ 
   ecc_computeblock(sector + 0xC, 86, 24, 2, 86, sector + 0x81C); 
   /* Compute ECC Q code */ 
   ecc_computeblock(sector + 0xC, 52, 43, 86, 88, sector + 0x8C8);
    /* Restore the address */ 
   if(zeroaddress)
    for(i = 0; i < 4; i++)
    sector[12 + i] = address[i]; 
}
 /***************************************************************************/ 
// Generate ECC/EDC information for a sector (must be 2352 = 0x930 bytes), Returns 0 on success 
void eccedc_generate(BYTE *sector, int type)
{ 
   DWORD i; 
   switch(type) 
   { 
      case 1: /* Mode 1 */ 
         edc_computeblock(sector + 0x00, 0x810, sector + 0x810); 
         /* Write out zero bytes */ 
         for(i = 0; i < 8; i++)
          sector[0x814 + i] = 0; 
         ecc_generate(sector, 0); break; 
      case 2: /* Mode 2 form 1 */ 
        edc_computeblock(sector + 0x10, 0x808, sector + 0x818);
        ecc_generate(sector, 1); break; 
     case 3: /* Mode 2 form 2 */ 
        edc_computeblock(sector + 0x10, 0x91C, sector + 0x92C); break; 
    } 
}
eccedc_init(void)
{
    DWORD i, j, edc;
    for(i = 0; i < 256; i++) 
   { 
      j = (i << 1) ^ (i & 0x80 ? 0x11D : 0);
      ecc_f_lut[i] = j;
      ecc_b_lut[i ^ j] = i; 
      edc = i; 
      for(j = 0; j < 8; j++) 
         edc = (edc >> 1) ^ (edc & 1 ? 0xD8018001 : 0); 
      edc_lut[i] = edc; 
   } 
} 
/***************************************************************************/ 
// Compute EDC for a block 
void edc_computeblock( const BYTE *src, WORD size, DWORD *dest )
{ 
   DWORD edc=0x00000000;
   while(size--) 
      edc = (edc >> 8) ^ edc_lut[(edc ^ (*src++)) & 0xFF];
   dest[0] = (edc >> 0) & 0xFF; dest[1] = (edc >> 8) & 0xFF;
   dest[2] = (edc >> 16) & 0xFF; dest[3] = (edc >> 24) & 0xFF; 
} 
/***************************************************************************/ 
// Compute ECC for a block (can do either P or Q) static 
void ecc_computeblock( BYTE *src, DWORD major_count, DWORD minor_count,
                       DWORD major_mult, DWORD minor_inc, BYTE *dest) 
{
    DWORD size = major_count * minor_count;
    DWORD major, minor; 
   for(major = 0; major < major_count; major++)
    { 
      DWORD index = (major >> 1) * major_mult + (major & 1); 
      BYTE ecc_a = 0; BYTE ecc_b = 0;
      for(minor = 0;minor < minor_count;  minor++) 
      {
          BYTE temp = src[index]; 
         index += minor_inc; 
         if(index >= size) 
            index -= size; ecc_a ^= temp;
         ecc_b ^= temp;
         ecc_a = ecc_f_lut[ecc_a]; 
      } 
      ecc_a = ecc_b_lut[ecc_f_lut[ecc_a] ^ ecc_b]; 
      dest[major ] = ecc_a; 
      dest[major + major_count] = ecc_a ^ ecc_b;
    } 
} 
// Generate ECC P and Q codes for a block static
 void ecc_generate( BYTE *sector, int zeroaddress) 
{ 
   BYTE address[4], i; /* Save the address and zero it out */
    if(zeroaddress) 
      for(i = 0; i < 4; i++) 
      { 
         address[i] = sector[12 + i]; 
         sector[12 + i] = 0; 
      } /* Compute ECC P code */ 
    ecc_computeblock(sector + 0xC, 86, 24, 2, 86, sector + 0x81C);
    /* Compute ECC Q code */ 
    ecc_computeblock(sector + 0xC, 52, 43, 86, 88, sector + 0x8C8); /* Restore the address */
    if(zeroaddress) 
      for(i = 0; i < 4; i++)
       sector[12 + i] = address[i];
 } 
/***************************************************************************/ 
// Generate ECC/EDC information for a sector (must be 2352 = 0x930 bytes), Returns 0 on success
void eccedc_generate(BYTE *sector, int type) 
{ 
   DWORD i; 
   switch(type) 
   { 
      case 1: /* Mode 1 */
          edc_computeblock(sector + 0x00, 0x810, sector + 0x810); 
         /* Write out zero bytes */ 
         for(i = 0; i < 8; i++) 
            sector[0x814 + i] = 0; 
         ecc_generate(sector, 0); break;
     case 2: /* Mode 2 form 1 */ 
         edc_computeblock(sector + 0x10, 0x808, sector + 0x818); 
         ecc_generate(sector, 1); break; 
     case 3: /* Mode 2 form 2 */
         edc_computeblock(sector + 0x10, 0x91C, sector + 0x92C); break; 
     } 
}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
/dev/flash
FAT32引导扇区代码(引导代码应该初始化以下寄存器)
【光盘刻录】让马赛克和爆音远离你的VCD、CD
Nand :oob,bbt,ecc
重装Win7后找回Ubuntu启动项并在Ubuntu中修复引导
更新中 EDC 2022
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服