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.
- Synthesize at the 4.000 ns / 250 MHz basis.
- Inspect mapping, DRC, and resource limits before placement.
- Place and route that exact variant.
- 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.