Capture a crossing
You will learn
How one crossing was captured at the flip-flops on a real board, and what the recorded run printed.
One crossing, captured where it lands: at the RX flip-flops themselves. The tri fpga-rxcap command models the E3 RX capture on the AX7203 board (XC7A200T in an FBG484 package) in the same SDF the last module used, and its recorded run printed: falling-edge hold 10900 ps on rxctl_n, with RXC 2.4 ns behind its data through the BUFG, so rxd_p1 and an RX_ER nibble sample the new value over a window the model states. The spec is a tool card -- constants for a tool page, 0 tests, and the recording shows the native report saying exactly that. The pins it captures are the far end of every lesson before this one.
Try it
In the recording, find the recorded hold margin and the delay through the BUFG; then in the spec frame read the tool card's data sources and say what the model did not measure.

The tri fpga-rxcap tool-card spec reports 0 tests -- constants for a tool page, not a test suite; the first lines show what it carries.
specs/tools/trios/tri/fpga-rxcap.t27
// SPDX-License-Identifier: Apache-2.0
; specs/tools/trios/tri/fpga-rxcap.t27 -- tool gHashTag/BrowserOS:tri/fpga-rxcap, the `tri fpga-rxcap` 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_rxcap;
pub const KIND : str = "tool";
pub const FAMILY : str = "tri-cli";
pub const ID : str = "gHashTag/BrowserOS:tri/fpga-rxcap";
pub const REPO : str = "gHashTag/BrowserOS";
pub const QUALIFIED_ID : str = "gHashTag/BrowserOS:tri/fpga-rxcap";
pub const SCHEMA : u32 = 2;
pub const COMMAND : str = "tri fpga-rxcap";
; The case arm of the dispatcher and the first line of it that does the work.
pub const VARIANT : str = "case arm `fpga-rxcap)`, line 1946";
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 = "cd \"$HOME/trinity-fpga\" && { if [ $# -eq 0 ] && [ -f conformance/model_runs/e3_rx_capture_model.log ]; then exec cat conformance/model_runs/e3_rx_capture_model.log; fi; exec nice -n 19 python3 conformance/e3_rx_capture_model.py \"$@\"; }";
pub const DOCUMENTED : bool = true;
pub const HELP_LINE : str = "tri fpga-rxcap [--self-test] -- E3 RX capture at the RX flip-flops in the same SDF (conformance/e3_rx_capture_model.py; spec specs/trinet/e3_rx_capture_model_ax7203.t27; reads /tmp/e3txhold, pinned by sha, runs no tool): with no argument prints the one recorded run (conformance/model_runs/e3_rx_capture_model.log) if it exists, else runs it once (seconds); exit 0 PASS, 1 FAIL, 2 NO VERDICT. PASS 00:21Z 2026-09-28: falling-edge hold 10900 ps on rxctl_n; RXC 2.4 ns behind its data through the BUFG, so rxd_p1 and an RX_ER nibble sample the new value over x -2.5..+0.5 ns (board ed should stay 0)";
pub const CATEGORY : str = "AX7203 board (tern_tc: receipts, UART, formats)";
pub const ABOUT : str = "E3 RX capture at the RX flip-flops in the same SDF (conformance/e3_rx_capture_model.py; spec specs/trinet/e3_rx_capture_model_ax7203.t27; reads /tmp/e3txhold, pinned by sha, runs no tool): with no argument prints the one recorded run (conformance/model_runs/e3_rx_capture_model.log) if it exists, else runs it once (seconds); exit 0 PASS, 1 FAIL, 2 NO VERDICT. PASS 00:21Z 2026-09-28: falling-edge hold 10900 ps on rxctl_n; RXC 2.4 ns behind its data through the BUFG, so rxd_p1 and an RX_ER nibble sample the new value over x -2.5..+0.5 ns (board ed should stay 0)";
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 : [1]str = ["[--self-test]"];
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 = "E3 RX capture at the RX flip-flops in the same SDF (conformance/e3_rx_capture_model.py; spec specs/trinet/e3_rx_capture_model_ax7203.t27; reads /tmp/e3txhold, pinned by sha, runs no tool): with no argument prints the one recorded run (conformance/model_runs/e3_rx_capture_model.log) if it exists, else runs it once (seconds); exit 0 PASS, 1 FAIL, 2 NO VERDICT. PASS 00:21Z 2026-09-28: falling-edge hold 10900 ps on rxctl_n; RXC 2.4 ns behind its data through the BUFG, so rxd_p1 and an RX_ER nibble sample the new value over x -2.5..+0.5 ns (board ed should stay 0)";
; public/term/tri-fpga-rxcap/meta.json lists 1 run(s) of `tri fpga-rxcap`; recorded with the live ~/.local/bin/tri,
; not a build of SOURCE_COMMIT. The site plays it at the end of this card.
pub const CAST : str = "term/tri-fpga-rxcap/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 clock is
One edge, one world: what shares a clock edge shares a world, the period and the jitter of a real edge, and where the clock enters a board.
Module 2 · Clock trees
Skew and insertion delay, the global buffer network, and the trap of gating a clock with logic.
Module 3 · PLL and MMCM
Multiply and divide one clock into another, move its phase in steps of the VCO, and which clocks the analyzer treats as related.
Module 4 · Resets
Assert asynchronously, release synchronously: the three reset kinds, the release pipe, and the tree a reset grows.
Module 5 · Metastability
The setup-hold window, the mean time between failures in integer arithmetic, and the two flops that fix it.
Module 6 · Crossing many bits
Why a binary bus tears, why Gray code does not, and the handshake that moves a pulse between worlds.
Module 7 · The asynchronous FIFO
Pointers, flags and depth: the buffer that moves a stream between two clocks.
Module 8 · Constraints
The lines that tell the analyzer what a clock is, which paths not to check, and what the pins must meet.
Module 9 · On the board
A CDC report, one crossing captured at the flip-flops, and the bitstream diff that closes the course.