Chinaunix首页 | 论坛 | 博客
  • 博客访问: 70852
  • 博文数量: 9
  • 博客积分: 1459
  • 博客等级: 上尉
  • 技术积分: 112
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-22 08:46
文章分类

全部博文(9)

文章存档

2011年(1)

2008年(8)

我的朋友

分类: LINUX

2008-07-02 11:20:45

文件: NAND_ECC_Algoritalm.PDF
大小: 166KB
下载: 下载
首先感谢www.mcuos.comwonder sky对我的指导.本帖主要是对话记录.

代码中的ECC_CODE顺序和文中的ECC图示并不相同,
代码中的ECC_CODE[0]对应的是P1024~P128',
ECC_CODE[1]
对应的是P64~P8'

检验代码如下:
#include
#include

typedef  unsigned char u_char;

u_char ecc_code[3];

u_char nand_ecc_precalc_table[] =
{
    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
    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,
    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
    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,
    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
    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,
    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
};

void nand_trans_result(u_char reg2,u_char reg3,u_char *ecc_code)
{
    u_char a,b,i,tmp1,tmp2;
    a=b=0x80;
    tmp1=tmp2=0;
    for(i = 0;i < 4;i++)
    {
        if(reg3&a)
            tmp1|=b;
        b>>=1;
        if(reg2&a)
            tmp1|=b;
        b>>=1;
        a>>=1;
    }

    b=0x80;
    for(i = 0;i < 4;i++)
    {
        if(reg3&a)
            tmp2|=b;
        b>>=1;
        if(reg2&a)
            tmp2|=b;
        b>>=1;
        a>>=1;
    }

    ecc_code[0]=tmp1;
    ecc_code[1]=tmp2;

}

void nand_calculate_ecc(u_char *dat,u_char*ecc_code)
{
    u_char idx,reg1,reg2,reg3;
    int j;
    reg1=reg2=reg3=0;
    ecc_code[0]=ecc_code[1]=ecc_code[2]=0;
    for(j=0;j<256;j++)
    {
        idx=nand_ecc_precalc_table[dat[j]];
        reg1^=(idx&0x3f);
        if(idx&0x40)
        {
            reg3^=(u_char)j;
            reg2 ^=~((u_char)j);
        }
    }
    ecc_code[2]=reg1;
    nand_trans_result(reg2,reg3,ecc_code);
    cout<<"Org_Cal -> Ecc_code are :\n"
        <<(int)ecc_code[0]<        <<(int)ecc_code[1]<        <<(int)ecc_code[2]<   
}

void hard_cal(u_char *dat,u_char*ecc_code)
{
    u_char idx,reg1,reg2,reg3;
    int j;
    reg1=reg2=reg3=0;
    ecc_code[0]=ecc_code[1]=ecc_code[2]=0;
    for(j=0;j<256;j++)
    {
        idx=nand_ecc_precalc_table[dat[j]];
        reg1^=(idx&0x3f);
    }
    ecc_code[2]=reg1;
    u_char cal1=0,cal2=0;
    int    Move=0,count=1;

    while(count<=128)
    {
        int i=0;
        cal1=0;
        cal2=0;
        while(i<256)
        {
            for(int j=0;j            {
                if(nand_ecc_precalc_table[dat[i+j]]&0x40)
                    cal1^=1;//P'
                if(nand_ecc_precalc_table[dat[i+count+j]]&0x40)
                    cal2^=1;//P
            }
            i+=2*count;
        }
        if(Move<8)
        {
            ecc_code[0]|=cal1<<(Move);
            ecc_code[0]|=cal2<<(Move+1);
        }
        else
        {
            ecc_code[1]|=cal1<<(Move-8);
            ecc_code[1]|=cal2<<((Move-8)+1);
        }
        count*=2;
        Move+=2;
    }

    cout<<"hard cal -> Ecc_code are :\n"
        <<(int)ecc_code[0]<        <<(int)ecc_code[1]<        <<(int)ecc_code[2]<}


/*
ECC_CODE[0]
实际保存的是高位的P1024,P1024',P512,P512',P256,P256',P128,P128'
ECC_CODE[1]
保存的是
P64,P64',P32,P32',P16,P16',P8,P8'
*/
int main()
{
    u_char dat[256];
    for(int i=0;i<256;i++)
        dat
= rand()%256;
    hard_cal(dat,ecc_code);
    nand_calculate_ecc(dat,ecc_code);
    return 1;
}

VC6下编译通过,其中的hard_cal是按照图示的顺序摆放ECC,按照定义来进行计算的,结果两者的ECC_CODE颠倒,可以证明之前的结论正确。


这样的Reg3中从高位到地位摆放的是P1024~P8的值。
为什么这些位的值可以表示P1024~P8的值呢,看看之前的
if(idx&0x40)
{
    reg3^=(u_char)j;
    reg2 ^=~((u_char)j);
}

idx&0x40
,因为行校验初始为0,所以只有在idx&0x40=1的情况,即某行的行校验为1的时候,进行异或才能使行校验的值发生改变。
reg3^=(u_char)j
,这句代码可以记住这些行校验的值,
首先,81632……1024对应的字节数为1,2,4……128
对于P8,进行计算的行号为135……,即所有的奇数号,这些数字的二进制表示的特征是第一位一定为1
对于P16,计算的行号为2367……,这些数字的二机制表示的特征是第二位一定为1
以此类推,每个行校验的P都有一个对应的二进制位,暂时叫做特征位吧,
结合前面所说的某行的行校验为1的时候,进行异或才能使行校验的值发生改变
可以得到reg3各位就是对应的行校验。

 

reg3保存的是p1024  ~ p8 的值
reg2
保存的是p1024' ~ p8'的值

j
是原始data的下标,也就是原始数据的行号,reg3 ^= (uchar) j;取的就是第几行的如果2,3行对应的是P16那么 2,3取反 就是0,1 也就是P16' 呵呵,非常感谢了,经过你耐心指导~算法这块儿是明白一些了. 然后对照1BIT校验的其他的yaffs_eccwince ecc都是一样的.

然后在其余的一些时间里,看了S3C2410A的手册(中文第6)关于nandflash控制器后,它的硬件ECC512b校验1,3个字节, wince ecc是硬件ECC 算法是判断那几种情况就可以,linux ecc要简单些.揭过不提
.
nand_ecc
yaffs_ecc 从根本上就是一样的(个人认为)


阅读(3155) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~