Expand description
A folded SHA-512 core: S round stages in a ring, S / 80 blocks per
clock, for lines smaller than one full pipeline.
┌──────────────────── recirculate (round < 80) ───────────────┐
▼ │
ShaIn ─▶ [skid] ─▶ mux ─▶ round ─▶ round ─▶ … ─▶ round ──┬─────────────┘
stage 0 stage 1 stage S−1 └─▶ [final add] ─▶ ShaOut
(round = 80)§Why this exists
Problem. The full Sha512Pipeline gives one
block per clock for ~43k LUTs. The Ed25519 modules need far less: the
default Ed25519 chip hashes about 25M blocks per second, an eighth of a
block per clock. Before this core the line came only in whole and half
blocks per clock (the half-rate “folded” core was a plan), so most of its
LUTs bought nothing, and a line shrunk below ~23k could not be built.
Reasoning. All 80 rounds are the same step with a different constant.
A block does not need 80 stages of its own: it can go round a ring of S
stages 80 / S times. Every stage carries the block’s round counter, and
the constant K_t is read from a 128-entry ROM by that counter (a 7-input
function per bit, two LUT6 each), so a stage serves any round. The ring
holds S blocks at once, each for 80 cycles: S / 80 blocks per
clock, and the latency stays 82 cycles.
Decision. One core per stage count S that divides 80:
Sha512Folded2, Sha512Folded4, Sha512Folded5,
Sha512Folded8, Sha512Folded10, Sha512Folded16,
Sha512Folded20 and Sha512Folded40 (FOLDS). S = 80 would be
a full pipeline with a ROM per stage, so the line uses
Sha512Pipeline there. The cores share one
control kernel (fold_control) and differ only in their ring segment
(FoldSeg10 and friends: at most ten children each, every stage wired
as one expression, because RHDL lowers array-element writes to
whole-array copies).
The planner (crate::planner) builds the line from any mix of folded
cores and full pipelines, the fastest that fits the line’s LUTs, so the
line’s rate moves in steps of 1/40 block per clock instead of 1/2.
Status. Every size is bit-exact against sha2::compress512 in RHDL
simulation at its full rate and under back-pressure, and lowers to
Verilog that passes RHDL’s syntax check; the 2-, 5- and 10-stage Verilog
matches the Rust model cycle by cycle in Icarus (tests/folded.rs). Every
core routes out of context at 4.878 ns (205 MHz) with positive slack;
the planner uses those routed LUTs (planner::ROUTED_LUT), and
folded_lut remains the older Yosys estimate.
§Ports and flow control
The same ShaIn and ShaOut as the full pipeline, but with
back-pressure: ShaCoreOut::ready is low while the ring is full. A
client presents a block and holds it until ready is high in that
cycle (a block presented while ready is low is ignored).
Inside, a one-entry skid buffer holds the accepted block until the slot arriving at stage 0 is free. A slot is busy while its block still has rounds to do; it frees the cycle its block finishes round 79, and the buffered block takes it. Blocks finish in the order they entered.
§Where to go next
| You want to… | Start here |
|---|---|
| see one stage | FoldRound, fold_round_kernel |
| see the ring and the skid buffer | fold_control |
| change what the planner thinks a fold costs | folded_lut, crate::planner |
Structs§
- Fold
Control - What the ring control decides in one cycle.
- Fold
Round - One registered ring stage: performs round
tof whatever block arrives. - Fold
Seg2 - Two ring stages.
- Fold
Seg4 - Four ring stages.
- Fold
Seg5 - Five ring stages.
- Fold
Seg8 - Eight ring stages (two four-stage segments).
- Fold
Seg10 - Ten ring stages (two five-stage segments).
- Fold
Seg16 - Sixteen ring stages (two eight-stage segments).
- Fold
Seg20 - Twenty ring stages (two ten-stage segments).
- Fold
Seg40 - Forty ring stages (four ten-stage segments).
- Fold
Stage - A block’s state between stages, with its round counter.
- Sha512
Folded2 - 2 stages: 1/40 block per clock.
- Sha512
Folded4 - 4 stages: 1/20 block per clock.
- Sha512
Folded5 - 5 stages: 1/16 block per clock.
- Sha512
Folded8 - 8 stages: 1/10 block per clock.
- Sha512
Folded10 - 10 stages: 1/8 block per clock.
- Sha512
Folded16 - 16 stages: 1/5 block per clock.
- Sha512
Folded20 - 20 stages: 1/4 block per clock.
- Sha512
Folded40 - 40 stages: 1/2 block per clock.
Constants§
- FOLDED_
LATENCY - Cycles from accepting a block (into the skid buffer) to presenting its
result when the ring has room: the buffer, 80 rounds and the output
register. The same as the full pipeline’s
LATENCY. - FOLDS
- Ring stage counts that have a core, smallest first.
- K128
- The round constants padded to 128 entries, so a 7-bit round counter can index them (entries 80–127 are zero and never used).
Functions§
- fold_
control - The ring control, the same for every stage count.
leavingis the state leaving the last stage this cycle: it recirculates into stage 0 while it has rounds left, and is added to its chaining value when it has done round 79. A free slot takes the buffered block; the buffer takes the client’s block when it is empty or being placed (ready). - fold_
round_ kernel - Round
twithK_{t+1}from the ROM for the next round’s look-ahead. - fold_
seg2_ kernel - Chain the stages of
FoldSeg2in series. - fold_
seg4_ kernel - Chain the stages of
FoldSeg4in series. - fold_
seg5_ kernel - Chain the stages of
FoldSeg5in series. - fold_
seg8_ kernel - Chain the stages of
FoldSeg8in series. - fold_
seg10_ kernel - Chain the stages of
FoldSeg10in series. - fold_
seg16_ kernel - Chain the stages of
FoldSeg16in series. - fold_
seg20_ kernel - Chain the stages of
FoldSeg20in series. - fold_
seg40_ kernel - Chain the stages of
FoldSeg40in series. - folded_
lut - Estimated LUTs of a core with a ring of
stagesround stages: 1,020 per stage (round, schedule step, constant ROM, counter) plus 3,450 for the skid buffer, the stage-0 mux and the final addition. Fitted to Yosyssynth_xilinx -family xcupof the 2-, 5- and 10-stage cores (5,491, 8,550 and 13,654 LUTs). An estimate: Yosys is not Vivado, and nothing here is placed or timed. - sha512_
folded2_ kernel - The ring control around
Sha512Folded2’s segment. - sha512_
folded4_ kernel - The ring control around
Sha512Folded4’s segment. - sha512_
folded5_ kernel - The ring control around
Sha512Folded5’s segment. - sha512_
folded8_ kernel - The ring control around
Sha512Folded8’s segment. - sha512_
folded10_ kernel - The ring control around
Sha512Folded10’s segment. - sha512_
folded16_ kernel - The ring control around
Sha512Folded16’s segment. - sha512_
folded20_ kernel - The ring control around
Sha512Folded20’s segment. - sha512_
folded40_ kernel - The ring control around
Sha512Folded40’s segment.