720f841494
登记簿 N-21(报告 N-12/N-13)与 N-24(报告 N-16)两项未闭环问题修复并销项。 N-12:dhara_nand_is_free() 旧实现只读页首 64 B 判全 0xFF,会把"页首 0xFF、后段有数据"的已编程页误判空闲,dhara 遂往已编程页再编程 = 位碰撞、 journal/map 指向垃圾且不报任何错。改整页扫描(栈上 64 B 分块、页首命中即 早退,故"已编程且页首有数据"的绝大多数页成本与旧实现同价)。 N-13:报告原建议经核对不成立——本仓裁剪版 dhara 既无 DHARA_NO_PAGE(哨兵 实为 DHARA_PAGE_NONE,journal.h:46)也无 DHARA_E_UNSUPPORTED(error.h 枚举 里没有,照抄直接编译失败),且 map.c 三处 dhara_journal_copy 调用点各自已 挡掉哨兵。真风险是移植层零上界校验:越界页号被芯片地址位截断成某个真实页 → 静默读写错页。改为六个 HAL 入口统一几何上界守卫 + DHARA_E_CORRUPT_MAP。 错误码选择是刻意的:BAD_BLOCK 会让 journal.c:904 标坏无辜好块,RECOVER 会 让 map.c:275 启动回收;无错误通道的 is_free/is_bad/mark_bad 一律取保守值。 N-16 写侧:一次排空合并成"每文件一次 open/write/close"(≤8 条 = 512 B 静态缓冲)。掉电语义不变——批次仍在同一次 drain 调用内 close,而 close 回写目录项这个不同 LPN 会把 FTL 单页写回缓存逼出到 NAND;失败尾部回投 队列,条目不丢(旧实现 -2 卷忙会直接丢掉那一条)。容量轮转仍只在按条慢 路径做,批量路径发现装不下一批就返回 -3 退回。 N-16 读侧:s_read_raw() 加 8 条滑动读窗口 + 写者代数失效,API 与 UI 零改动。 验证:@build 0 错 0 警(Code 213,540 / ER_IROM1 232,280 B = 22.2%, RW_IRAM1 75,232 B = 57.4%,ZI +1,640 B 全为静态缓冲、不吃任务栈); @test PASS,且台架 journal 恢复点与修复前同轨——连续四次启动 sectors used 恒 14,094、Map head 每轮 +128 单调推进、epoch 稳定 3 → 整页 is_free 未 改变恢复语义、无双编程、无回退;stack_report 9 个任务全 PASS(defaultTask 静态最坏链 3,024 B / 余 40%,实测峰值 2,164 B / 余 57%)。 新增主机侧移植层单测 test/host/nand_port/(第 16 个 -unit-test 钩子): RAM 假芯片 + 真实 dhara map/journal 源,149 断言,含"旧算法只看页首 64 B" 对照用例(将来有人把 is_free 改回去会立刻红)与 dhara 级 resume 双编程计数 为 0 的场景。L0.5 由 15 runner / 955 断言 → 16 runner / 1,104 断言。 文档:存储架构说明 §5.3 加移植层两条硬约束;运行与自检记录设计说明 §4.4/§4.5 写批量化与读窗口;GD5F Trap Records 新增 Trap 07(含三条遗留 代价与一条待办编译期断言);登记簿 N-21/N-24 删行销项并同步 README §1/§2.0/§2.1、排期详述 C3、报告 §0.1/§0.2/§0.4/§4.x/§7 与去处表; 钩子计数 33→34、主机侧单测 15→16 全库同步。
85 lines
3.4 KiB
C
85 lines
3.4 KiB
C
/*
|
||
* 主机侧单测桩:gd5f2gq5ue.h(GD5F2GQ5UE SPI NAND 驱动 API)
|
||
* 模块功能:为 Drivers/BSP/GD5F2GQ5UE/nand_ftl.c 提供**可在 PC 上编译链接**的
|
||
* 芯片几何常量与 SPI 原语声明;实现体(RAM 假芯片)在
|
||
* nand_port_test.c 里给出。
|
||
*
|
||
* ⚠ 仅供 test/host/nand_port/ 使用,不参与 MCU 构建。
|
||
* 真实头 Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h 会 `#include "main.h"` 拖入整套
|
||
* ST HAL / CMSIS(GPIO、SPI、HAL_GetTick),主机侧不引入。
|
||
*
|
||
* 保真点(与真实头逐项对齐,只有容量是刻意缩小的):
|
||
* - 几何常量 GD5F_PAGE_SIZE / GD5F_PAGES_PER_BLOCK / GD5F_BLOCK_SIZE /
|
||
* GD5F_SPARE_SIZE / GD5F_BBT_POOL_COUNT **同名同值**;
|
||
* - GD5F_TOTAL_BLOCKS 真实 2048(256 MB)→ 本桩 **32**(4 MB),
|
||
* 够跑 dhara map/journal 与全部越界用例;
|
||
* - 返回值 GD5F_OK / GD5F_ERROR / GD5F_PROGRAM_FAIL / GD5F_ERASE_FAIL 同值;
|
||
* - SPI 原语**签名逐字照抄**真实头(gd5f_page_read/gd5f_read_from_cache/
|
||
* gd5f_program_load/gd5f_program_exec/gd5f_block_erase/gd5f_check_ecc/
|
||
* gd5f_write_enable/gd5f_dma_buf_ok/gd5f_get_usable_blocks/
|
||
* gd5f2gq5ue_is_block_bad/gd5f2gq5ue_mark_block_bad),
|
||
* 桩与真实 API 一旦漂移,编译期即报错。
|
||
*
|
||
* 刻意**不搬**的部分:SPI 命令码 / 状态位 / 控制引脚宏 / DMA 窗口常量与
|
||
* 编译期守卫(nand_ftl.c 不使用它们;DMA 可达性在 PC 上没有物理意义,
|
||
* 由假芯片的 gd5f_dma_buf_ok 恒返 1 代替)。
|
||
*
|
||
* 创建日期:2026-10-15
|
||
*/
|
||
|
||
#ifndef GD5F2GQ5UE_H
|
||
#define GD5F2GQ5UE_H
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/* ======================== 芯片几何(与真实头同名同值,除总块数) ======================== */
|
||
|
||
#define GD5F_PAGE_SIZE 2048
|
||
#define GD5F_SPARE_SIZE 64
|
||
#define GD5F_TOTAL_PAGE_SIZE 2112
|
||
#define GD5F_PAGES_PER_BLOCK 64
|
||
#define GD5F_BLOCK_SIZE (GD5F_PAGES_PER_BLOCK * GD5F_PAGE_SIZE)
|
||
|
||
/* 真实 2048 块(256 MB)→ 假芯片 32 块(4 MB),见文件头说明 */
|
||
#define GD5F_TOTAL_BLOCKS 32
|
||
#define GD5F_TOTAL_SIZE (GD5F_TOTAL_BLOCKS * GD5F_BLOCK_SIZE)
|
||
|
||
/* 坏块表保留块池(真实头同值):dhara 可见块数 = 总块数 - 本值 */
|
||
#define GD5F_BBT_POOL_COUNT 4
|
||
|
||
/* ======================== 返回值(与真实头同值) ======================== */
|
||
|
||
#define GD5F_OK 0
|
||
#define GD5F_ERROR -1
|
||
#define GD5F_BUSY_TIMEOUT -2
|
||
#define GD5F_ECC_ERROR -3
|
||
#define GD5F_PROGRAM_FAIL -4
|
||
#define GD5F_ERASE_FAIL -5
|
||
#define GD5F_ID_MISMATCH -6
|
||
|
||
/* ======================== SPI 原语(签名逐字照抄真实头) ======================== */
|
||
|
||
int32_t gd5f_write_enable(void);
|
||
int32_t gd5f_page_read(uint32_t page_addr);
|
||
int32_t gd5f_read_from_cache(uint16_t column, uint8_t *p_buf, uint32_t size);
|
||
int32_t gd5f_program_load(uint16_t column, const uint8_t *p_buf, uint32_t size);
|
||
int32_t gd5f_program_exec(uint32_t page_addr);
|
||
int32_t gd5f_block_erase(uint32_t block_addr);
|
||
int32_t gd5f_check_ecc(void);
|
||
|
||
int32_t gd5f2gq5ue_is_block_bad(uint32_t block);
|
||
void gd5f2gq5ue_mark_block_bad(uint32_t block);
|
||
uint32_t gd5f_get_usable_blocks(void);
|
||
int gd5f_dma_buf_ok(const void *p_buf, size_t size);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* GD5F2GQ5UE_H */
|