Skip to main content

Module tui

Module tui 

Source
Expand description

The interactive terminal front end (feature tui).

§The Tuner: plan a U280 signature chip and know how far to trust it

The Tuner answers one question in a second: with this much of an Alveo U280, how many signatures and verifications per second does the chip deliver, and what exactly do we build? You set a budget and a few knobs. It searches every build it knows, shows the rates, the latency and every module’s estimated resources, and writes a TOML record of proposed compile-time settings. The current build scripts read environment variables; saving TOML alone does not apply those settings to a build. Check the supported application path before claiming that a displayed plan became generated hardware.

Why it exists, in four sentences. Two papers share one chip, and by hand nobody could say how to divide it. The first planner added up costs from synthesis, and its first full-chip plan did not fit the chip’s block RAM. So we routed the plans it made, 80 Vivado runs in four days, and fitted its costs to what Vivado really used. Now it predicts a routed core’s LUTs to within a few percent, and this page shows you how far to trust it and where it is still wrong.

In numbers.

  • Measured against 88 Vivado routes of the planned designs (Vivado 2023.2, out of context, 4.878 ns = 205 MHz, Oct 16–20 2026), the Tuner predicts a whole core’s LUTs within −1.0 … +2.3 % on cores its costs were not fitted to:

    CorePredictedRouted
    fix10 L200 signer 12,0,3,1255,219254,817
    fix11 verifier 6,0,1,1150,198150,873
    fix12 verifier 6,0,1,1150,198151,645
    fix12 L200 verifier 24,0,2,1840,023842,345
    fix13 L200 verifier 24,0,2,1 (hard route)840,023827,202
    fix12 verifier 1,1,1,1 (DSig’s certificate-miss core)84,05882,184
  • DSPs are exact. BRAM36 is within 2.3 %, and URAM within 1.8 % except on the smallest core (1,1,1,1: +4.5 %, 184 predicted against 176).

  • Its throughput model is within 0–8 % of cycle-accurate simulation, and it errs low. Every simulated signature equals ed25519-dalek and every verification equals verify_strict.

  • Seven whole cores it planned meet 205 MHz routed: signers 4,0,1,1 (two builds), 8,0,2,1, 9,0,2,1 and 12,0,3,1, and verifiers 6,0,1,1 and 1,1,1,1. Since then 8,0,2,0, 8,0,3,1 and 12,0,1,1 have met it too.

  • The L200 verifier 24,0,2,1 (827k LUT, ~64 % of the device) now meets 205 MHz too, by 0.008 ns, with the hard route directives (fix13, job 007zzq). On fix12 it missed by 2.225 ns. It is the largest core to meet timing, and the thinnest margin.

Reproduce the accuracy table with cargo run --release --example predict_builds (it writes measure/accuracy.tsv). Open the screen with cargo tuner.

§Contents

  1. What you see
  2. One plan, start to finish
  3. Where the resources go
  4. How it is built
  5. How it became accurate
  6. What is proven
  7. Every cost constant
  8. Limits
  9. Working on it
  10. Glossary

§1. What you see

The screen has two halves.

On the left are the controls.

  • The paper: Ed25519, or DSig with an Ed25519 background. A build with a uBFT service also offers its uBFT mode (below).
  • LUT and DSP budgets, from 0 % up to the whole device: 268.8 % of 485,000 LUTs and 199.6 % of 4,520 DSPs.
  • BRAM and URAM budgets, from 0 to 100 % of the shell’s dynamic region: 1,776 BRAM36 and 960 URAM.
  • The LUT split between the SHA-512 line and the engines.
  • The sign and verify powers, and the mix of verifications per signature.
  • The best case b, in the DSig paper only.
  • Each module’s share, shape and knobs.

On the right is what the chip delivers.

  • Each side’s rate, with its bottleneck.
  • Idle latency (one request on an idle core) and loaded latency (in flight ÷ throughput, Little’s law).
  • Each module’s build. It shows the profile, the cores, where its memory went and which multiplier it uses. It also shows the resources, each marked measured or model, and the limiting resource.
  • next: +N LUT → rate, the distance to the next faster build.
  • The SHA-512 blocks used against those supplied, and the chip’s gauges.

