Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

U280 evidence workflow

The U280 flow evaluates the exact generated production signer top out of context. It is not a Vitis kernel shell and cannot establish card throughput.

The separate Phase-A card path wraps the same Rust/RHDL signer in an AXI-Lite benchmark kernel. Its XO is explicitly user_managed so the host can own the register protocol through xrt::ip. Vitis links exactly one CU, and the host accepts only hashsigs_wots_sha256_benchmark_kernel:{hashsigs_wots_sha256_benchmark_kernel_1}. The exact clock/name contracts are fpga/u280/phase_a/link_250.cfg and fpga/u280/phase_a/link_300.cfg; they are not interchangeable with this raw-crypto OOC flow. Packaging, source-digest, and non-overwrite rules are in fpga/u280/README.md, while the register and one-time range contract is in fpga/u280/BENCHMARK_ABI.md.

Preserve provenance

Stage only a checksum-validated linked signer bundle whose generated-RTL gate passed. The staging manifest binds the RTL, source evidence manifests, Tcl, XDC, target part, and checksums. Use a new staging and run directory for every source or constraint variant.

The preserved 6801a66-41fe7ba3-20260715T1103PDT stage is superseded and unlaunchable because its managed XDCs contain unsupported Tcl control flow. It remains a forensic artifact only; do not mutate, execute, or promote it. A run must use a fresh schema-v2 stage with flow_variant=baseline.

bun run stage:u280 -- <preserved-generated-rtl-evidence> <new-stage-directory>

The stage must be read-only and contain exactly one linked Verilog bundle. The flow accepts only xcu280-fsvh2892-2L-e; it rejects a different part, a renamed or altered clock constraint, extra RTL, a dirty flow checkout, or a checker whose commit and tree differ from the staged flow identity.

Run sequentially

Before any remote U280 Vivado, Vitis, XRT, or card action, record explicit ownership in both coordination ledgers and use the wrapper to obtain the nonblocking lock at the effective user’s canonical passwd login home plus .cache/rhdl-fpga/u280.lock. Caller-controlled HOME never selects the lock namespace. Failure to acquire the lock immediately means stop. Do not wait for it, probe the owner, inspect the owner’s process, or start a competing flow. Ledger ownership without the lock, or the lock without both ledger entries, is insufficient.

The checked-in wrapper is the only supported launch entry point. Set its acknowledgment inline only after both ownership entries exist, and pass the approved executable by absolute path:

HASHSIGS_U280_COORDINATION_ACK=both-ledgers-recorded \
  tools/with-u280-lock.sh /absolute/path/to/approved-executable <arguments>

tools/with-u280-lock.sh delegates to a descriptor-rooted helper. The helper walks the passwd-home path with O_NOFOLLOW, validates effective-user ownership and rejects group- or other-writable lock-path objects, takes LOCK_EX|LOCK_NB on the already-open file, and reopens every path component to compare identities. Privileged Bash startup ignores BASH_ENV and imported functions; the Python helper also removes Bash/POSIX startup hooks, option injection, and exported Bash functions from the guarded child’s environment, then validates its own owner, mode, type, and link count. ELF commands are launched through their retained descriptor, while script launchers are checked against a retained inode immediately before and after spawn. The helper then remains as a supervisor that retains the locked fd while the exact absolute command runs in a foreground process group; closing inherited non-stdio descriptors inside the tool cannot release the supervisor’s lock. Termination signals are forwarded to that process group. There is no lock wait or unlocked fallback. The Vitis run action additionally rejects a bare invocation unless that inherited fd matches the canonical path’s device, inode, and /proc/self/fd target.

The approved tool must remain in the foreground and wait for its subprocesses; backgrounding, double-forking, or daemonizing a hardware job is unsupported. Launch remote flows in a dedicated systemd service with KillMode=control-group, so an abnormal supervisor termination cannot leave an untracked descendant using the card after the lock descriptor disappears.

The acknowledgment is a human assertion that both ledger entries exist; it is not cryptographic verification. The advisory lock and inherited-context check prevent accidental contention among cooperating processes. They do not defend against a malicious process already executing as the same UID, which can deliberately violate any same-user advisory protocol.

  1. Synthesize at the 4.000 ns / 250 MHz basis.
  2. Inspect mapping, DRC, and resource limits before placement.
  3. Place and route that exact variant.
  4. Repeat the 3.333 ns / 300 MHz goal in a separate run only after the first run is understood.

Do not run competing high-memory Vivado jobs on a shared host. Worker count is an explicit input and does not exceed the flow’s cap.

The exact Vivado 2023.2 commands, empty-directory rule, console capture, and archive inventory are published in the privacy-sanitized flow narrative. Run synthesis and full implementation in different directories; never resume one phase by adding files to the other phase’s result.

Validate outside Vivado

Vivado process success is an input to the evidence checker, not the verdict. After a run has written vivado.console.log and vivado.exit-status, validate the stage and result together:

bun run tools/check-u280-reports.ts -- \
  <stage-directory> <result-directory> synth <synthesis-evidence.json>

bun run tools/check-u280-reports.ts -- \
  <stage-directory> <result-directory> full <route-evidence.json>

The checker creates its read-only JSON manifest only after every applicable gate passes. It streams checkpoints into the result checksum inventory rather than loading large DCP files into memory.

The manifest distinguishes a statically declared managed XDC, a Vivado read_xdc call that applied it, and a post-synthesis gate that observed the exact clock, top-level port inventory, valid/invalid constraint export, and I/O-delay coverage. None of these states is card or hardware evidence.

Passing gates

For the crypto hierarchy, the project limits are:

  • no more than 200,000 LUTs;
  • no more than 300,000 registers; and
  • no more than 4,000 DSPs; this is the absolute project ceiling.

A routed timing pass requires a completely routed design, no route errors, setup WNS at least zero with TNS zero, hold WHS at least zero with THS zero, pulse-width WPWS at least zero with TPWS zero, and zero findings in all twelve verbose check_timing categories. The report must repeat the staged core_clk period and exact design/device identity. The checker also requires post_synth_applied_constraints.xdc and the deterministic post_synth_constraints_observed.rpt; unsupported XDC commands, any invalid constraint, an unexpected port, or a missing/partial I/O delay fails. Enabled Error/Fatal DRC violations, unresolved black boxes, missing reports, report-command errors, resource overruns, or a nonzero Vivado exit all fail the gate. Process exit zero alone is never a pass.

Publish the right claim

  • Synthesis reports mapping and estimated timing.
  • A completely routed OOC result reports the exact crypto top without a shell.
  • A shell route includes shell resources and timing.
  • Only validated execution on a programmed card reports hardware throughput.

Archive reports and checkpoints with the staged manifest; never combine a simulator interval with an unrelated routed revision.