⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ddr.c

📁 新一代基于事件的嵌入式操作系统dyos在三星的s3c44b0的arm芯片上的完整移植代码
💻 C
📖 第 1 页 / 共 5 页
字号:
//功能:根据已经正确读到内存的DDR_main,校验flash中的DDR_bak是否正确。校验中只要
//      发现一个字节不一致,就返回错误,接下来会重构DDR_bak。调用
//      本函数前,DBX_flash_tag中与DDR表相关的成员应该初始化好(除DBL_bak外)。
//      本函数没有对应的__DFFSD_verify_DDR_main函数,因为启动时如果需要读
//      DDR_bak,则DDR_main无需校验,肯定是有错误的。
//参数: DBX_flash_tag,被操作的文件柜,flash文件柜的专有数据结构指针
//返回:true=完全无错,flash中DDR表被读入到DBX_flash_tag中。
//      false=有错误,flash中DDR表有任何错误,__DFFSD_scan_DDR函数会调用
//      __DFFSD_rebuild_DDR_bak
//-----------------------------------------------------------------------------
bool_t __DFFSD_verify_DDR_bak(struct st_DBX_flash_tag *DBX_flash_tag)
{
    uint32_t block_no;      //DDR表的块号
    uint32_t DDR_blocks;    //DDR表占用的块数
    uint32_t loop,read_size;
    uint32_t offset = 0,completed = 0;
    uint32_t FDSB_start,ARB_start,ART_start,ART_end,MAT_start;
    uint32_t temp;
    struct MAT_table *MAT_item;
    struct flash_chip *chip = DBX_flash_tag->chip;  //获取文件柜对应的芯片
    uint32_t *DBL_buf;
    uint8_t attr;

    DDR_blocks = (DBX_flash_tag->DDR_size+chip->block_size-1)/chip->block_size;
    DBL_buf = DBX_flash_tag->DDR_DBL+DDR_blocks;   //取DBL_bak缓冲区指针
    DBL_buf[0] = DBX_flash_tag->DDR_bak;
    FDSB_start = DDR_blocks*4;
    ARB_start = FDSB_start + 4;
    ART_start = ARB_start +4;
    ART_end = ART_start + DBX_flash_tag->block_sum *2;
    MAT_start = __DFFSD_MAT_start(DBX_flash_tag);
    MAT_item = DBX_flash_tag->DDR_MAT;
    for(loop = 0; loop < DDR_blocks; loop++)  //从首块到末块循环
    {
        block_no = DBL_buf[loop] + DBX_flash_tag->start_block;
        if(loop == DDR_blocks-1)
            read_size = DBX_flash_tag->DDR_size - completed;
        else
            read_size = chip->block_size;
        if(chip->read_data_with_ecc(block_no,0,chip->block_buf,read_size)
                                    != read_size)
        {
            return false;   //读函数返回错误
        }else
        {
            while(offset - completed < read_size)
            {
                if(offset < FDSB_start)         //DBL
                {
                    DBL_buf[offset/4] = __pick_little_32bit(
                                        chip->block_buf+(offset-completed),0);
                    offset +=4;
                }else if(offset < ARB_start)  //FDSB
                {
                    temp = __pick_little_32bit(
                                        chip->block_buf+(offset-completed),0);
                    if(DBX_flash_tag->DDR_FDSB != temp)
                        return false;
                    offset +=4;
                }else if(offset < ART_start) //ARB
                {
                    temp = __pick_little_32bit(
                                        chip->block_buf+(offset-completed),0);
                    if(DBX_flash_tag->DDR_ARB != temp)
                        return false;
                    offset +=4;
                }else if(offset < ART_end)   //ART
                {
                    temp = __pick_little_16bit(
                                        chip->block_buf+(offset-completed),0);
                    if(DBX_flash_tag->ART_times[(offset-ART_start)/2]
                                != (uint16_t)temp)
                        return false;
                    offset +=2;
                }else if(offset < MAT_start)    //跳过对齐填充
                {
                    offset = MAT_start;
                }else if(offset < DBX_flash_tag->DDR_size)
                {

                    temp = __pick_little_32bit(
                                        chip->block_buf+(offset-completed),0);
                    attr = temp >>30;
                    //向前指针
                    if((temp & 0x3fffffff) != MAT_item->previous)
                        return false;
                    temp = __pick_little_32bit(
                                        chip->block_buf+(offset-completed),1);
                    attr += (temp >>30)<<2;
                    //向后指针
                    if((temp & 0x3fffffff) != MAT_item->next)
                        return false;
                    if(attr != MAT_item->attr)
                        return false;
                    offset +=8;
                    MAT_item++;
                }
            }
            completed += chip->block_size;
        }
    }
    return true;        //哈哈,如果有任何错误,函数走不到这里
}