Keys.

KeyDoes
Up / Downselect a control
Left / Right (Shift: ×5)adjust it
Bbalance the sign/verify powers for the mix (what “100 %” means)
Pnext paper (every paper this build has, then the uBFT modes)
Wwrite build-config.toml
Q / Escquit

§2. One plan, start to finish

Follow one plan, the Ed25519 paper at LUT 100 %, DSP 100 %. These are the numbers in measure/configs/predictions.tsv.

  1. The budget becomes shares. The SHA-512 line sizes itself first. The engines at this budget want about 0.2 SHA-512 blocks per clock, so the line is one fold-16 core of 16,887 LUT instead of the 65k default. Sign and verify split the rest by their powers. → decisions, chapter 1.

  2. Each side finds its best build. The signer searches every profile fb,sha,sc,cp up to 40 machines, with both multipliers and 1–4 cores. The fastest build that fits is 7,0,2,1: 7 field machines, the shared SHA line, 2 scalar rings and 1 compress machine.

    • Its URAM share holds 6 machines’ banks. The placer moves the seventh machine’s banks to block RAM.
    • The verifier is 14,0,1,1 with the 150-DSP multiplier, half its machines in URAM and half in block RAM. → chapter 2.
  3. Lending. After the first plans, resources one side left unused are offered, in real counts, to whichever side gains most from them. → plan_chip, chapter 3.

  4. Delivery. The signer is machine-bound at 3.55M signatures/s (134,076 LUT, 1,846 DSP). The verifier delivers 3.70M verifications/s (333,987 LUT, 2,423 DSP). → chapter 4.

  5. W writes the build. One TOML table per module. The signer’s table is:

    ED25519_SCALABLE_PROFILE = "7,0,2,1"
    cores = 1
    SH = 1
    memory = "SPECIALIZED"
    multiplier = "DSP225"
    uram_machines = 6
    lut_machines = 0
    buildable = true

    measure/export_build.py turns that table into the environment for export_scalable, and the Verilog goes to Vivado. → chapter 6.

Why this matters: every number on the screen can be traced to one function and one table, and every build it writes can be exported and routed. Section 5 tells how that last part became true.

§Beside a uBFT replica

uBFT runs consensus on the same card. Each slot needs one signature and 2f verifications of peers’ shares, far below what even one small core delivers, so the rate is the wrong headline. In a uBFT mode (Mode::UbftEd25519, Mode::UbftDsig) the Tuner changes three things:

  1. Only uBFT modules take part. The replica, and the services built for its streams. The papers’ modules and the shared SHA-512 line stay out, and the papers never plan a uBFT module (Mode::admits).
  2. The budget is the whole device (Budget::whole_device), and the replica’s routed design comes off it: 346,232 LUT and 36 DSP. That is an upper bound, because it counts the shell. Switching back to a paper restores the papers’ budget.
  3. The headline is a slot’s crypto time: sign one share, then verify 2f shares. uBFT tolerates f = (n − 1) / 2 faults, so a quorum is nearly every replica. The first verification takes the verifier’s idle latency, and the rest follow at its rate. It is shown for 3, 7 and 11 replicas, beside the inline Vitis Ed25519 that uBFT calls today (3.07M cycles to sign and 10.4M to verify, one after another, at its 161.3 MHz).
Ed25519 service, n replicasSlot crypto (model)Inline HLSLess
3 (2 verifies)367 µs148 ms404×
7 (6 verifies)382 µs406 ms1,065×
11 (10 verifies)397 µs665 ms1,675×

The signer (1,1,1,0) is measured, and the verifier (1,1,1,1) is routed but not yet measured inside the service. The service’s own logic (6k LUT) and the 16-slot key tables (+57 BRAM36) are estimates. The model ignores network time. → rhdl_fpga_planner::ubft, planner::ubft in the Ed25519 crate, and chapter 12 of its guide.

§3. Where the resources go

A signing core is mostly field machines. A verifier is mostly machines plus a large fixed controller.

