tsb: drive each tier to its size floor

asm 502->498 B (below the oracle's 500): the stack bring-up moves to plain C++,
and a register is reserved for the config-page high byte instead of reloading it
at each app-flash-boundary compare. tricks 808->778 B: shared erase/rww helpers
plus the libavr half-duplex W1C fix. pure 950->896 B and no SRAM: streams
rx->SPM/EEPROM instead of staging a 128 B page buffer. All three keep full oracle
feature parity and stay byte-identical across modes; protocol tests (round-trip +
password + emergency erase) green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-19 18:47:38 +02:00
parent ac9447c07f
commit fc5433fd7d
4 changed files with 74 additions and 65 deletions

View File

@@ -118,16 +118,30 @@ const std::uint8_t *flash_ptr(std::uint16_t addr)
__builtin_unreachable();
}
// One flash page erased and waited out. Shared, so the SPM erase command
// sequence is emitted once for the whole-app erase, the config page and the
// emergency wipe rather than three times.
[[gnu::noinline]] void erase1(std::uint16_t addr)
{
spm::erase_page<off>(addr);
spm::wait();
}
// Re-enable RWW flash reads after programming, shared for the same reason.
[[gnu::noinline]] void rww()
{
spm::rww_enable<off>();
}
// Erase the whole application, one page at a time.
[[gnu::noinline]] void erase_application()
{
g_addr = 0;
do {
spm::erase_page<off>(g_addr);
spm::wait();
erase1(g_addr);
g_addr += page;
} while (g_addr < app_end);
spm::rww_enable<off>();
rww();
}
// 'f'/'e': stream memory back one page per host '!'. send advances g_addr, so
@@ -165,10 +179,9 @@ void write_config()
if (!request_confirm())
return;
g_addr = app_end;
spm::erase_page<off>(g_addr);
spm::wait();
erase1(g_addr);
store_page(true);
spm::rww_enable<off>();
rww();
g_addr = app_end;
g_cnt = page;
send(true);
@@ -182,9 +195,8 @@ void write_config()
do {
ee::write<off>(g_addr, 0xff);
} while (++g_addr <= eeprom_end);
spm::erase_page<off>(app_end);
spm::wait();
spm::rww_enable<off>();
erase1(app_end);
rww();
}
// The password gate. A byte of 0 requests emergency erase; a wrong byte hangs