pureboot 7: the same features in fewer words on every chip
Four cuts, none touching what the loader can do. The entry stub stops re-doing the reset logic's own SP write where the datasheet guarantees RAMEND (stack::hardware — the classic megas keep theirs). The autobaud unit moves into GPIOR2:GPIOR1 wherever the chip has the pair: one-word accesses, no RAM object, and the host's measured-clock peek follows it by version and geometry. 'J' rides the unified decode, carrying a selector it ignores so its address is the same two reads as every other command — the tool sends the bare form to older residents. run_app stops insisting on a body of its own. The fleet lands at 358–410 B stock and 438–474 B autobaud; the tightest image in the space — the 1284s' autobaud on a USART's own pins with the OSCCAL trim — drops from 510 to 484 of its 512. Every chip's suite is green on the wire that changed, and the README's table is machine-checked against the built images. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,31 +28,31 @@ it carries the calibration machinery and no clock at all.
|
||||
|
||||
| Chip | Flash | Loader at | Link | Stock | Autobaud |
|
||||
|---|---|---|---|---|---|
|
||||
| ATtiny13, ATtiny13A † | 1 KiB | 0x0200 | software | 390 B | 460 B |
|
||||
| ATtiny25 † | 2 KiB | 0x0600 | software | 394 B | 464 B |
|
||||
| ATtiny45 † | 4 KiB | 0x0e00 | software | 398 B | 468 B |
|
||||
| ATtiny85 † | 8 KiB | 0x1e00 | software | 398 B | 468 B |
|
||||
| ATmega8, 8A | 8 KiB | 0x1e00 | USART0 | 360 B | 474 B |
|
||||
| ATmega16, 16A | 16 KiB | 0x3e00 | USART0 | 362 B | 480 B |
|
||||
| ATmega32, 32A | 32 KiB | 0x7e00 | USART0 | 362 B | 480 B |
|
||||
| ATmega48, 48A, 48P, 48PA † | 4 KiB | 0x0e00 | USART0 | 388 B | 464 B |
|
||||
| ATmega88, 88A, 88P, 88PA | 8 KiB | 0x1e00 | USART0 | 398 B | 474 B |
|
||||
| ATmega168, 168A, 168P, 168PA | 16 KiB | 0x3e00 | USART0 | 400 B | 480 B |
|
||||
| ATmega328, 328P | 32 KiB | 0x7e00 | USART0 | 400 B | 480 B |
|
||||
| ATmega164A, 164P, 164PA | 16 KiB | 0x3e00 | USART0 | 400 B | 480 B |
|
||||
| ATmega324A, 324P, 324PA | 32 KiB | 0x7e00 | USART0 | 400 B | 480 B |
|
||||
| ATmega644, 644A, 644P, 644PA | 64 KiB | 0xfe00 | USART0 | 394 B | 474 B |
|
||||
| ATmega1284, 1284P | 128 KiB | 0x1fe00 | USART0 | 420 B | 500 B |
|
||||
| ATtiny13, ATtiny13A † | 1 KiB | 0x0200 | software | 384 B | 452 B |
|
||||
| ATtiny25 † | 2 KiB | 0x0600 | software | 388 B | 442 B |
|
||||
| ATtiny45 † | 4 KiB | 0x0e00 | software | 388 B | 442 B |
|
||||
| ATtiny85 † | 8 KiB | 0x1e00 | software | 388 B | 442 B |
|
||||
| ATmega8, 8A | 8 KiB | 0x1e00 | USART0 | 358 B | 470 B |
|
||||
| ATmega16, 16A | 16 KiB | 0x3e00 | USART0 | 360 B | 474 B |
|
||||
| ATmega32, 32A | 32 KiB | 0x7e00 | USART0 | 360 B | 474 B |
|
||||
| ATmega48, 48A, 48P, 48PA † | 4 KiB | 0x0e00 | USART0 | 378 B | 438 B |
|
||||
| ATmega88, 88A, 88P, 88PA | 8 KiB | 0x1e00 | USART0 | 388 B | 448 B |
|
||||
| ATmega168, 168A, 168P, 168PA | 16 KiB | 0x3e00 | USART0 | 390 B | 454 B |
|
||||
| ATmega328, 328P | 32 KiB | 0x7e00 | USART0 | 390 B | 454 B |
|
||||
| ATmega164A, 164P, 164PA | 16 KiB | 0x3e00 | USART0 | 390 B | 454 B |
|
||||
| ATmega324A, 324P, 324PA | 32 KiB | 0x7e00 | USART0 | 390 B | 454 B |
|
||||
| ATmega644, 644A, 644P, 644PA | 64 KiB | 0xfe00 | USART0 | 384 B | 448 B |
|
||||
| ATmega1284, 1284P | 128 KiB | 0x1fe00 | USART0 | 410 B | 474 B |
|
||||
|
||||
† No hardware boot section: the host patches the reset vector, and the budget
|
||||
is 510 bytes, since the slot's last word is the trampoline.
|
||||
|
||||
The tightest fit in the whole space is the 1284s' autobaud build deployed on a
|
||||
USART's own pins with the `OSCCAL` trim baked, 510 of its 512 — they alone
|
||||
USART's own pins with the `OSCCAL` trim baked, 484 of its 512 — they alone
|
||||
carry the far-flash machinery (ELPM reads, RAMPZ page commands), autobaud
|
||||
alone carries the calibration loop, a bit-banged link on a USART's pins alone
|
||||
has to release it (below), and the trim adds its one register write. Without
|
||||
the trim that build is 504; on the default pins, 500. The flash bank riding
|
||||
the trim that build is 478; on the default pins, 474. The flash bank riding
|
||||
in a transfer's selector byte keeps even those chips' addressing the same
|
||||
16-bit form every other chip uses, which is why they are no longer the
|
||||
outlier they were.
|
||||
@@ -187,8 +187,10 @@ reply, repeat.
|
||||
|
||||
Addresses are **byte addresses within a 64 KiB bank**, and the bank rides in
|
||||
the command's selector byte, so no command has to speak word addresses. `J` is
|
||||
the exception: it takes a word address, because that is what the hardware's own
|
||||
jump takes. EEPROM and data-space addresses and all counts are bytes.
|
||||
the exception: its address is a word address, because that is what the
|
||||
hardware's own jump takes — it still carries a selector byte (reserved,
|
||||
ignored) so its decode is the same three reads as every other command's.
|
||||
EEPROM and data-space addresses and all counts are bytes.
|
||||
|
||||
The loader trusts the host to keep addresses in range: it does not bound them
|
||||
against the chip. **Gotcha:** a write (or read) that runs past `E2END` wraps —
|
||||
@@ -203,7 +205,7 @@ better spent on features than on re-checking a bound the host already holds.
|
||||
| `G` | sel8, addr16, n8 | n bytes from the selected space (n = 0 means 256) |
|
||||
| `g` | sel8, addr16, n8, then n data bytes | `+` per byte, sent once its write has begun |
|
||||
| `W` | sel8, addr16, then one page of data | — (completion = next prompt) |
|
||||
| `J` | word address (16-bit) | `+`, then execution continues there |
|
||||
| `J` | sel8 (reserved), word address (16-bit) | `+`, then execution continues there |
|
||||
| other | — | ignored; the loop re-prompts (send a junk byte, await `+`, to resync) |
|
||||
|
||||
`G` and `g` are one letter in two cases, which is the whole command set for
|
||||
@@ -291,7 +293,12 @@ from `b`, and a command per memory (`R`/`W` flash, `r`/`w` EEPROM, `F` fuses).
|
||||
above; the shipped tool speaks both, choosing on the version it reads, so a
|
||||
deployed pureboot 4 stays drivable and self-updatable to 5. **6** changes
|
||||
nothing on the wire: it marks the builds that may carry a baked `OSCCAL` trim
|
||||
(Configuration), so a tool driving an update knows such images exist.
|
||||
(Configuration), so a tool driving an update knows such images exist. **7**
|
||||
moves `J` onto the unified decode — it gains the selector byte the table
|
||||
shows, which older loaders do not read, so the tool sends each form to the
|
||||
version that speaks it — and re-homes the autobaud unit into the GPIOR pair
|
||||
on the chips that have one (Session: what must not be written), which is
|
||||
where `--info`'s measured clock now reads it on those parts.
|
||||
|
||||
Every closed generation is tagged in this repo at its era's last commit — the
|
||||
commit just before the next version bump, so a tag holds everything its
|
||||
@@ -476,11 +483,14 @@ Reads are safe anywhere; **two small regions cannot be written without ending th
|
||||
session,** because they are what the loader is standing on:
|
||||
|
||||
- the **top of SRAM**, where its stack lives — a handful of bytes below RAMEND;
|
||||
- on an **autobaud** build, the **two bytes at RAMSTART**: the measured bit
|
||||
period, in `.noinit`, which is the whole of that loader's static RAM. Overwrite
|
||||
it and its next reply is timed against garbage. On an ATtiny13A that is
|
||||
`0x60..0x61`, and the symptom is a mangled prompt byte rather than any error —
|
||||
the loader is fine, it simply is no longer speaking the agreed rate.
|
||||
- on an **autobaud** build, the **measured bit period**: two bytes in
|
||||
GPIOR2:GPIOR1 where the chip has the pair (data `0x32..0x33` on the
|
||||
t25/45/85, `0x4A..0x4B` from the x8 generation on — such a loader has *no*
|
||||
static RAM at all), and the two bytes at RAMSTART on the chips without one
|
||||
(the t13s and classic megas), where they are the whole of the loader's
|
||||
static RAM. Overwrite either home and the next reply is timed against
|
||||
garbage — the symptom is a mangled prompt byte rather than any error; the
|
||||
loader is fine, it simply is no longer speaking the agreed rate.
|
||||
|
||||
Both are self-inflicted rather than defects, and a reset clears them. Note also
|
||||
that `--poke` can write OSCCAL, which does take effect — but a session can only
|
||||
@@ -518,9 +528,10 @@ Per chip preset, `ctest` runs:
|
||||
below sweeps. `pureboot*osccal*.size` add the `OSCCAL` trim on the stock
|
||||
shape and on the tightest image in the space (autobaud on a USART's own
|
||||
pins), holding both of the trim write's addressing encodings to the budget;
|
||||
- `pureboot_autobaud.unit` — the measured bit period is the loader's only RAM
|
||||
object and sits exactly at ram_start, where `--info` reads it: wire
|
||||
contract, not layout accident;
|
||||
- `pureboot_autobaud.unit` — the measured bit period sits where `--info`
|
||||
reads it (wire contract, not layout accident): in the GPIOR pair, with no
|
||||
RAM object at all, on the chips that have one; as the loader's only RAM
|
||||
object at exactly ram_start elsewhere;
|
||||
- `pbm_*.size` — with `PUREBOOT_FULL_MATRIX=1`, the exhaustive cross product
|
||||
replacing that compact matrix, on **every** chip: every plausible oscillator
|
||||
(the internal ones, the CKDIV8 floor, the plain and the UART crystals) ×
|
||||
|
||||
Reference in New Issue
Block a user