PartLUTDSPNote
field machine (sign)14,615225one 255-bit product per clock; ~11 % of a 100 % chip’s DSPs; 1,505 less inside a core
known-key verify machine14,09122513,863 routed + 228 of controller logic per machine
compress machine16,569225batch inversion, 32 points per inversion
key loader (verifier)14,518225builds a key’s tables, ~108k cycles per key
verify controller30,6570admission, contexts, compare, decode; fixed
signing controller10,0990fixed; 3,115 with no compress machine
scalar ring (sign)7,871236,194 routed alone plus its dispatch
scalar ring (verify)2,40823fitted with the verify controller
SHA client port1,5000per core on the shared line

What binds.

  • DSPs bind the Ed25519 paper first, because every machine brings a 225-DSP multiplier. That is why the verifier above takes the 150-DSP Karatsuba multiplier, which costs +4,440 LUT and saves 75 DSP.
  • URAM binds the verifier next. Each verify machine holds 56 URAM: 32 of banks and 24 of key tables.
  • When URAM runs out, the placer moves machine banks to block RAM. When block RAM runs out too, it moves them to LUT RAM, which costs +22,830 LUT per machine. That is how spare LUTs still buy machines.

Throughput is the slowest stage of the cycle model:

  • machines: 392 / fb / 0.97 cycles per signature;
  • SHA: 243 / sha / 0.886;
  • scalar: 64 / sc / 0.9;
  • admission: 2;
  • compress credits: 23.25 cycles, which caps one core at 8.82M/s.

A verification is 775 machine bundles instead of 392.

§4. How it is built

ModuleOwnsRead
crates/planner/src/lib.rsComponent, budgets, shares, lending, delivery, balance, build configfirst: the crate page
decisionsthe whole decision path, heuristic by heuristic, with whysecond
tui (this page)the screen, keys and the plan cachethird
crates/ed25519/src/planner.rsthe Ed25519 modules as Components; their knobs and build flagsfor Ed25519 plans
crates/ed25519/src/frontier.rsthe Ed25519 cost tables (slimmed_costs), the search, the placerto change a cost
crates/dsig/src/planner.rsDSig sign and verify, and the SHA-512 line modelfor DSig plans
src/paper.rswhich modules each paper hasto add a module
examples/build_configs.rs, examples/predict_builds.rsthe plan grid, and predicted against routedto check accuracy

The planner knows nothing about Ed25519 or DSig. Each module knows its own blocks and their costs. Why: the people who build a module know its costs, and the chip-level arithmetic stays a few lines anyone can check.

§5. How it became accurate