//----读取一个文件柜的DDR表----------------------------------------------------
//功能: 读取一个文件柜的DDR表,并检测其有效性。先读DDR_main,如果有错误,就读
//      DDR_bak,若仍然错误,返回错误。读取一份正确的DDR表后,用这份正确的DDR表
//      校验另一份DDR表,如果发现错误,在DBX_flash_tag的writed数组中标记。
//      校验的算法太复杂,难于在此解释清楚,有专用文档说明。读取的数据保存在
//      DBX_flash_tag的DDR_mirror指针中,它是flash中DDR表的近似镜像。
//参数: DBX_flash_tag,被操作的文件柜,flash文件柜的专有数据结构指针
//返回: true=正确读取,false=错误
//备注: 内存有缓存,平时无须从flash中读取DDR,仅在文件柜尚未完成初始化时读DDR表用
//-----------------------------------------------------------------------------
bool_t __DFFSD_scan_DDR(struct st_DBX_flash_tag *DBX_flash_tag)
{
    if(__DFFSD_read_DDR(DBX_flash_tag,0) == true)  //先读DDR_main
    {
        //DDR_main正确读取,需校验DDR_bak是否一致,校验过程中可能产生修改
        //DDR_main的请求
        if(__DFFSD_verify_DDR_bak(DBX_flash_tag) == false);
            __DFFSD_rebuild_DDR_bak(DBX_flash_tag);   //重构DDR_bak
    }else if(__DFFSD_read_DDR(DBX_flash_tag,1) == true)
    {
        //执行到此DDR_main肯定有错,无需校验,直接重构就可以了
        __DFFSD_rebuild_DDR_main(DBX_flash_tag);
    }else
        return false;
    return true;
}

//----跳跃换区-----------------------------------------------------------------
//功能: 某块从一个磨损分区转移到另一个磨损分区
//参数: DBX_flash_tag,被操作的文件柜,flash文件柜的专有数据结构指针
//      from,原区号
//      to,目标区号
//      position,被移动的块的原始位置
//返回: 无
//特注: 调用方确保第from分区不是空的,也就是说,position是有效参数
//-----------------------------------------------------------------------------
void __DFFSD_ART_flip(struct st_DBX_flash_tag *DBX_flash_tag,
                         ufast_t from,ufast_t to,uint32_t position)
{
    uint32_t loop,block_position,block_no_temp;
    uint32_t *pos_tab,*block_no_tab;
    uint16_t *times_tab;
    uint32_t block_no,*balance_region;
    uint16_t times_bak;

    block_position = position;
    balance_region = DBX_flash_tag->balance_region;
    pos_tab = DBX_flash_tag->ART_position;          //磨损位置表
    block_no_tab = DBX_flash_tag->ART_block_no;     //磨损块号表,与次数表同列
    times_tab = DBX_flash_tag->ART_times;           //磨损次数表
    block_no = block_no_tab[position];
    times_bak = times_tab[block_position];          //被移动块的磨损次数

    if(to > from)       //向上跳跃
    {
        for(loop = from; loop < to; loop++)
        {
            if(balance_region[loop] == balance_region[loop+1])//第loop分区是空的
            {
                continue;
            }
            //取第loop分区的最后一个单元的块号(即在pos表中的偏移量)
            block_no_temp = block_no_tab[balance_region[loop+1]-1];
            //第loop分区最后一个单元的磨损次数copy到上次循环移空的单元
            times_tab[block_position] = times_tab[balance_region[loop+1]-1];
            //第loop分区最后一个单元的块号copy到上次循环移空的单元
            block_no_tab[block_position] = block_no_temp;
            //第loop分区第一个单元的位置表指向上次移空的单元号
            pos_tab[block_no_temp] = block_position;
            block_position = balance_region[loop+1]-1;    //本次清空的单元索引号
        }
        for(loop = to; loop > from; loop--)
            balance_region[loop]--;        //分区指针上移一格
    }else               //向下跳跃
    {
        for(loop = from; loop > to; loop--)
        {
            if(loop != from)//此条件很重要,因为如果loop=18的话,loop+1下标越限
            {
                if(balance_region[loop] == balance_region[loop+1])//第loop分区空
                {
                    continue;
                }
            }
            //取第loop分区第一个单元的块号(即在pos表中的偏移量)
            block_no_temp = block_no_tab[balance_region[loop]];
            //第loop分区第一个单元的磨损次数copy到上次循环移空的单元
            times_tab[block_position] = times_tab[balance_region[loop]];
            //第loop分区第一个单元的块号copy到上次循环移空的单元
            block_no_tab[block_position] = block_no_temp;
            //第loop分区第一个单元的位置表指向目标单元号
            pos_tab[block_no_temp] = block_position;
            block_position = balance_region[loop];    //本次清空的单元索引号
        }
        for(loop = from; loop > to; loop--)
            balance_region[loop]++;        //分区指针下移一格
    }
    //被移动块的擦除次数写到目标区最后(上移)或首(下移)单元
    times_tab[block_position] = times_bak;
    //被移动块的块号写到目标区ART_block_no表的最后(上移)或首(下移)单元
    block_no_tab[block_position] = block_no;
    //pos表的被移动块指针指向目标区表最后(上移)或首(下移)单元
    pos_tab[block_no] = block_position;
}

