Skip to main content

Module config

Module config 

Source
Expand description

The planner: predicts throughput and resources for every profile and picks one from a LUT and DSP budget.

A Profile is fb/sha/sc plus fused; written as four numbers (15/11/3/1) the last one is 1 for one batch-compress machine and 0 for fused mode, the same order as ED25519_SCALABLE_PROFILE. Budgets (Budget) are percentages of the project caps: LUT_CAP (260,000; up to 200 %) and DSP_CAP (7,000; up to the U280’s 9,024). The planner reports the smallest LUT percentage that still gives a working signer (min_lut_percent) and the DSP percentage beyond which more DSPs do not help (useful_dsp_percent).

§Throughput model

Profile::cycles_per_sign is the slowest of these stages:

StageCycles per signature15/11/3/1
fixed-base machinesFB_BUNDLES / fb / UTIL_MACHINE (fused: plus the SHA term)26.94
SHA-512 rings3 · 81 / sha / UTIL_SHA24.93
scalar rings2 · 32 / sc / UTIL_RING23.70
batch compressionCP_BUNDLES / CP_BATCH / UTIL_MACHINE13.63
compress credits(FB_BUNDLES·32 + CP_BUNDLES·CP_CONTEXTS + CREDIT_OVERHEAD) / 204823.25
admission22.00

The utilizations are conservative (the fixed-base machines measured 0.99–0.997); CREDIT_OVERHEAD is fitted to measured runs. 15/11/3/1 measured 26.43 against the predicted 26.94.

§Resource model

yosys_calibrated uses Yosys leaf maps (in mapping/) plus structural adjustments for blocks not yet mapped; structural is a hand estimate. DSPs trade for LUTs the way Vivado does under synth_design -max_dsp: a multiply tile without a DSP becomes fabric, and spare DSPs absorb wide adders (USE_DSP).

The largest uncertainty: about 8,600 of each multiplier’s LUTs are its 225 chain additions P = PCIN + A·B. Yosys packs that pattern into DSPs for 7-series but not UltraScale+; Vivado infers such cascades. calibrated assumes packing (15/11/3/1 ≈ 219k LUT); with yosys_calibrated(false) it would not fit 260k. Only Vivado settles it.

Every resource number here is an estimate, and the clock (DESIGN_MHZ) is a target until routed.

§Using it

cargo run --release --bin ed25519_plan -- --lut 100 --dsp 100 --mhz 205
cargo run --release --bin ed25519_plan -- --lut 100 --dsp 100 --target 7000000
cargo run --release --bin ed25519_plan -- --sweep
cargo run --release --bin ed25519_plan -- --lut 100 --dsp 100 --out plans/s100
cargo tuner-ed25519        # at the repository root: the planner TUI, Ed25519 only

--out writes the plan, its ED25519_SCALABLE_PROFILE value and a Vivado synth.tcl that rejects an over-budget result. The fast way to iterate on the model is tools/hostmodel (no hardware build).

Structs§

BlockCost
One block’s resources, per instance. Profile::estimate multiplies each row by the instance count and then trades DSPs for LUTs using tiles/lut_per_tile and adder_dsps/lut_per_adder_dsp.
Budget
Planner request: resource allowances and the clock to project at.
CostTable
Per-block costs used by Profile::estimate. Built either by structural (hand estimate) or yosys_calibrated (Yosys leaf maps plus structural adjustments); replace rows with Vivado measurements as they become available.
Estimate
Resource and throughput estimate of a profile under a DSP limit, as returned by Profile::estimate. All values are model output, not measurements.
Profile
A buildable signer profile: how many of each replicated block the signer instantiates. Profile::env_value turns it into the ED25519_SCALABLE_PROFILE string that build.rs reads.

Constants§