The first plans on screen were confident and wrong. Each step below fixed one way they were wrong. It gives the measurement that showed the problem, the idea, and the result.

  1. Synthesis costs said too little.
    • Problem: block costs came from synthesis, and routing changes LUT counts.
    • Idea: route every block out of context at 4.878 ns and use those numbers.
    • Result: the field machine, verify machine, compress machine, key loader, SHA ring and scalar ring are all routed costs, and each meets 205 MHz on its own. → frontier::slimmed_costs (commit b34eba7).
  2. Plans that could not be built.
    • Problem: the first L200 verifier plan, 27,0,2,1, put every machine in its preferred layout. Vivado stopped before placement: it needed 2,646 BRAM36 on a device with 2,016 (job 023).
    • Idea: place memory per machine (URAM, then block RAM, then LUT RAM) inside the RAM budget, export the counts as uram_machines and lut_machines, and offer only layouts the RTL can build.
    • Result: no plan since has failed placement for memory. → frontier::place (bb9dbb2).
  3. The dynamic region is smaller than the device.
    • Problem: DSig’s build v4 asked for 4,033 BRAM18 in a region with 3,552.
    • Idea: budget 1,776 BRAM36, the dynamic region, not 2,016.
    • Result: the BRAM budget is what the shell gives us. → decisions, chapter 1.
  4. A whole core is more than its blocks.
    • Problem: whole cores routed 6.5–7.6 % above the sum of their routed blocks (fb9b7ec, measure/accuracy.tsv).
    • Idea: treat rings and controllers as unknowns, and fit them to routed whole cores: the routed total less the routed blocks.
    • Result: within 0.5 % in sample, and −3.4 … −1.3 % out of sample. → 11019b8.
  5. Projected fallbacks were optimistic.
    • Problem: LUT-RAM banks were projected at +16,500 LUT and the 150-DSP multiplier at +2,500 LUT.
    • Idea: build and route both.
    • Result: LUT-RAM banks measured +22,830 (37,440 against 14,615 for the same machine), and the multiplier +4,367 … +4,441 LUT for −75 DSP. Both are now measured costs. → frontier::LUT_BANKS_LUT, lean_mul.
  6. Meeting 205 MHz changed the costs.
    • Problem: whole cores missed timing on long paths: 255-bit carries, the scalar ring, the verifier’s decode and arbitration (fix3 to fix12, Oct 17–19). Each fix added registers.
      • The verify controller grew from 17,540 + 716 per machine to 30,657 + 228.
      • The field machine grew from 14,070 to 14,615.
    • Idea: refit the costs to the RTL that meets timing (fix9), then check against cores routed later.
    • Result: fix10 to fix12 cores land at +0.2 %, −0.4 %, −1.0 % and +2.3 % LUT (the last is the one-machine verifier). → 467e39e.
  7. The throughput model, checked cycle by cycle.
    • Problem: the cycle model is arithmetic. A deadlock or a stalled stage would not show in it.
    • Idea: simulate the planned builds natively and compare the steady rate. measure/native_runs.sh runs 3,000–6,000 operations past the 2,048-context pool and counts the 50–90 % window.
    • Result: see the table in section 6. The model errs low by up to 8 %.
    • A rejected alternative: we planned fix10’s verifier on the cycle model alone. Simulation caught that it lost a coordinate on a flush and failed verification 585. It was fixed in fix11 before it routed.
  8. A verifier the core cannot build.
    • Problem: the verify search offered builds with no compress stage. In the DSig paper it chose 1,0,1,0 for the certificate-miss verifier, at 63,174 LUT. KnownKeyVerifyCore always has exactly one compress stage, so five grid plans were buildable = false.
    • Idea: known-key verification searches cp = 1 only. The strict and batch modes, which are models, keep 0–2.
    • Result: the DSig paper plans 1,0,1,1 at 79,743 LUT and 698 DSP. The routed own-ring 1,1,1,1 is 82,184 LUT and 698 DSP (job 007zzi). Every Ed25519 plan in the grid is now buildable. → frontier::plan_verify_shaped.
  9. A starved side that needed two modules.
    • Problem: when a side’s share holds no build, the planner sets aside a module’s smallest build and replans. It did that one module at a time. DSig signing needs two modules, the DSig signer and the Ed25519 signer that certifies it, so flooring either alone never helped.
    • Idea: floor every starved module of a side in one trial.
    • Result: a side is rescued whenever its modules’ smallest builds fit together. → floor_starved in the planner crate.
  10. Loaded latency five times too high.
    • Problem: loaded latency is requests in flight ÷ throughput, and the Tuner assumed every core holds all 2,048 compress credits. The saturated 6,0,1,1 verifier holds ~404, so its loaded latency was about 5× too high.
    • Idea: count what a core can actually hold: its machines’ 32 contexts each, plus the requests that left the machines and have not finished, at one per cycles per operation. Measure the peak in flight in simulation to check it (max in_flight in the logs).
    • Result: verify 6,0,1,1: 393 modeled, 404 measured. Sign 8,0,2,1 held 1,026, against 880 at first. The gap was the 8,000-cycle credit overhead that the rate model already uses. With it the Tuner says 952 at its own rate (1,012 at the simulated rate).
    • The idle latencies had a gap of their own: the code said it added the shared SHA line’s round trip, and it did not. Measured isolated, the line costs ~210 cycles per block. Signing is now 40,406 modeled against 40,446 measured, and verification 52,392 against 52,350. → loaded_in_flight, LINE_BLOCK_CYCLES (2026-10-19).
  11. The scalar ring was hiding in the other terms.
    • Problem: we routed four signers chosen to pull the fit apart: 4,0,1,1, 8,0,3,1 (one more ring than any fitted core), 8,0,2,0 (no compress machine, never built before) and 8,0,2,1 with the 150-DSP multiplier. The fit said a ring costs 2,408 LUT, yet a ring routed alone is 6,194. 8,0,3,1 came in 3.6 % above the prediction, and 8,0,2,0 5.5 % below it.
    • Idea: fit the controller, the per-ring cost and a per-machine in-core change together, by least squares on all four signers with a compress machine.
    • Result: a ring costs 7,871 in a core (6,194 plus ~1,700 for its dispatch), the controller 10,099, and each fixed-base machine 1,505 less than alone. All four land within 102 LUT. The fused 8,0,2,0 gets its own controller, 3,115, with no credit pool to keep.
    • A side effect worth knowing: a SHA line set by hand far below what it needs (2k) borrows LUTs back only when the engines leave some. After this refit they used them all, and the screen said the line limits both sides; with fix14’s constant ROM (step 12) fewer engines fit and the line borrows again. “auto” sizes it correctly either way. → frontier::slimmed_costs, FB_IN_CORE_LUT, sign_controller_fused (2026-10-20).
  12. A bug the card found, and its price.
    • Problem: the card rejected valid keys. Vivado had turned a constant bank into LUT RAM and scrambled 16 bits of d (see the Ed25519 crate’s chapter 11).
    • Idea: build the constants as a literal and a mux (fix14), and price the change.
    • Result: the routed 1,1,1,1 verifier grew from 82,184 to 84,435 LUT: 2,251 across its three field machines, 750 each. The model moves by the same 2,250, so this core keeps the error it had before the fix. Every field machine now carries CONST_ROM_LUT; predict_builds takes it off for cores routed before fix14, so their errors still mean what they meant.
  13. Timing on screen.
    • Problem: the Tuner plans resources. A plan could look perfect and miss 205 MHz by a nanosecond.
    • Idea: keep a table of every whole core routed on current RTL and show the verdict on the card.
    • Result: each build ends with routed: meets 205 MHz (+0.159 ns, 007zzm fix13), routed in another layout: …, or timing: not routed. Add a row to ROUTED in crates/ed25519/src/planner.rs when a route lands.

