From 7b24684f06838efbdd670a09137f5aa3dc03ba25 Mon Sep 17 00:00:00 2001 From: coffee Date: Tue, 30 Dec 2025 17:06:51 +0800 Subject: [PATCH] =?UTF-8?q?1.=20=E5=AE=8C=E5=96=84Flash=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E9=A1=B5=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/HFlashMem.h | 2 +- src/HFlashMem.c | 226 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 182 insertions(+), 46 deletions(-) diff --git a/include/HFlashMem.h b/include/HFlashMem.h index c253bb2..554e51b 100644 --- a/include/HFlashMem.h +++ b/include/HFlashMem.h @@ -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表示失败 diff --git a/src/HFlashMem.c b/src/HFlashMem.c index c41cf33..fc4adb7 100644 --- a/src/HFlashMem.c +++ b/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(); }