tools: a hardware harness, so a board can be proven and not just a protocol
check.sh proves the protocol under simavr on every chip; it cannot prove a board. Two things live only on silicon — an RC oscillator that is not on its nominal, and a reset edge that has to come from somewhere — and until now the scripts that reached them were per-session scratch on the machine holding the programmer, which is where the ATtiny13A run's findings nearly stayed. pbrig.py is the primitives, knowing nothing per-board: every deployment fact is a flag or a PUREBOOT_* variable. Two rig facts are encoded in it because neither is guessable and each cost a session to learn: an ISP access *is* the reset edge where the adapter's DTR is unwired, so a session begins with an ISP touch and knocks immediately after; and avrdude splits -U on colons, so a Windows drive letter breaks the spec and every file goes as a bare name with avrdude run in its own directory. Its `rate` subcommand is the one that turns "the loader is silent, so the wiring must be wrong" into a number, by sweeping the host rate against a fixed cycles-per-bit transmitter — PUREBOOT_HEARTBEAT makes the existing fixture into one, software link only, since the hardware-link idle owes the self-update tests its command loop. pbhw.py takes every bound from the info block the loader reports, so one run covers a 1 KiB tiny and a 128 KiB mega alike. Both are exercised on an ATtiny13A: backup verified against a known-good capture, the clock measured at 9.048 MHz against a 9.6 MHz nominal, and the suite 11/11. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -470,3 +470,43 @@ Per chip preset, `ctest` runs:
|
||||
|
||||
`size`, `pi`, `planner` and `handshake` are host logic and run anywhere; the
|
||||
simulator-driven targets need simavr and a pty, so they are POSIX-only.
|
||||
|
||||
## Hardware
|
||||
|
||||
The suite above proves the protocol on every chip; it cannot prove a *board*.
|
||||
Two things live only on silicon: an RC oscillator that is not on its nominal, and
|
||||
a reset edge that has to come from somewhere. `tools/pbrig.py` and
|
||||
`tools/pbhw.py` cover that, and know nothing per-board — every deployment fact
|
||||
is a flag or a `PUREBOOT_*` environment variable.
|
||||
|
||||
```sh
|
||||
export PUREBOOT_PROGRAMMER=atmelice_isp PUREBOOT_PART=t13 PUREBOOT_PORT=COM6
|
||||
tools/pbrig.py backup rig-backup/ # verified, before anything is written
|
||||
tools/pbhw.py --autobaud --loader build/ab.bin --app build/pbapp.hex --marker APP
|
||||
```
|
||||
|
||||
`pbrig.py` is the primitives — `signature`, `reset`, `flash`, `fuses`, `backup`,
|
||||
`rate` — and the module `pbhw.py` builds on. Two rig facts are encoded in it
|
||||
because neither is guessable: an **ISP access is the reset edge** (the part runs
|
||||
the moment the programmer releases it, which is the only edge available when the
|
||||
adapter's DTR is not wired to reset, so a session begins with an ISP touch and
|
||||
knocks immediately after), and **avrdude splits `-U` on colons**, so a Windows
|
||||
path's drive letter breaks the spec and every file is passed as a bare name with
|
||||
avrdude run in its own directory.
|
||||
|
||||
`pbrig.py rate` is the one that turns "the loader is silent, so the wiring must
|
||||
be wrong" into a number. Against a fixture built with `PUREBOOT_HEARTBEAT` — a
|
||||
*fixed* cycles-per-bit transmitter — it sweeps the host rate, and the band where
|
||||
the marker still decodes brackets the part's true bit rate; with the clock the
|
||||
image was built for, that is the clock the part is really running at. No
|
||||
instrument beyond the adapter already attached. An ATtiny13A measured this way
|
||||
came out at 9.072 MHz against its 9.6 MHz nominal, −5.5 % — inside the
|
||||
datasheet's ±10 % and outside what an 8N1 frame survives, which is the whole
|
||||
case for the autobaud backend on such a part.
|
||||
|
||||
`pbhw.py` takes its bounds from the info block the loader reports, so one run
|
||||
covers a 1 KiB tiny and a 128 KiB mega alike: identity, the EEPROM round trip
|
||||
and erase, an application flashed and verified and then *seen running*, the
|
||||
application region read and erased, the loader slot proven intact across that
|
||||
erase by an independent ISP read, and an oversized image refused. It overwrites
|
||||
the application flash and EEPROM, which is why `backup` comes first.
|
||||
|
||||
Reference in New Issue
Block a user