§6. What is proven

Whole cores routed (LUT, predicted against routed; measure/accuracy.tsv):

BuildRTLPredictedRoutedErrorWNS (ns)
sign 8,0,2,1 u6l0 (L100)fix9148,691148,6910.0 % (fitted)+0.218
verify 6,0,1,1fix9150,198150,2000.0 % (fitted)+0.043
sign 12,0,3,1 u5l2 (L200)fix9255,219255,2090.0 % (fitted)−0.358
verify 24,0,2,1 u2l19 (L200)fix9840,023839,7280.0 % (fitted)−5.763
sign 9,0,2,1fix7163,306166,422−1.9 %+0.114
sign 12,0,3,1 u5l2 (L200)fix10255,219254,817+0.2 %+0.050
verify 6,0,1,1fix11150,198150,873−0.4 %−0.190
verify 6,0,1,1fix12150,198151,645−1.0 %+0.019
verify 1,1,1,1fix1284,05882,184+2.3 %+0.094
verify 24,0,2,1 u2l19 (L200)fix12840,023842,345−0.3 %−2.225
verify 24,0,2,1 u2l19, route_hardfix12840,023842,267−0.3 %−1.047
verify 24,0,2,1 u2l19, route_hardfix13840,023827,202+1.5 %+0.008
verify 12,0,1,1fix13234,744233,052+0.7 %+0.031
sign 4,0,1,1fix1388,47988,532−0.1 % (fitted)+0.024
sign 8,0,3,1fix13156,661156,6640.0 % (fitted)+0.159
sign 8,0,2,0 (no compress machine)fix13125,237125,2370.0 % (fitted)+0.397
sign 8,0,2,1, 150-DSP multiplierfix13188,750188,537+0.1 %+0.103
verify 1,1,1,1 (constant ROM)fix1486,30884,435+2.2 % (ROM fitted)+0.072

