Bring-up on the bench
You will learn
What a pre-registered bring-up looks like on the real bench, step by step.
A bring-up is not improvisation: the steps are pre-registered, each command is logged, and what did not run is as recorded as what did. The widget is the Ethernet bring-up plan on this bench, tri fpga-steps, and the spec is its tool card. The next module shows the discipline that guards the hardware the plan touches.
Try it
In the recording, count the steps and find one that did not run; then in the spec frame read what the tool card declares it records.

The Ethernet bring-up plan on the bench: pre-registered steps, logged exits, what ran and what did not
specs/tools/trios/tri/fpga-steps.t27
// SPDX-License-Identifier: Apache-2.0
; specs/tools/trios/tri/fpga-steps.t27 -- tool gHashTag/BrowserOS:tri/fpga-steps, the `tri fpga-steps` command of the trios loop CLI
; Generated by apps/website/scripts/tools-from-trios-tri.mjs from gHashTag/BrowserOS:trios/bin/tri at 7366096248df; do not edit.
; The CLI the loop timers run (`tri drift` holds ~/.local/bin/tri to the tracked copy). It is another program than
; the Rust tri of gHashTag/t27 and the Zig tri of gHashTag/trinity, so the ID is repository-qualified.
; A card is data and carries no test block. ASCII only (L3). phi^2 + 1/phi^2 = 3 | TRINITY
module tool_trios_tri_fpga_steps;
pub const KIND : str = "tool";
pub const FAMILY : str = "tri-cli";
pub const ID : str = "gHashTag/BrowserOS:tri/fpga-steps";
pub const REPO : str = "gHashTag/BrowserOS";
pub const QUALIFIED_ID : str = "gHashTag/BrowserOS:tri/fpga-steps";
pub const SCHEMA : u32 = 2;
pub const COMMAND : str = "tri fpga-steps";
; The case arm of the dispatcher and the first line of it that does the work.
pub const VARIANT : str = "case arm `fpga-steps)`, line 1943";
pub const SOURCE : str = "trios/bin/tri";
pub const ENTRY : str = "trios/bin/tri";
pub const SOURCE_COMMIT : str = "7366096248dfb09893e9a7d1a0f1c56ced13d16e";
pub const ROUTED : bool = true;
pub const DISPATCH : str = "exec python3 \"$HOME/skills/ax7203-board-loop/scripts/board.py\" steps \"$@\"";
pub const DOCUMENTED : bool = true;
pub const HELP_LINE : str = "tri fpga-steps KEY [--plan FILE] -- where a pre-registered board sequence stands (default plan NODE_ETHERNET_PLAN.md, e.g. KEY=E3; FILE is looked up here, then in conformance/; KEY is the start of the heading, e.g. \"The board run\" --plan UART_LOSS_HUBFREE.md): each tri fpga-run/-flash line against its board_runs log, commands that differ from the plan, out-of-order logs, the next step; prints only, runs nothing, judges nothing; exit 2 on a problem";
pub const CATEGORY : str = "AX7203 board (tern_tc: receipts, UART, formats)";
pub const ABOUT : str = "where a pre-registered board sequence stands (default plan NODE_ETHERNET_PLAN.md, e.g. KEY=E3; FILE is looked up here, then in conformance/; KEY is the start of the heading, e.g. \"The board run\" --plan UART_LOSS_HUBFREE.md): each tri fpga-run/-flash line against its board_runs log, commands that differ from the plan, out-of-order logs, the next step; prints only, runs nothing, judges nothing; exit 2 on a problem";
pub const ABOUT_SOURCE : str = "`tri help` (the heredoc under the help arm of trios/bin/tri)";
pub const ACTIONS : [0]str = [];
pub const ACTIONS_ABOUT : [0]str = [];
pub const ARGS : [2]str = ["KEY", "[--plan FILE]"];
pub const AGENTS : [0]str = [];
pub const AGENTS_NOTE : str = "No source binds an agent letter to this command: the trios CLI is not named by docs/agents/AGENTS_ALPHABET.md or .claude/agents/*.md of gHashTag/t27.";
pub const WHEN_TO_USE : str = "where a pre-registered board sequence stands (default plan NODE_ETHERNET_PLAN.md, e.g. KEY=E3; FILE is looked up here, then in conformance/; KEY is the start of the heading, e.g. \"The board run\" --plan UART_LOSS_HUBFREE.md): each tri fpga-run/-flash line against its board_runs log, commands that differ from the plan, out-of-order logs, the next step; prints only, runs nothing, judges nothing; exit 2 on a problem";
; public/term/tri-fpga-steps/meta.json lists 1 run(s) of `tri fpga-steps`, exit 0. The site plays it at the end of this card.
pub const CAST : str = "term/tri-fpga-steps/session.cast";
pub const WITNESS : str = "source-parse";
pub const WITNESS_SOURCE : str = "gHashTag/BrowserOS:trios/bin/tri at 7366096248dfb09893e9a7d1a0f1c56ced13d16e, read as text (the help heredoc and the top-level case arms); the CLI was not run";
pub const ENABLED : bool = true;
All lessons
Module 1 · What a bus is
Why a bus exists at all: a conversation on wires, framed and addressed, and who is allowed to talk.
Module 2 · UART
The two-wire bus with no clock: the frame, the divisor that sets the rate, and the status a driver polls.
Module 3 · SPI
The clocked conversation: four modes, a prescaler ladder, and a chip select per servant.
Module 4 · APB
The register bus: PSEL and PENABLE, strobes and wait states, and how many address bits a peripheral count costs.
Module 5 · AXI4
The five channels: address, data and response in both directions, lite or full, bursts and IDs.
Module 6 · Memory
What sits on the far side of every bus: memory maps, port kinds, and latency that a wait state must cover.
Module 7 · Bridges
Why designs grow more than one bus, and the packet bridge that moves work between them.
Module 8 · Ethernet
Frames, the frame check sequence, RGMII timing, and the pre-registered steps of a real bring-up.
Module 9 · The bench
The discipline that guards real hardware: who holds the IO, taking and giving the lock, and what runs next.