//----磨损平衡块交换----------------------------------------------------------
//功能:当磨损平衡表中出现严重失衡时,调用本函数,用busy[0]中的一块与free[8]中的
//      一块交换,把busy[0]拷贝到free[8]中成为busy[8],这样可以使“死”在busy中
//      的一块重新激活进入free[0]中待用,让free[8]中的一块到busy[8]中“睡”一会
//      儿。严重失衡的标准是:free[0~7]均空,而free[8]和busy[0]不空。
//参数: DBX_flash_tag,被操作的文件柜,flash文件柜的专有数据结构指针
//返回:true=成功交换一块到free[0],false=失败
//-----------------------------------------------------------------------------
bool_t __DFFSD_exchange_busy0_free8(struct st_DBX_flash_tag *DBX_flash_tag)
{
    uint32_t *busy_region,*free_region;
    uint32_t *pos_tab,*block_no_tab;
    uint16_t *times_tab,times_bak;
    uint32_t block_no_bak,block_no;
    uint32_t loop,invalid_num;
    struct flash_chip *chip = DBX_flash_tag->chip;  //取文件柜所属芯片
    pos_tab = DBX_flash_tag->ART_position;          //取磨损位置表
    block_no_tab = DBX_flash_tag->ART_block_no;     //取磨损块号表,与次数表同列
    times_tab = DBX_flash_tag->ART_times;           //取磨损次数表
    busy_region = &DBX_flash_tag->balance_region[9];    //第一个忙分区
    free_region = DBX_flash_tag->balance_region;        //第一个空闲分区

    //以下两句保存busy0.end条目的磨损次数和块号,
    times_bak = times_tab[busy_region[1]-1];
    block_no_bak = block_no_tab[busy_region[1]-1];
    block_no = DBX_flash_tag->start_block + block_no_bak;
    //读出busy0.end的内容
    chip->read_data_with_ecc(block_no,0,chip->block_buf,chip->block_size);
    //把busy0.end的内容写入到free8.0中,若写入不成功,则写入到free8.1,依次类推
    //直到成功。
    for(invalid_num=0;invalid_num < DBX_flash_tag->valid_sum;invalid_num++)
    {
        block_no = block_no_tab[free_region[8]+invalid_num];
        block_no += DBX_flash_tag->start_block;
        if(chip->write_data_with_ecc(block_no,0,chip->block_buf,
                                     chip->block_size) == chip->block_size)
        {
            break;  //正确写入,说明找到了一个好块,跳出循环
        }
    }
    //新产生坏块数量比可用块数量少,说明busy0.end已经正确写入到第
    //free_region[8]+invalid_num块中
    if(invalid_num < DBX_flash_tag->valid_sum)
    {
        for(loop = 1; loop < 8; loop++)
        {       //本循环将busy1~7整体下移一个条目,空出busy7.end
            busy_region[loop]--;        //busy_region[loop]指针下移一格
            if(busy_region[loop] == busy_region[loop-1])
                continue;       //第loop个busy分区是空的
            times_tab[busy_region[loop]] = times_tab[busy_region[loop+1]-1];
            block_no = block_no_tab[busy_region[loop+1]-1];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -