GD5F页读回归主线单发令(settle与二次发令移除、3.1V误判更正归一Trap05)、新增Phase11复现用例(16轮零复现)、附台架环境与审计文档

This commit is contained in:
2026-09-21 16:55:05 +08:00
parent f86cb8824b
commit ee206ab688
11 changed files with 965 additions and 145 deletions
+2
View File
@@ -20,6 +20,7 @@
* Phase 8 | FTL 层(nand_ftl_init / nand_ftl_format)
* Phase 9 | FatFS diskio(可选)
* Phase 10 | 边界条件(offset 越界 / size=0 / 未擦除写入 / 写保护解除)
* Phase 11 | 13h 锁存 / WIP 提前清零对照复现(编程擦除风暴 + 立即读比对,2026-09-21)
*/
#ifndef GD5F_TEST_H
@@ -48,6 +49,7 @@ extern "C" {
//#define ENABLE_GD5F_PHASE8_TESTS
//#define ENABLE_GD5F_PHASE9_TESTS
//#define ENABLE_GD5F_PHASE10_TESTS
//#define ENABLE_GD5F_PHASE11_TESTS /* 13h 锁存复现(仅擦写最高一块,独立门控,可随时启用) */
/* ======================== 测试统计与断言 ======================== */
+148
View File
@@ -785,6 +785,151 @@ static void gd5f_phase10(void)
}
#endif /* ENABLE_GD5F_PHASE10_TESTS */
/* -------------------------------------------------------------------
* Phase 11 — 13h 锁存 / WIP 提前清零对照复现(2026-09-21 台架实验)
*
* 复现对象 = 09-20 两项读异常(归因/证伪史实见 GD5F Trap_Records
* Trap 05,本用例只承担复现职能):
* H1: 编程/擦除风暴后 13h 命令未被锁存(空操作)→ 0Bh 读残留缓存
* H2: WIP 早于 array→cache 整页装载完成而清零 → 0Bh 读混合页
* 设计:
* 每轮:擦块 → 64 页背靠背编程(风暴,每页唯一图案)→ 立即(零间隔,
* 最坏时序)13h 读 3 个非相邻页并逐字节比对。
* 读目标刻意避开最后编程的页(页 63):若 13h 为空操作,残留缓存即
* 最后一次编程的数据,读页 63 会巧合一致而掩盖故障;读其他页时,
* 空操作(整页陈旧 = 页 63 图案)与提前清零(前段新后段旧)都会
* 表现为不一致。
* 对照组:延迟 50ms 后重读同 3 页——立即读失败而延迟读成功 = 时间窗型故障。
* 首次失败时记录页头/尾 4B,用于区分 H1 / H2 签名。
* 影响面:仅擦写最高一块(gd5f_find_run(1) 取最高好块,远离 FTL 活跃区);
* 不写 BBT、不格式化卷。
* ------------------------------------------------------------------- */
#ifdef ENABLE_GD5F_PHASE11_TESTS
#define GD5F_P11_ROUNDS 16
static const uint32_t s_p11_probe[3] = {0, 21, 43};
static void gd5f_phase11(void)
{
uint32_t blk;
uint32_t page0;
int32_t round, pi, p, i;
int32_t ret;
int32_t storm_fail = 0;
int32_t imm_fail = 0, ctl_fail = 0;
int32_t imm_bad = 0, ctl_bad = 0;
int32_t first_bad = -1;
blk = gd5f_find_run(1);
if (blk >= GD5F_TOTAL_BLOCKS) {
GD5F_TEST_CHECK(0, "TC-GD5F-1100 no usable block for repro");
GD5F_TEST_REPORT("GD5F Phase 11");
return;
}
page0 = blk * GD5F_PAGES_PER_BLOCK;
DBG_INFO("=== GD5F Phase 11: 13h latch / WIP repro (%d rounds, block %u) ===",
GD5F_P11_ROUNDS, (unsigned)blk);
for (round = 1; round <= GD5F_P11_ROUNDS; round++) {
int32_t round_bad = 0;
/* 风暴:擦除 + 64 页背靠背编程(图案 = i ^ p*0x11 ^ round*0x37) */
if (gd5f_block_erase(blk) != GD5F_OK) {
storm_fail++;
}
for (p = 0; p < GD5F_PAGES_PER_BLOCK; p++) {
for (i = 0; i < GD5F_PAGE_SIZE; i++) {
s_wbuf[i] = (uint8_t)(i ^ (p * 0x11) ^ (round * 0x37));
}
gd5f_write_enable();
if (gd5f_program_load(0, s_wbuf, GD5F_PAGE_SIZE) != GD5F_OK ||
gd5f_program_exec(page0 + (uint32_t)p) != GD5F_OK) {
storm_fail++;
}
}
/* 立即读(零间隔、最坏时序):3 个非相邻页逐字节比对 */
for (pi = 0; pi < 3; pi++) {
int32_t ok = 1;
uint8_t want;
ret = gd5f_page_read(page0 + s_p11_probe[pi]);
if (ret != GD5F_OK) {
ok = 0;
}
memset(s_rbuf, 0, GD5F_PAGE_SIZE);
if (gd5f_read_from_cache(0, s_rbuf, GD5F_PAGE_SIZE) != GD5F_OK) {
ok = 0;
}
for (i = 0; ok && i < GD5F_PAGE_SIZE; i++) {
want = (uint8_t)(i ^ (s_p11_probe[pi] * 0x11) ^ (round * 0x37));
if (s_rbuf[i] != want) {
ok = 0;
}
}
if (!ok) {
imm_fail++;
round_bad = 1;
if (first_bad < 0) {
first_bad = round;
DBG_INFO("TC-GD5F-1101 r=%d p=%u IMM mismatch head=%02X %02X %02X %02X "
"tail=%02X %02X %02X %02X",
round, (unsigned)s_p11_probe[pi],
s_rbuf[0], s_rbuf[1], s_rbuf[2], s_rbuf[3],
s_rbuf[GD5F_PAGE_SIZE - 4], s_rbuf[GD5F_PAGE_SIZE - 3],
s_rbuf[GD5F_PAGE_SIZE - 2], s_rbuf[GD5F_PAGE_SIZE - 1]);
}
}
}
/* 对照组:延迟 50ms 后重读同 3 页(区分时间窗型故障) */
HAL_Delay(50);
for (pi = 0; pi < 3; pi++) {
int32_t ok = 1;
uint8_t want;
ret = gd5f_page_read(page0 + s_p11_probe[pi]);
if (ret != GD5F_OK) {
ok = 0;
}
memset(s_rbuf, 0, GD5F_PAGE_SIZE);
if (gd5f_read_from_cache(0, s_rbuf, GD5F_PAGE_SIZE) != GD5F_OK) {
ok = 0;
}
for (i = 0; ok && i < GD5F_PAGE_SIZE; i++) {
want = (uint8_t)(i ^ (s_p11_probe[pi] * 0x11) ^ (round * 0x37));
if (s_rbuf[i] != want) {
ok = 0;
}
}
if (!ok) {
ctl_fail++;
ctl_bad = 1;
}
}
if (round_bad) {
imm_bad++;
}
if (round == 1 || (round & 3) == 0) {
DBG_INFO("TC-GD5F-1101 progress r=%d/%d storm_fail=%d imm_fail=%d ctl_fail=%d",
round, GD5F_P11_ROUNDS, storm_fail, imm_fail, ctl_fail);
}
}
GD5F_TEST_CHECK(storm_fail == 0,
"TC-GD5F-1100 storm ops: erase/program all OK (fail=%d)", storm_fail);
GD5F_TEST_CHECK(imm_bad == 0,
"TC-GD5F-1101 immediate read after storm: %d/%d bad rounds (pages=%d first=%d)",
imm_bad, GD5F_P11_ROUNDS, imm_fail, first_bad);
GD5F_TEST_CHECK(ctl_fail == 0,
"TC-GD5F-1102 delayed(50ms) read: %d/%d bad rounds (pages=%d)",
ctl_bad, GD5F_P11_ROUNDS, ctl_fail);
GD5F_TEST_REPORT("GD5F Phase 11");
}
#endif /* ENABLE_GD5F_PHASE11_TESTS */
/* -------------------------------------------------------------------
* 入口:按启用的阶段顺序执行并汇总
* ------------------------------------------------------------------- */
@@ -829,6 +974,9 @@ void gd5f_test_run(void)
#ifdef ENABLE_GD5F_PHASE10_TESTS
gd5f_phase10();
#endif
#ifdef ENABLE_GD5F_PHASE11_TESTS
gd5f_phase11();
#endif
GD5F_TEST_REPORT("GD5F2GQ5UE Tests");
DBG_INFO("########## GD5F2GQ5UE Test Done ##########");
+1
View File
@@ -66,6 +66,7 @@ extern "C" {
#define ENABLE_GD5F_PHASE2_TESTS /* BBT 读取与 RAM 内标记(206/207 落盘另受门控) */
#define ENABLE_GD5F_PHASE7_TESTS /* DMA 边界与守卫(701~703/705 写擦受门控;704 只读,日常回归亦跑) */
#define ENABLE_GD5F_PHASE10_TESTS /* 越界与 size=0 参数校验(1003/1004 写入另受门控) */
//#define ENABLE_GD5F_PHASE11_TESTS /* 13h 锁存复现实验(2026-09-21 已完成:16 轮×48 读零复现;仅擦写最高一块,可随时重开) */
#ifdef ENABLE_DESTRUCTIVE_TESTS
/* --- 破坏性阶段:写/擦页与块、格式化、FatFS 写入 --- */