📄 ddr.c
字号:
//功能:根据已经正确读到内存的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 + -