1. 完善Flash读取页映射

This commit is contained in:
coffee 2025-12-30 17:06:51 +08:00
parent f0d6e3547c
commit 7b24684f06
2 changed files with 182 additions and 46 deletions

View File

@ -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表示失败

View File

@ -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();
}