Expand description
systolic — the weight-stationary spatial GEMM tile (Phase 1).
Today’s GEMM lowering is a 1-D unrolled dot-product reduction (P multiply tiles → one accumulator → one output per operand pass): a MAC lane. A real accelerator (TPU MXU, a SambaNova PCU in GEMM mode) keeps the weights stationary in a 2-D array of PEs, streams activation rows through, and produces a whole output row in parallel — so each weight is read once and reused across the entire activation stream (the operand-reuse the reduction lane lacks), and N outputs settle per cycle instead of 1.
A Systolic tile is K rows × N cols of int8 multiply-accumulate PEs. PE(r, c) holds the stationary
weight W[r][c]. Each cycle one activation row A[i][0..K] is applied and one output row
O[i][0..N], with O[i][c] = Σ_r int8(A[i][r]) · int8(W[r][c]), is registered out. eval_systolic is
the reference semantics; emit_systolic_verilog is the registered array; the per-PE datapath
psum + a·w is SAT-certified ≡ its abstract form by the existing placer + bitblast (see the lock).
The datatype is int8 operands accumulated in wrapping i64 (the VM’s Int), so for int8-range inputs the
tile is byte-identical to a plain integer GEMM — and to the VM. Operand truncation is x as i8 as i64,
matched exactly by the RTL’s $signed(x[7:0]) sign-extension, so eval ≡ RTL for ALL inputs.
Structs§
- Fused
Block - A fused transformer-block stage over a weight-stationary GEMM tile (Phase 3): the GEMM, its fixed-point
requantization
(acc·M) >> S(arithmetic shift = floor-divide by2^S), a per-column bias add, and a ReLU — all fused into ONE spatial pass so the intermediates are streamed, never materialized to memory. - Systolic
- A weight-stationary GEMM tile:
kcontraction rows ×noutput columns of int8 MAC PEs, weights baked. - Systolic
Os - An output-stationary tile: an
r×cgrid of accumulators computingO = A·Wwith contraction depthk(Ais r×k row-major,Wis k×c row-major,Ois r×c row-major). Both operands stream in; O stays put.
Enums§
- Systolic
Schedule - The systolic microarchitecture dial. Both schedules compute the identical GEMM (
eval_systolic); they trade against each other rather than dominate, so both stay live (see the dominance characterization inpipelined_systolic_lock).SystolicSchedule::Combinationalaccumulates each column with a K-deep adder tree — one output row per clock, zero fill latency, but the critical path grows with K.Pipelinedregisters the activation (east) and partial sum (south) at every PE so the only path between flip-flops is one mul + one add — the critical path is K-INDEPENDENT (a real MXU stays at GHz at 128×128), at the cost ofK+N−1fill latency and the extra registers. Default isCombinational(smallest; correct for low clocks). - Weight
Source - Where a PE array’s weights come from: baked into the netlist as constants, or loaded at run time through
a row port (
w_load,w_row,w_data= one packed row ofnweights) — the spatial IR’sCompute(MatmulTiles)stage on our fabric loads its weight block, then streams activations. - Weight
Start - What a loaded array’s weight registers hold before their rows are first loaded.
Constants§
- ACC_
BITS_ FULL - Default accumulator width — 64-bit, so
emit_systolic_pipelined_verilog_bitsis bit-identical to the i64 model for EVERY input. Real int8 MXUs (and the taped tiles) use a narrowerACC_BITS_MXUaccumulator. - ACC_
BITS_ MXU - The TPU-MXU-standard int8 accumulator width (int32). Narrows the inter-PE partial-sum bus so a systolic grid routes without congestion; lossless for int8 with contraction depth K where |Σ a·w| < 2³¹.
Functions§
- bist_
tile_ weights - The stationary weights a signed-off weight-stationary tile bakes: a fixed int8 pattern,
k*nrow-major. - emit_
loadable_ vs_ baked_ testbench - A bench that loads
sys’s weights into the loadable array while both arrays sit in reset, releases both on the same edge, streamsacts(m rows) through both, and compares every output every cycle. PrintsOUT o <i*n+c> <value>for the loadable array’s aligned output rows (row i sampled after edge i+L-1),LATENCY <L>, andPASS:iff the two arrays never differed. - emit_
systolic_ bist_ wrapper - The self-test wrapper a weight-stationary tile
coreis signed off in: a 64-bit LFSR drives thekint8 activation lanes and thenregistered outputs fold into a MISR, so onlyclk,rstandsigcross the block’s boundary and no pad shapes its timing. - emit_
systolic_ os_ bist_ wrapper - The self-test wrapper an output-stationary tile
coreis signed off in: the LFSR drives therwest activation andcnorth weight lanes, and ther × cstationary accumulators fold into the MISR through registers, row by row. Each row’s accumulators fold into a row word, the row words into two half-folds (foldA,foldB), and the MISR XORs those. The fold stays off the critical path, so the block’s critical path is the array’s PE, and no register reads more than one row’s accumulators, so no fold gathers every accumulator at one point of the die. - emit_
systolic_ os_ pipelined_ verilog - Emit the output-stationary pipelined array (int8) as synthesizable Verilog. See
emit_systolic_os_pipelined_verilog_bits. - emit_
systolic_ os_ pipelined_ verilog_ bits - Emit the output-stationary pipelined array at precision
bitswith a full (64-bit) accumulator. - emit_
systolic_ os_ pipelined_ verilog_ bits_ acc - Emit the register-staged output-stationary array at precision
bits. Ports:clk/rst,aw{i}(west activation stream for row i),wn{j}(north weight stream for col j), andacc{i}_{j}(the stationary accumulator outputs, continuously readable). Per PE:a_reg(flows east),w_reg(flows south),acc_reg <= acc_reg + a_in·w_in. The only combinational path between flip-flops is one mul + one add — K-independent, exactly like the weight-stationary pipelined tile. Skew of the streamed operands is applied on-chip (row i / col j delayed i / j cycles), so the caller drives un-skewed streams. - emit_
systolic_ os_ streaming_ verilog - Emit the output-stationary array for tile after tile. Ports:
clk/rst,first(high on each tile’s first contraction beat),aw{i}/wn{j}(the un-skewed operand streams ofemit_systolic_os_pipelined_verilog_bits_acc) andres{i}_{j}(the finished sums of the previous tile).firstrides the activation wavefront, so it reaches PE(i,j) with the tile’s first products: there the PE moves its sum intores_regand restarts from that product — no reset and no idle beat between tiles. Columnj’s result waitsos_streaming_deskewcycles, so each row is readable all at once atos_streaming_result_offset. - emit_
systolic_ pipelined_ loadable_ verilog - A weight-stationary PE array whose weights are loaded through a port and hold what they power up with until then:
pe_array_verilog(.., Loaded(PowerUp)). Cycle-for-cycle identical to the baked array once the same weights are loaded (locked). - emit_
systolic_ pipelined_ loadable_ verilog_ starting emit_systolic_pipelined_loadable_verilogwith its weight registers starting atstart.- emit_
systolic_ pipelined_ verilog - Emit the PIPELINED weight-stationary array (int8) as synthesizable Verilog. See
emit_systolic_pipelined_verilog_bits; the critical path is ONE mul + ONE add (K-independent). - emit_
systolic_ pipelined_ verilog_ bits - Emit the pipelined weight-stationary array at precision
bitswith a full (64-bit) accumulator. - emit_
systolic_ pipelined_ verilog_ bits_ acc - Emit the pipelined, register-staged weight-stationary systolic array at operand precision
bitsand accumulator widthacc_bits. Structure (matcheseval_systolic_pipelined_accregister-for-register): per PE an activation register (a_reg, flows EAST,bitswide) and a partial-sum register (ps_reg, flows SOUTH,acc_bitswide) withps_reg[r][c] <= ps_in + a_in·W[r][c]— the only combinational path between flip-flops is onebits×bitsmultiply + one add, so the critical path does NOT grow with K. On-chip input-skew (row r delayed r cycles) and output de-skew (col c delayed N-1-c) keep the cleanclk/rst/a0..a{k-1}/o0..o{n-1}interface;o{c}on cycletholds output rowt-L(L=K+N-1). Narrowingacc_bitstoACC_BITS_MXUshrinks the inter-PE bus for a congestion-free tape and is lossless while the true accumulation fitsacc_bits(guarded in the lock). - emit_
systolic_ scheduled - Emit the weight-stationary array under the chosen
SystolicScheduleat precisionbits. Both schedules are observationally equivalent (eval_systolic); this is the single retargeting seam an emitter/target selects the microarchitecture through. - emit_
systolic_ verilog - Emit the registered weight-stationary array as synthesizable Verilog. Ports:
clk,rst, thekactivation inputsa0..a{k-1}(64-bit; the low 8 bits are the int8 operand), and thenregistered outputso0..o{n-1}. Weights are baked as signed 64-bit constants (the sign-extended int8). One output row is produced per clock;o{c}on cyclet+1is the dot of the activation row applied at cyclet. - emit_
systolic_ verilog_ bits - Emit the weight-stationary array at a chosen integer precision
bits(8/16/32/64) — the precision dial’s RTL (Phase 4). Operands are the lowbitsof each input, sign-extended; weights baked as sign-extended two’s-complement constants. Matcheseval_systolic_bitsfor ALL inputs. - eval_
fused_ block - Evaluate the fused block:
O[i][c] = ReLU( ((A·W)[i][c] · M) >> S + bias[c] )— one streamed pass, no intermediate tensor written back. Byte-identical to computing the four stages separately (proven by the lock), so the fusion is correctness-preserving; the win is that nothing lands in DRAM between stages. - eval_
systolic - Reference semantics:
O(M×N) = A(M×K) · W(K×N), int8 operands accumulated in wrappingi64.actsism*krow-major (A[i][r] = acts[i*k + r]); returnsOasm*nrow-major. - eval_
systolic_ bf16 - bf16 GEMM: operands rounded to bf16, products and accumulation in f32 (the standard bf16 MAC), returned as
f64.
weightsisk*nrow-major,actsism*krow-major. - eval_
systolic_ bits - Precision-parameterized integer semantics: operands truncated to
bits(8/16/32/64), products accumulated in wrappingi64— the integer precision dial (Phase 4). - eval_
systolic_ f32 - fp32 GEMM: operands, products and accumulation in f32 (the PCU’s native 32-bit FU MAC — Plasticine’s
format), returned as f64.
weightsisk*nrow-major,actsism*krow-major. - eval_
systolic_ os - Reference int8 GEMM for the output-stationary tile:
O[i][j] = Σ_t A[i][t]·W[t][j](wrapping i64). - eval_
systolic_ os_ pipelined - Cycle-accurate output-stationary model — mirrors the RTL register-for-register. Activation
A[i][t]enters rowiskewed byi, flows east; weightW[t][j]enters coljskewed byj, flows south; every cycle each PE doesacc <= acc + a_in·w_in(skew/drain fill zeros contribute nothing). At PE(i,j) on cycleTboth operands carry contraction indext = T-i-j, soacc[i][j]converges toO[i][j]. Returns(O, latency)withlatency = pipelined_os_latency. - eval_
systolic_ os_ pipelined_ acc eval_systolic_os_pipelinedwith an explicit accumulator widthacc_bits— each PE’s accumulator wraps (two’s-complement) atacc_bits, exactly like theacc_bits-wideacc_regin the emitted OS RTL.- eval_
systolic_ os_ pipelined_ o eval_systolic_os_pipelinedwithout the latency — theOmatrix only.- eval_
systolic_ pipelined - Cycle-accurate golden model of the pipelined weight-stationary array — steps the register planes exactly
as the emitted RTL does (activation EAST, partial-sum SOUTH, on-chip skew/de-skew), so the RTL must match
it cycle-for-cycle. Returns
(O row-major, L)whereO≡eval_systolic_bits(the math is unchanged; only the timing differs).actsism*krow-major. - eval_
systolic_ pipelined_ acc eval_systolic_pipelinedwith an explicit accumulator widthacc_bits— the partial-sum register wraps (two’s-complement) atacc_bits, exactly like theacc_bits-wideps_regin the emitted RTL. Withacc_bits = 64this is bit-identical toeval_systolic_pipelined; withACC_BITS_MXUit models the int32-accumulator tape and is lossless whenever the true accumulation fits (guarded in the lock).- eval_
systolic_ pipelined_ o eval_systolic_pipelinedwithout the latency — theOmatrix only, for equivalence tests.- eval_
tiled_ gemm - Compute a
K×NGEMM by TILING intotk×tnsub-tiles (Phase 2). Each weight sub-block is loaded ONCE into the on-chip scratchpad and reused across allmactivation rows;k-direction tiles are accumulated. Byte-identical toeval_systolicon the full matrix — so the tiling is proven correct by equality to the untiled reference (which is itself ≡ the oracle ≡ VM).actsism*krow-major. - eval_
unfused_ block - The UNFUSED reference: the same computation with each stage materialized into its own buffer (a DRAM
round-trip per stage). Equal to
eval_fused_block— the composition proof — but it writes2·m·nintermediate elements the fused pass never does. Returns(result, intermediate_writes). - os_
streaming_ deskew - The cycles column
j’s results wait so a whole row is readable in one cycle atos_streaming_result_offset:c - k - jwhere that is positive. A tile’s period is at least its contractionk, and columnjholds its result for a period fromperiod + i + j + 1, so it covers the row’s read cycle with this delay at every period a tile can have; an array no wider than its contraction waits for nothing. - os_
streaming_ result_ offset - When row
i’s results of a streamed tile are readable:periodcycles after the tile’s first beat the next tile’s first beat arrives and moves each PE’s finished sum into its result register as it passes,i + jcycles in, where it staysperiodcycles. Every column of rowiholds itperiod + i + ccycles after the tile’s first beat: columnjfromperiod + i + j + 1until2·period + i + j, delayed where that window would close before columnc - 1’s opens (os_streaming_deskew). - pipelined_
latency - The fill latency of the pipelined array: row
i’s output emerges at cyclei + L,L = K + N − 1. Shared by the golden model, the RTL emitter, and the lock so they cannot disagree. - pipelined_
os_ latency - The cycle at which the last accumulator (
i=r-1, j=c-1) has absorbed its final product and is drainable. - round_
bf16 - Round
xto bf16 (8-bit exponent, 7-bit mantissa) with round-to-nearest-even — the float precision dial (Phase 4). Idempotent, and a no-op on values already representable in bf16. - trunc_
signed - Sign-extend
xfrom its lowbits(the int-precision truncation;bits >= 64is a no-op). Matches the RTL’s$signed(x[bits-1:0]).