Skip to main content

Module fabric_pipe

Module fabric_pipe 

Source
Expand description

fabric_pipe — the compiled residual circuit cut into register stages: a new input every clock, a short period.

fabric_rtl lowers a dispatch-free residual to a dataflow circuit that resolves in one clock, so its period is the propagation delay of the whole residual (for the Horner polynomial, two chained 64-bit multiplies and three carry chains). This module keeps the same op vocabulary and pipelines that circuit:

  1. Carry-save lowering (carry_save_lower). Every additive tree (the Add/Sub/Mul ops a value is built from, through intermediates read exactly once) becomes one set of rows. A variable multiply contributes one masked, shifted copy of its multiplicand per multiplier bit; a constant multiply one shifted row per canonical signed digit; a subtraction the inverted rows plus their +1s; constants fold into a single row. A tree of 3:2 compressors reduces the rows to two, and one Kogge-Stone carry-propagate add resolves them. The lowered circuit holds only bitwise ops and constant shifts, so no op is more than one gate deep and a register can sit between any two of them.
  2. Scheduling (schedule_pipeline). Ops take the earliest stage whose accumulated depth stays within a per-stage budget, in the units of op_delay. Wiring (is_wiring: a constant shift, or a bitwise op with a constant) has no depth and no stage of its own: each reader rebuilds it from its operand’s register, so only computed values cross registers.
  3. Emission (emit_fabric_pipelined_verilog). Inputs register into stage 0 (Inputs::Registered), or stage 0 reads the ports the registers upstream hold (Inputs::Ports); each value is delayed through as many registers as stages separate it from its last reader, and the result registers after its stage. The result of the input presented before clock t is on result after clock t + latency - 1.

simulate_pipeline is the cycle model of exactly those registers, so a schedule is checked without a simulator, and the lowering takes a width so our SAT can check it exhaustively at a narrow one.

Structs§

PipelineSchedule
Where every op of a residual computes, and which op leaves the pipeline.

Enums§

FinalAdd
How the two words a sum’s compressor tree leaves are added.
Inputs
Where a pipeline’s first stage reads its inputs.
SumSharing
How a sum that other sums read is lowered.

Constants§

DECISION_CELLS_BUDGET
The stage budget a decision is cut to on standard cells, in the units of op_delay: three carry chains and their selects. A register is ~20 µm² of flip-flop a bit there, where on a fabric it rides in a LUT’s slice, so a decision takes few stages and reads its ports (Inputs::Ports); each compare takes the sums it reads into its own rows (SumSharing::Fold), resolved by one add synthesis picks (FinalAdd::Native). MEASURED (2026-10-18, K1’s decide so lowered, its ports read, Sky130 HD: yosys 0.33 with OpenLane v1’s DELAY 0 ABC script at a 2 ns target, OpenSTA at the typical corner, no wires): 18 = 5 stages, 44,306 µm² at 4.65 ns; 30 = 3 stages, 34,005 µm² at 3.57 ns; 36 = 2 stages, 30,843 µm² at 5.03 ns; one stage, 32,013 µm² at 7.71 ns. Without the folds, 27 and 30 were 32,750 µm² at 4.10 ns and 31,559 µm² at 4.34 ns.
DECISION_CHAIN_BUDGET
The stage budget a decision is cut to on a fabric with carry chains, in the units of op_delay: one unlowered add or subtract (a carry chain, 9) and an AND. The XORs that finish a compare’s sign start the next stage, so the mask a select fans out to its 64 bits leaves a register, never the end of a carry chain. MEASURED (2026-10-17, K1’s decide, Artix-7 fabric map, yosys 0.33 synth_xilinx + nextpnr-xilinx, seeds 1-3, median): 12 (the compare and its select in one stage) = 852 LUTs at 119.2 MHz, 10 = 848 at 147.3, 9.6 = 784 at 145.4, 6 = 848 at 147.8; at 8 and 9 one seed in three does not finish routing within 300 s.
FOLD_ROW_LIMIT
The words a folded sum may bring into each reader’s rows; a larger sum resolves once and is read as one word.
GEMM_MUL_BITS
The int8 width of the GEMM array’s multiply tiles.
GEMM_TERM_BUDGET
The term stage budget of the GEMM array, in the units of loop_cell_delay: the operand arithmetic in one stage, the int8 multiplies in the next.
HORNER_SEQ_BUDGET
The stage budget fabric_horner_seq is cut to, in the units of op_delay. MEASURED (2026-10-17, the synthesis sequence of OpenLane’s synth.tcl under host yosys 0.33, AREA 0, abc target 1 ns, sky130_fd_sc_hd tt_025C_1v80, worst stage by abc stime): budget 4 is 1.36 ns over 311,772 µm² of cells, 5 is 1.43 ns over 258,289 µm², 6 is 1.99 ns, 7 is 2.65 ns; the single-stage residual is 13.85 ns. Five is the knee: the next tighter budget buys 5% of period for 21% more area.