CP_BATCH
Points per compression batch (one batch inversion amortized over them).
CP_BUNDLES
Bundles of one 32-point batch compression (compiler output); shared by the CP_BATCH points of the batch.
CP_CONTEXTS
Batch-compress machine contexts (barrel slots, each holding one batch).
CREDIT_OVERHEAD
Credit hold time in cycles beyond the two programs’ issue latency (queueing, batch filling, hashing). Calibrated from native simulation: with 1,024 credits, 12/6/2/1 and 13/8/2/1 measured 45.7 and 44.1 cycles/signature, i.e. ~45k cycles per credit against 15.7k + 22.0k of issue latency for the programs of that time (492 fixed-base bundles, the older compress machine). With today’s programs the issue latency in the formula is FB_BUNDLES·32 + CP_BUNDLES·CP_CONTEXTS = 12,544 + 27,072 cycles. Rechecked 2026-10-19 on fix13 8,0,2,1: 1,026 signatures in flight at 46.46 cycles/signature is a mean hold of ~47.7k cycles, i.e. 39.6k + 8.1k.
DESIGN_MHZ
Design clock in MHz (the project’s target frequency, not yet a routed result). Used to turn cycles per signature into signatures per second.
DEVICE_BRAM36
Physical BRAM36 count of the xcu280. plan rejects profiles above it; there is no separate project BRAM cap.
DEVICE_DSP
Physical DSP48E2 count of the xcu280 (device data sheet). Hard ceiling on any DSP budget.
DEVICE_LUT
Physical LUT count of the xcu280 (for reference; budgets use LUT_CAP).
DSP_CAP
Project DSP cap (100 %), in DSP48E2 blocks. Below the device’s DEVICE_DSP, so DSP percentages may exceed 100 (up to ~128.9 %).
FB_BUNDLES
Bundles (issue slots) in the fixed-base program, from the microcode compiler (see programs). Each bundle occupies one machine slot, so this is the machine time per signature in cycles at full utilization.
FUSED_BUNDLES
Bundles of the fused fixed-base + per-point inversion program (compiler output). Used instead of FB_BUNDLES in fused mode.
LUT_CAP
Project LUT cap (100 %), in LUTs. A project budget, well below the device’s DEVICE_LUT.
SIGN_CONTEXTS
Sign contexts (requests in flight). Caps the compress credit pool.
UTIL_MACHINE
Sustainable utilization of a barrel field machine (0.997 measured in simulation; 0.97 kept as margin). Planned builds on the shared SHA line (native simulation, 2026-10-16): 9,0,2,1 ran 41.83 cycles/signature on a full line (effective utilization 1.04; this model says 44.90), 44.76 on a fold10 line (0.97) and 4,0,1,1 96.18 on fold4 (1.02; model 101.03), so the margin covers the slowest measured line.
UTIL_RING
Assumed sustainable utilization of a scalar ring (not measured).
UTIL_SHA
Sustainable utilization of a SHA-512 ring, as a fraction of its ideal rate (conservative simulation fit, see cycles_per_sign).

Functions§

calibrated
The planner’s default cost table: yosys_calibrated with packed post-adders. Use yosys_calibrated(false) for the pessimistic bound.
candidates
Every profile the planner considers: 1..=40 fixed-base machines, 1..=24 SHA rings, 1..=6 scalar rings, with and without fusing (the same ranges as crate::frontier). The search is exhaustive, so these ranges bound what the planner can return; at 200 % of the LUT cap the best profile stays well inside them.
describe
Human-readable report of a plan: profile, budget, resource estimate with its source, cycle model and the synthesis settings to use.
min_lut_percent
Smallest LUT percentage at which some profile fits under dsp_percent (the lower end of the LUT slider), counting only profiles whose BRAM fits the device. Infinity if no candidate exists.
plan
Best profile for a budget: highest rate (capped at the target), then fewest LUTs, then fewest DSPs. None when nothing fits. A profile fits when its LUTs, DSPs and BRAM36 are within the budget and the device.
plan_json
JSON record of a plan (schema scalable-plan-1). status is always estimate-unmeasured; measured counts come from the measured.json that synth_tcl writes.
structural
The built-in structural estimate: hand-counted from the block structure, never synthesized. The crate’s unit tests use it because it does not depend on mapping results.
synth_tcl
Vivado out-of-context synthesis gate enforcing the plan’s budget.
useful_dsp_percent
DSP percentage above which no profile within 200 % LUTs uses more DSPs: the DSP count of the best plan with the largest LUT and DSP allowances.
write_plan
Write plan.json, plan.txt, synth.tcl and constraints.xdc to dir. Nothing is launched; the files are inputs for a reserved synthesis host. The XDC constrains the clock port to the budget’s assumed clock (period in ns = 1000 / MHz).
yosys_calibrated
Leaf costs from Yosys 0.55 synth_xilinx -family xcup maps of the generated netlists (mapping), with packed selecting whether the multiplier’s 225 column-chain additions are absorbed into the DSP48E2 post-adders (P = PCIN + A*B).