1. 完善Flash读取页映射
This commit is contained in:
parent
f0d6e3547c
commit
7b24684f06
@ -31,7 +31,7 @@ typedef struct HFlashMemCache
|
||||
uint16_t offset; ///< 内存偏移
|
||||
uint16_t eraseStatus : 2; ///< 擦除状态
|
||||
uint16_t isDirty : 1; ///< 是否脏页
|
||||
uint16_t heat : 4; ///< 热度优先级
|
||||
uint16_t heat : 5; ///< 热度优先级
|
||||
} HFlashMemCache;
|
||||
|
||||
///< 内存操作, 回调返回0表示失败
|
||||
|
||||
226
src/HFlashMem.c
226
src/HFlashMem.c
@ -7,17 +7,27 @@
|
||||
#ifdef USE_STD_MEM
|
||||
#define FATAL_ERROR(format, ...) LogE(format, ##__VA_ARGS__);
|
||||
#else
|
||||
#define FATAL_ERROR(format, ...) while (1) { LogE(format, ##__VA_ARGS__); };
|
||||
#include "HShellLex.h"
|
||||
#define FATAL_ERROR(format, ...) while (1) { LogE(format, ##__VA_ARGS__); HShellRun(); };
|
||||
#endif
|
||||
|
||||
// flash块大小
|
||||
#define HFLASH_BLOCK_SIZE (4096)
|
||||
|
||||
// 调度热度时间
|
||||
#define HEAT_TIME_MS (1000)
|
||||
|
||||
// 是否对齐页
|
||||
#define IS_4K(size) ((size & (HFLASH_BLOCK_SIZE - 1)) == 0)
|
||||
|
||||
// 最大热度
|
||||
#define MAX_HEAT ((1 << 4) - 1)
|
||||
#define MAX_HEAT ((1 << 5) - 1)
|
||||
|
||||
// 写转读增加热度
|
||||
#define WRITE_CONV_READ_ADD_HEAT (2)
|
||||
|
||||
// 读最小热度
|
||||
#define READ_MIN_HEAT (0)
|
||||
|
||||
// 快速最小值
|
||||
#define FAST_MIN(type, a, b) ((b) ^ (((a) ^ (b)) & (-(type)((a) < (b)))))
|
||||
@ -31,6 +41,7 @@ enum eErase
|
||||
|
||||
struct Info
|
||||
{
|
||||
uint32_t currHeatTime; ///< 当前热度时间, 用于计算下一次热度下降
|
||||
uint16_t useNum; ///< 缓存已使用数量
|
||||
uint16_t needWaitErase : 1; ///< 用于判断是否在擦除
|
||||
};
|
||||
@ -83,6 +94,9 @@ static void SyncCache()
|
||||
sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE);
|
||||
sOpts->cache[i].isDirty = 0;
|
||||
sOpts->cache[i].eraseStatus = kEraseWait;
|
||||
|
||||
// 写入页转换空闲页, 热度持续增加
|
||||
sOpts->cache[i].heat = FAST_MIN(uint8_t, sOpts->cache[i].heat + WRITE_CONV_READ_ADD_HEAT, MAX_HEAT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +125,7 @@ static void CheckSyncCache()
|
||||
waitWrite |= sOpts->cache[i].isDirty;
|
||||
// 寻找需要擦除的页
|
||||
if (sOpts->cache[i].isDirty && sOpts->cache[i].eraseStatus == kEraseWait) {
|
||||
// 查找最低热度的优先擦除
|
||||
// 查找最低热度的优先擦除, 方便低热度页转换空闲
|
||||
if (sOpts->cache[i].heat <= heat) {
|
||||
heat = sOpts->cache[i].heat;
|
||||
needErase = i;
|
||||
@ -131,6 +145,9 @@ static void CheckSyncCache()
|
||||
sOpts->write(sOpts->cache[i].addr, GetMMap(i), HFLASH_BLOCK_SIZE);
|
||||
sOpts->cache[i].isDirty = 0;
|
||||
sOpts->cache[i].eraseStatus = kEraseWait;
|
||||
|
||||
// 写入页转换空闲页, 热度持续增加
|
||||
sOpts->cache[i].heat = FAST_MIN(uint8_t, sOpts->cache[i].heat + WRITE_CONV_READ_ADD_HEAT, MAX_HEAT);
|
||||
}
|
||||
|
||||
if (needErase != sInfo.useNum) {
|
||||
@ -157,7 +174,57 @@ static void StartSyncCache()
|
||||
sCheckTimer = HTimerAdd(HFLASH_TIMER_ID, 0, CheckSyncCache, kHTimerLoop);
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindCache(uint32_t addr, uint8_t create, uint8_t needRead)
|
||||
static void ScheduleHeat()
|
||||
{
|
||||
if (HDLogGetTime() - sInfo.currHeatTime < HEAT_TIME_MS) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].eraseStatus || sOpts->cache[i].isDirty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 仅对空闲页降温
|
||||
sOpts->cache[i].heat >>= 1;
|
||||
}
|
||||
|
||||
sInfo.currHeatTime = HDLogGetTime();
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindMinHeatCache()
|
||||
{
|
||||
int16_t index = -1;
|
||||
uint8_t minHeat = MAX_HEAT;
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].eraseStatus || sOpts->cache[i].isDirty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 寻找最小热度
|
||||
const uint8_t currHeat = sOpts->cache[i].heat;
|
||||
if (index == -1) {
|
||||
index = i;
|
||||
minHeat = currHeat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currHeat > minHeat) {
|
||||
continue;
|
||||
}
|
||||
|
||||
index = i;
|
||||
minHeat = currHeat;
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sOpts->cache + index;
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindReadCache(uint32_t addr, uint8_t needRead)
|
||||
{
|
||||
addr = Align4K(addr);
|
||||
if (addr + HFLASH_BLOCK_SIZE > sOpts->flashSize) {
|
||||
@ -174,10 +241,6 @@ static HFlashMemCache *FindCache(uint32_t addr, uint8_t create, uint8_t needRead
|
||||
return sOpts->cache + i;
|
||||
}
|
||||
|
||||
if (create == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 如果缓存没有满, 直接增加
|
||||
if (sInfo.useNum < sOpts->cacheSize) {
|
||||
const uint16_t index = sInfo.useNum;
|
||||
@ -197,31 +260,56 @@ static HFlashMemCache *FindCache(uint32_t addr, uint8_t create, uint8_t needRead
|
||||
return sOpts->cache + index;
|
||||
}
|
||||
|
||||
int16_t index = -1;
|
||||
uint8_t minHeat = MAX_HEAT;
|
||||
for (uint16_t i = 0; i < sInfo.useNum; ++i) {
|
||||
if (sOpts->cache[i].eraseStatus || sOpts->cache[i].isDirty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 寻找最小热度, 同时空闲的降低温度
|
||||
const uint8_t currHeat = sOpts->cache[i].heat;
|
||||
sOpts->cache[i].heat >>= 1;
|
||||
if (index == -1) {
|
||||
index = i;
|
||||
minHeat = currHeat;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currHeat > minHeat) {
|
||||
continue;
|
||||
}
|
||||
|
||||
index = i;
|
||||
minHeat = currHeat;
|
||||
// 查找空闲的最低热度页
|
||||
HFlashMemCache *cache = FindMinHeatCache();
|
||||
if (cache == NULL || cache->heat > READ_MIN_HEAT) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index != -1) {
|
||||
const uint16_t index = cache->offset;
|
||||
memset(cache, 0, sizeof(HFlashMemCache));
|
||||
cache->addr = addr;
|
||||
cache->offset = index;
|
||||
cache->heat = READ_MIN_HEAT;
|
||||
|
||||
if (needRead) {
|
||||
WatiErase();
|
||||
if (sOpts->read(addr, GetMMap(index), HFLASH_BLOCK_SIZE) == 0) {
|
||||
LogE("addr[0x%08x], read faild", addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static HFlashMemCache *FindWriteCache(uint32_t addr, uint8_t needRead)
|
||||
{
|
||||
addr = Align4K(addr);
|
||||
if (addr + HFLASH_BLOCK_SIZE > sOpts->flashSize) {
|
||||
LogE("flash addr[0x%08x] size[%d] overflow", addr, sOpts->flashSize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindReadCache(addr, needRead);
|
||||
if (cache) {
|
||||
return cache;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
// 写入模式下, 需要抢占缓存页
|
||||
cache = FindMinHeatCache();
|
||||
if (cache == NULL) {
|
||||
// 如果在创建模式下, 没有一个空闲的缓存, 就需要先同步脏页, 再获取一个
|
||||
HFlashMemSync();
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint16_t index = cache->offset;
|
||||
memset(cache, 0, sizeof(HFlashMemCache));
|
||||
cache->addr = addr;
|
||||
cache->offset = index;
|
||||
cache->heat = READ_MIN_HEAT;
|
||||
if (needRead) {
|
||||
WatiErase();
|
||||
// 找到一个空闲且最低温度的
|
||||
@ -231,22 +319,17 @@ static HFlashMemCache *FindCache(uint32_t addr, uint8_t create, uint8_t needRead
|
||||
}
|
||||
}
|
||||
|
||||
memset(sOpts->cache + index, 0, sizeof(HFlashMemCache));
|
||||
sOpts->cache[index].addr = addr;
|
||||
sOpts->cache[index].offset = index;
|
||||
return sOpts->cache + index;
|
||||
return cache;
|
||||
}
|
||||
|
||||
// 如果在创建模式下, 没有一个空闲的缓存, 就需要先同步脏页, 再获取一个
|
||||
HFlashMemSync();
|
||||
return FindCache(addr, create, needRead);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len, void (*cpCall)(void *dest, const void *src, uint32_t len, void *userData), void *userData)
|
||||
{
|
||||
uint32_t adjustAddr = Align4K(addr);
|
||||
HFlashMemCache *cache = FindCache(adjustAddr, 1, (addr != adjustAddr || len < HFLASH_BLOCK_SIZE));
|
||||
HFlashMemCache *cache = FindWriteCache(adjustAddr, (addr != adjustAddr || len < HFLASH_BLOCK_SIZE));
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], write len[%d] faild", addr, len);
|
||||
return 0;
|
||||
@ -268,7 +351,7 @@ static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len, void (*cp
|
||||
adjustAddr += HFLASH_BLOCK_SIZE;
|
||||
|
||||
for (; len >= HFLASH_BLOCK_SIZE; adjustAddr += HFLASH_BLOCK_SIZE, len -= HFLASH_BLOCK_SIZE, bufPtr += HFLASH_BLOCK_SIZE) {
|
||||
cache = FindCache(adjustAddr, 1, 0);
|
||||
cache = FindWriteCache(adjustAddr, 0);
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], write len[%d] faild", adjustAddr, len);
|
||||
return 0;
|
||||
@ -279,7 +362,7 @@ static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len, void (*cp
|
||||
}
|
||||
|
||||
if (len) {
|
||||
cache = FindCache(adjustAddr, 1, 1);
|
||||
cache = FindWriteCache(adjustAddr, 1);
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], write len[%d] faild", adjustAddr, len);
|
||||
return 0;
|
||||
@ -292,6 +375,52 @@ static uint8_t WriteData(uint32_t addr, const void *buf, uint32_t len, void (*cp
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 尽可能不拷贝数据, 如果存在缓存就读取缓存, 不存在就直接读取flash
|
||||
* @param addr Flash地址
|
||||
* @param buf 写入缓存
|
||||
* @param len 读取长度
|
||||
* @return
|
||||
*/
|
||||
static uint8_t FindReadPageCopy(uint32_t addr, void *buf, uint32_t len)
|
||||
{
|
||||
if (sOpts == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buf == NULL || len == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *p = (uint8_t *)buf;
|
||||
while (len > 0) {
|
||||
const uint32_t pageAddr = Align4K(addr);
|
||||
const uint32_t offset = addr - pageAddr;
|
||||
const uint32_t remain = HFLASH_BLOCK_SIZE - offset;
|
||||
const uint32_t copyLen = len > remain ? remain : len;
|
||||
if (pageAddr + HFLASH_BLOCK_SIZE > sOpts->flashSize) {
|
||||
LogE("flash addr[0x%08x] size[%d] overflow", pageAddr, sOpts->flashSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindReadCache(pageAddr, 1);
|
||||
if (cache) {
|
||||
memcpy(p, GetMMap(cache->offset) + offset, copyLen);
|
||||
} else {
|
||||
WatiErase();
|
||||
if (sOpts->read(addr, p, copyLen) == 0) {
|
||||
LogE("addr[0x%08x], read faild", addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
addr += copyLen;
|
||||
p += copyLen;
|
||||
len -= copyLen;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
void HFlashMemInit(HFlashMemOpts *opts)
|
||||
{
|
||||
sOpts = opts;
|
||||
@ -331,6 +460,7 @@ uint8_t HFlashMemRead(uint32_t addr, void *buf, uint32_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
uint8_t *p = (uint8_t *)buf;
|
||||
while (len > 0) {
|
||||
const uint32_t pageAddr = Align4K(addr);
|
||||
@ -342,7 +472,7 @@ uint8_t HFlashMemRead(uint32_t addr, void *buf, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
HFlashMemCache *cache = FindCache(pageAddr, 0, 1);
|
||||
HFlashMemCache *cache = FindReadCache(pageAddr, 1);
|
||||
if (cache) {
|
||||
memcpy(p, GetMMap(cache->offset) + offset, copyLen);
|
||||
} else {
|
||||
@ -377,6 +507,7 @@ uint8_t HFlashMemWrite(uint32_t addr, const void *buf, uint32_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
return WriteData(addr, buf, len, _MemCpyHelper, NULL);
|
||||
}
|
||||
|
||||
@ -392,13 +523,14 @@ uint8_t HFlashMemSetValue(uint32_t addr, uint8_t value, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
return WriteData(addr, NULL, len, _MemSetValueHelper, &value);
|
||||
}
|
||||
|
||||
static void _MemAddrCopy(void *dest, const void *src, uint32_t len, void *userData)
|
||||
{
|
||||
uint32_t srcAddr = *(uint32_t *)userData;
|
||||
HFlashMemRead(srcAddr + (long)src, dest, len);
|
||||
FindReadPageCopy(srcAddr + (long)src, dest, len);
|
||||
}
|
||||
|
||||
uint8_t HFlashMemAddrCopy(uint32_t srcAddr, uint32_t destAddr, uint32_t len)
|
||||
@ -407,6 +539,7 @@ uint8_t HFlashMemAddrCopy(uint32_t srcAddr, uint32_t destAddr, uint32_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
return WriteData(destAddr, NULL, len, _MemAddrCopy, &srcAddr);
|
||||
}
|
||||
|
||||
@ -416,6 +549,7 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScheduleHeat();
|
||||
uint32_t offset = 0;
|
||||
HFlashMemCache *cache = NULL;
|
||||
uint16_t len = 0;
|
||||
@ -423,7 +557,7 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
|
||||
// 先处理未对齐的部分
|
||||
if (addr != Align4K(addr)) {
|
||||
cache = FindCache(addr + offset, 1, 1);
|
||||
cache = FindWriteCache(addr + offset, 1);
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], find cache faild", addr);
|
||||
return 0;
|
||||
@ -440,7 +574,7 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
|
||||
// 剩余处理对齐部分
|
||||
while (result == 0) {
|
||||
cache = FindCache(addr + offset, 1, 1);
|
||||
cache = FindWriteCache(addr + offset, 1);
|
||||
if (cache == NULL) {
|
||||
LogE("addr[0x%08x], find cache faild", addr + offset);
|
||||
return 0;
|
||||
@ -459,6 +593,7 @@ uint8_t HFlashMemMMapCall(uint32_t addr, uint8_t(*call)(uint32_t addr, uint32_t
|
||||
|
||||
void HFlashMemSync()
|
||||
{
|
||||
ScheduleHeat();
|
||||
SyncCache();
|
||||
}
|
||||
|
||||
@ -466,5 +601,6 @@ void HFlashMemFreeCache()
|
||||
{
|
||||
HFlashMemSync();
|
||||
sInfo.useNum = 0;
|
||||
sInfo.currHeatTime = HDLogGetTime();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user