The fix9 rows and the fix13 signers are the fit, so 0.0 % there is by construction, not a test. The others are the test. The 12-machine verifier sits between the two fitted verifiers (6 and 24) and lands at +0.7 %. The signer rows above were predicted with the 2026-10-20 refit, and the older signers moved with it (8,0,2,1 +0.1 %, 12,0,3,1 0.0 %, the fix7 9,0,2,1 −2.7 %). The lean 8,0,2,1 was routed after the refit and was not part of it: +0.1 %. The 1,1,1,1 core shows the fit’s weak spot: with one machine, the fixed controller and key loader are most of the core, and the controller’s fixed and per-machine parts were fitted on 6 and 24 machines.

Throughput in simulation (native RHDL, 205 MHz assumed; measure/native-results.tsv):

BuildSimulatedTunerModel error
sign 8,0,2,1 (fix10)46.46 cycles = 4.41M/s4.06M/s−8 %
sign 9,0,2,1 (fold10 line)4.58M/s4.57M/s−0.2 %
sign 12,0,3,16.42M/s6.09M/s−5 %
verify 6,0,1,1 (fix11)134.93 cycles = 1.52M/s1.50M/s−1 %
verify 2,0,1,10.53M/s0.50M/s−6 %
verify 14,0,1,13.68–3.75M/s (time-bounded)3.70M/s~0 %

Not proven yet.

  • No whole chip has been routed: sign, verify and the SHA line together.

  • The L200 verifier (24,0,2,1) meets timing by only 0.008 ns, and only with the hard route directives, on fix13 (job 007zzq). It has not been routed on fix14, whose constant ROM adds LUTs (the 1,1,1,1 verifier lost 0.022 ns of slack to it), or with default directives. On fix12 it missed by 2.225 ns (007zzg), or 1.047 ns with the hard route directives (007zzj), with failures spread over all 24 machines. The Tuner plans resources, not timing; near ~65 % of the device read the timing verdict on screen as a measurement of one route, not a promise.

  • No Ed25519 build has run on the card.

  • DSig verification is a model. DSig is building it.

  • Latency is checked against simulation on four builds, not routed hardware:

    BuildIsolated (cycles)Saturated median / p90Peak in flight
    sign 1,1,1,0 (small)22,240——
    sign 8,0,2,140,446 (model 40,406)45,431 / 55,8441,026 (model 952)
    verify 1,1,1,152,67063,026 / 81,73886 (model 69)
    verify 6,0,1,152,350 (model 52,392)54,533 / 72,184404 (model 393)

    The Tuner shows the mean (Little’s law). At full load the p90 is 20–30 % above the median.

  • The strict and batch verify modes are models.

§7. Every cost constant

All costs are in crates/ed25519/src/frontier.rs. They are routed on the fix9 RTL unless marked fitted or derived.

ConstantValueUnitSource
fb_machine14,615 / 225 / 25 / 32LUT / DSP / BRAM36 / URAMrouted 007zq, +0.848 ns
verify_machine_known_key13,863 + 228 / 225 / 25 / 56samerouted 007zt; +228 fitted
cp_machine16,569 / 225 / 2 / 64samerouted 007zu
key_loader14,518 / 225 / 10 / 48samerouted 007zv
sha_ring4,315LUTrouted 007zx
scalar_ring7,871LUTfitted to 4 signers (2026-10-20)
sign_controller10,099LUTfitted to 4 signers
sign_controller_fused3,115LUTfitted to 8,0,2,0 (one core)
FB_IN_CORE_LUT−1,505LUT per fixed-base machinefitted to 4 signers
CONST_ROM_LUT750LUT per field machinefix14, one core (007zzr against 007zzi)
verify_scalar_ring2,408LUTfitted with the verify controller (2026-10-18)
verify_controller30,657LUTfitted
VERIFY_PER_MACHINE_LUT228LUT per verify machinefitted
bram_layout (fb / verify)14,615 / 57 BRAM36 / 0 URAM; 14,094 / 57 / 24routed 007zy, 007zz
LUT_BANKS_LUT22,830LUT per machinerouted 007zza, 007zzb
lean_mul+4,440 / −75LUT / DSP per multiplierrouted before the fixes
small_signer29,055 / 248 / 40 / 32routed (fix4), +0.306 ns
SHA_CLIENT_LUT1,500LUT per coreestimate
verify_machine_strictfb + 2,500 LUT, +22 BRAM36derived, not built

