The second pass concluded the 168 B tricks->asm gap was per-call ABI
cost. Most of it was structure. Rebuilt around the oracle's own shape —
argless noinline primitives over a whole-loader call-saved register
protocol (g_addr in Y, count r16, window r7, direction latch r6), a
top-down erase_below whose loop tests against zero and hands callers
g_addr = 0 for free, bounded rx everywhere (a silent host unwinds to
the app from any state, as the oracle does), and a named tsb_app entry
that --pmem-wrap-around=32k relaxes to the wrapped rjmp:
tsb_asm 510 B in the 512 B section (oracle: 500), C++ except rx
and the page-store loop — the two routines whose remaining
cost is the calling convention itself (~30 asm lines, was
~280)
tsb_tricks 526 B, no assembly at all (was 666)
tsb_pure 836 B, still one readable function per command (was 842)
Every g_* update placement works around a GCC 16.1 wrong-code bug
(stores into global register variables deleted when only callees read
them — repro and rules in libavr dev/lessons.md). Also fixes two
latent hardware bugs all earlier tiers carried, masked by simavr's
zeroed register file: the crt-less entries never established
__zero_reg__ = 0, and the direction latch was read before written —
power-on registers are undefined.
All tiers full oracle feature parity, protocol tests green in both
libavr modes, .text byte-identical across modes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
50 lines
2.5 KiB
Markdown
50 lines
2.5 KiB
Markdown
# Oracle — the hand-written TinySafeBoot assembly
|
||
|
||
`tsb-fixedbaud.asm` is the reference implementation this port is measured
|
||
against: the **native-UART, fixed-baud** TinySafeBoot bootloader, hand-written
|
||
in AVR assembly. It is the size-and-feature bar for the port's `tsb_asm` tier.
|
||
|
||
- **Source**: <https://github.com/seedrobotics/tinysafeboot>
|
||
(`firmware_ASM/latest_stable_release/20200727-fixedbaud/main.asm`), the Seed
|
||
Robotics fixed-baud fork of Julien Thomas' TinySafeBoot.
|
||
- **License**: GPLv3 (see the header in the file). It is vendored here **only as
|
||
a reference oracle** — it is not compiled, linked, or distributed as part of
|
||
the MIT-licensed port. Mere aggregation.
|
||
|
||
## Why this variant
|
||
|
||
The user chose the fixed-baud, hardware-UART variant deliberately: it is the one
|
||
whose feature set the port must match. It fits the **complete** TSB feature set
|
||
into the 512-byte ATmega boot section:
|
||
|
||
| Feature | Oracle routine |
|
||
|---|---|
|
||
| Watchdog-reset bail straight to the app | `RESET` (WDRF check) |
|
||
| One-wire half-duplex (RX/TX shorted): RXEN/TXEN toggled per direction, TX turnaround guard | `SetRX` / `SetTX` / `TransmitByte` |
|
||
| Activation timeout read from the config page, with a lockout-proof minimum | `WRX1To` (uses `utimeoutH`) |
|
||
| 3×`@` activation knock | `ActCharRcvd` |
|
||
| Password gate; wrong byte hangs (still draining the UART) | `CheckPassword` |
|
||
| Emergency erase on password `\0` + double-confirm — wipes flash, EEPROM and the config page | `EmergencyErase` |
|
||
| Device-info block (16 bytes) | `SendDeviceInfo` / `DEVICEINFO` |
|
||
| App-flash read/write (`f`/`F`), EEPROM read/write (`e`/`E`), config read/write (`c`/`C`) | `CheckCommands` |
|
||
|
||
## Assembled size (the bar)
|
||
|
||
Assembled for the ATmega328P with `avra`:
|
||
|
||
```
|
||
avra -I /usr/share/avra tsb-fixedbaud.asm # after uncommenting .include "m328Pdef.inc"
|
||
# Code : 250 words (500 bytes) — the whole loader, all features, in the 512 B section
|
||
```
|
||
|
||
**500 bytes with every feature** — the proof that ≤512 B and full feature parity
|
||
are simultaneously reachable. The port's `tsb_asm` tier meets the same bar at
|
||
510 B in the same 512 B section, written in C++ on libavr except the two
|
||
routines whose remaining cost is the calling convention itself (the bounded rx
|
||
and the page-store loop); `tsb_tricks` needs no assembly at all at 526 B, and
|
||
`tsb_pure` stays fully idiomatic at 836 B, both in the 1 KB section.
|
||
|
||
The oracle targets 20 MHz / 33333 baud; the port targets 16 MHz / 115200 baud
|
||
(what the simavr protocol test drives). Baud and geometry differ, code size and
|
||
feature set do not.
|