Functions§

carry_save_lower
Carry-save lowering of a residual at datapath width width (64 on silicon; narrower so our SAT can check the lowering exhaustively), each shared sum resolved once (SumSharing::Resolve). Only the values the result depends on are lowered. Returns the new op list, which holds no Add, Sub or Mul, and the index of its result.
carry_save_lower_with
carry_save_lower with the shared sums lowered as sharing says and each compressor tree’s last two words added as final_add says. Under SumSharing::Fold an add or subtract read only by adds and subtracts never resolves, however many read it, and one its rows fold into resolves only for its other readers; a multiply read more than once still resolves once. Under FinalAdd::Native the lowering holds one Add per resolved sum and nothing else additive.
csd_digits
The canonical signed digits of c mod 2^width: (shift, ±1) pairs whose signed sum of powers of two is c, no two adjacent. The top digit is taken positive, since ±2^(width-1) agree mod 2^width.
decision_ops
A decision fabric (decision_fabric_from_source: arithmetic cells and compare-selects) as a residual in the pipeline’s op vocabulary, and the index of its result. A compare becomes the mask of its outcome, all ones or zero (compare_mask); a select is e ^ ((t ^ e) & mask). Every op is emitted once, so a predicate many selects test has one mask. A fabric with any other cell (a functional unit, a memory or heap tile) has no combinational form and is refused.
dot_unrolled_source
The u-wide unrolled int8 dot product in LOGOS: each iteration accumulates u independent products, so the compiler places u multiply tiles that fire together, u MACs per clock.
earliest_schedule
Every computed value in its earliest stage: the shortest pipeline whose stages each stay within budget.
emit_csa_multiplier_verilog
A parameterized Verilog module {module}: an unsigned AW×BW multiplier as a tree of 3:2 compressors over its partial-product rows, registered after CUT tree levels and (with FINAL) once more before a Kogge-Stone final add. One generator for every consumer, so the BigInt limb multiplier and the FPU carry the same tree under their own names.
emit_fabric_pipelined_verilog
Emit the scheduled residual as a pipeline: module fabric_{name} with ports clk, in0.., and the registered result. Every assignment is its own net, so no operator’s signedness leaks into another’s.
emit_horner_seq_verilog
benchmarks/silicon/fabric_horner_seq.v: the RTL the flow hardens as fabric_horner_seq.
gemm_mac_array_verilog
benchmarks/silicon/gemm_mac_array.v: the eight-wide int8 MAC array cgra_arr8 as the pipelined loop CGRA (operands, then products, ahead of a carry-save accumulator), with its pin-light top.
horner_seq_pipeline
The residual fabric_horner_seq hardens: the REAL compiler’s residual of the Horner polynomial (POLY_BODY), carry-save lowered at 64 bits and cut to HORNER_SEQ_BUDGET.
is_wiring
Wiring costs no logic depth: a shift by a constant moves bits, and a bitwise op with a constant operand is constant bits or inverters. It takes its operands’ stage, and each reader rebuilds it from their registers.
known_bits
The bits of each value its construction fixes, as (mask of known bits, their values): shifts bring in zeros, masks and constants pin bits, a carry row’s bit 0 is zero. A register on a known bit holds a constant, which synthesis removes, so a schedule is charged only for the live bits it holds.
latest_schedule
Every computed value in its latest stage of that same shortest pipeline.
matmul_array_top
A pin-light top for a MAC array’s CGRA cgra_{name}, so placement and routing measure the array’s paths rather than its I/O: a serial input shifts into the loop bound, the finished result latches, its parity drives one pin.
op_delay
The logic depth of one op, in units of a two-input XOR at the synthesis corner. Wiring is zero. A carry chain or a multiplier left unlowered is one indivisible op, so it occupies a stage of its own whatever the budget.
schedule_pipeline
Cut a residual into the shortest pipeline whose stages each stay within budget (in the units of op_delay), placing every computed value so the pipeline holds the fewest live register bits. An op deeper than the budget on its own still gets a stage, alone.
simulate_pipeline
The cycle model of the emitted pipeline. Before each clock t the input vector stream[t] is presented; the returned vector holds the result register after each clock. Registers start at zero.