The budget constants:

ConstantValueWhy
BASE_LUT / BASE_DSP420,000 / 4,500the engines’ budget; 485k / 4,520 includes the 65k / 20 SHA line default
dynamic-region BRAM361,776the shell’s region (3,552 BRAM18), not the device’s 2,016
U280_URAM960

§8. Limits

  • DSig slice counts. Plans with 3 or 6 slices are marked not buildable: DSIG_SLICES builds 2, 4 or 8.
  • Lending is greedy. It is checked by the scaling tests, not proven optimal.
  • One RTL at a time. The costs describe fix9 to fix12. Change the RTL and the costs must be refitted. The out-of-sample check is the alarm.

§9. Working on it

  1. Change a cost in frontier::slimmed_costs, and write its source next to it (job, date, WNS).
  2. Run cargo run --release --example build_configs -- measure/configs to regenerate the grid and predictions.tsv.
  3. Export and route a plan (measure/README.md).
  4. Run python3 measure/pull_results.py and cargo run --release --example predict_builds. Read the error column.
  5. A fitted number is only trusted once a core it was not fitted to lands within a few percent.

Help wanted. Each of these is pure Rust and needs no FPGA:

  • Timing from the table. ROUTED is typed in by hand. Generate it from measure/results.tsv in build.rs, so a pulled route shows up on screen with no edit.
  • The one-machine fit. The 1,1,1,1 verifier is +2.3 % LUT and +4.5 % URAM, the weakest prediction. Fit the controller’s fixed part on a one-machine core and check that the other cores stay within 1 %.
  • Latency percentiles. The Tuner shows the mean loaded latency. The measured p90 is 20–30 % higher. Fit a p90 factor from the four runs in section 6 and show it beside the mean. ED25519_ISOLATED=1 and the saturated runs print every number you need.

§10. Glossary

TermMeaning
profile a,b,c,dsign: field machines, SHA rings (0 = shared line), scalar rings, compress machines; verify: machines, SHA rings, scalar rings, compress (always 1)
uNlMN machines with banks in UltraRAM, M in LUT RAM, the rest in block RAM
fixNthe Nth timing-fix revision of the RTL (fix9 met 205 MHz on the L100 cores)
OOCVivado out of context: one module routed without the shell
WNSworst negative slack; ≥ 0 meets 205 MHz
measured / modelrouted or simulated / computed from the cost tables or cycle model
fittedsolved from routed whole cores (total less routed blocks)
buildablethe RTL can build exactly this plan
nextthe LUTs the next faster build needs, and what it delivers

§uBFT evidence boundary

The uBFT slot panel reports projected cryptographic time only. It excludes network, memory visibility, recovery and application work. It does not display a speedup against the HLS wrappers: those measurements use a one-byte message, whereas a selected service may use a different message layout and key policy. The historical 161.3 MHz value is the linker-selected frequency after timing failure, not a runtime readback. The historical whole-design LUT/DSP total includes the shell and is only a planning allowance for a replica; its missing BRAM/URAM values are unknown, not measured zeros. A plan fitting these numbers does not establish that a complete RHDL system fits the card.

Structs§

App
The planner’s state.

Enums§

Control
One row of the control list.

Functions§

draw
Draw one frame.
next_step
The next faster build of slot with more LUTs and everything else as in share: (extra LUTs, its capacity), probing in 1k steps up to 64k. Builds come in whole blocks (a field machine is ~11k LUTs), so a rate that stays flat while LUTs grow is waiting for this step.
run
Run the planner in the terminal.
run_on
Run the planner on any backend until Q.
snapshot
Render app into text (for tests and documentation).