tsb: beat the first-pass size floors (tricks 666, pure 842)
tricks 778->666: always_inline every single-call handler into the [[noreturn]] reset entry (which pays no prologue, so their push/pop of call-saved registers vanishes), walk the page pointer in Y (adiw, base recovered as g_addr-page) instead of recomputing Z=base+offset, bring the UART up in the two registers that are not already at their reset value, and seed the activation counter as __uint24. pure 896->842: TU-local internal linkage (proper hygiene, and it lets the compiler inline the one-call handlers), a byte-wide activation count, __uint24 timeout. Still one readable function per command. asm unchanged at 498: its C++-expressible parts are already C++; the core stays asm (the 666 B all-tricks tier is 168 B over — per-call ABI tax, not a feature). All three cross-mode byte-identical, protocol green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ using serial_t = dev::uart0<{.baud = 115200_Bd, .max_baud_error = 3_pct, .half_d
|
||||
inline constexpr serial_t serial{};
|
||||
|
||||
namespace tsb {
|
||||
namespace {
|
||||
|
||||
// The loader is purely polled — it never enables interrupts — so every SPM and
|
||||
// EEPROM lock folds to nothing under this posture.
|
||||
@@ -80,13 +81,13 @@ const std::uint8_t *flash_ptr(std::uint16_t addr)
|
||||
}
|
||||
|
||||
// Stream `count` bytes to the host, from flash (LPM) or from EEPROM.
|
||||
void send_flash(std::uint16_t addr, std::uint16_t count)
|
||||
void send_flash(std::uint16_t addr, std::uint8_t count)
|
||||
{
|
||||
while (count--)
|
||||
tx(avr::flash_load(flash_ptr(addr++)));
|
||||
}
|
||||
|
||||
void send_eeprom(std::uint16_t addr, std::uint16_t count)
|
||||
void send_eeprom(std::uint16_t addr, std::uint8_t count)
|
||||
{
|
||||
while (count--)
|
||||
tx(ee::read(addr++));
|
||||
@@ -238,7 +239,7 @@ gate password_gate()
|
||||
// Activation: the host knocks three '@' inside a window whose length is the
|
||||
// config page's timeout byte (floored so a corrupt page can never lock the
|
||||
// loader out). An idle port times out and boots the application.
|
||||
std::uint32_t idle = static_cast<std::uint32_t>(avr::flash_load(flash_ptr(app_end + 2)) | 16) << 16;
|
||||
__uint24 idle = static_cast<__uint24>(avr::flash_load(flash_ptr(app_end + 2)) | 16) << 16;
|
||||
std::uint8_t knocks = 0;
|
||||
while (knocks < 3) {
|
||||
if (auto byte = serial.read())
|
||||
@@ -285,6 +286,7 @@ gate password_gate()
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tsb
|
||||
|
||||
// Reset lands here: BOOTRST vectors to the boot section base and .vectors is
|
||||
|
||||
Reference in New Issue
Block a user