/about
About this site
Systolic Arrays Explained is about the hardware that does a model's matrix multiplies: systolic arrays, their dataflows, and the matrix units of TPUs. Each chapter is built around an animation. It is the sixth of a family of companion sites, with the Transformer Decoder Explainer, LLM Inference Explained, LLM Architectures Explained, GPU Kernels Explained, Numerics Explained and Inference Trade-offs Explained. The chapters link the matching slides of the Google TPU series.
The model
reference/systolic.py is a cycle-accurate model of a parameterised array in plain Python, and src/lib/sa/model.ts repeats it line for line. Every PE's registers are recomputed each cycle from the previous cycle's, exactly as flip-flops behave, in weight-, output- and input-stationary dataflows, with row-stationary for a convolution as a reference; it also tiles problems that do not fit. The arithmetic is all integer, so the two agree exactly. The model page lists its conventions and closed forms.
How it is checked
- Against a direct matrix multiply. tests/python/test_systolic.py compares every result with numpy, for every dataflow, many shapes, arrays larger than the problem, and full-range signed INT8; and the row-stationary convolution with a direct convolution.
- Against the textbook timing. The tests read every product back from the frames and check it happened in the PE and the cycle the derivation in the chapters says, and that operands and partial sums move exactly one PE per cycle.
- Against its closed forms. Cycle counts, buffer reads and writes, PE-to-PE hops, partial-sum hops and register writes, counted from the frames, equal the formulas on the model page; tiled runs equal the sum of their tiles.
- Against RTL. rtl/check_rtl.py runs the author's SystemVerilog output-stationary array in Verilator 5.020 and compares every accumulator after every clock edge with the model: 613 values, 0 mismatches. It also runs the author's three-stage MAC unit, the PE of chapter 6, and compares every pipeline register after every edge: 11,079 values, 0 mismatches. CI repeats both.
- Against another simulator. Chapter 9's lowering of an ONNX model gives the same GEMM shapes and cycle estimates as the author's Torch_Sim_Frontend run on the same file (scripts/check_simfront.py, recorded in reference/simfront_check.json).
- Exact parity. scripts/make_fixtures.py writes the reference's traces, and the unit tests require the TypeScript port to reproduce every register of every PE in every cycle: in full for the chapters' demonstrations, and through SHA-256 digests for every size the sliders allow. CI fails if the fixtures are out of date.
- Animations from the model. Every animation draws the model's frames; a picture is a pure function of one frame. The tests set chosen frames of every animation and require the caption to match the caption built from the Python reference's frame.
- Numbers in the prose are printed from the model when the page is built, not typed.
What is illustrative
- The matrices are small seeded integers (−4 to 5) so their values fit in the drawings; the RTL check also runs full-range INT8.
- In chapters 1 to 4 each pass is counted on its own: the weights load before the stream and passes do not overlap. Chapter 5 adds double-buffered weights and runs tiles back to back.
- Chapters 5 to 9 use a small array and small matrices so every PE fits on a phone; HBM bandwidth is in words per cycle; the PE's operands have small exponents; the all-reduce is counted in steps, not timed; the TPU diagram is generic; the ONNX model was written by hand with small integer weights, not trained.
- Output-stationary results drain down the columns one row per cycle; other designs read them out in parallel.
- The memory-bandwidth figures of chapter 1 are round numbers, not a particular chip's.
The animations
Every animation has play and pause, step back and forward, a scrub bar, speeds from 0.25× to 4× and reset; with the animation focused, Space plays or pauses and the arrow keys step. Each step has a one-line caption, also announced to screen readers. With reduce motion set in your system, nothing plays by itself. Animations pause when scrolled out of view. Colours come from Okabe and Ito's colour-blind-safe palette, the same in light and dark mode: activations (A) blue, weights (B) vermillion, partial sums sky blue, results purple. A PE that multiplies in a cycle gets a thick outline; an idle PE is grey and hatched.
Source
The code, the model and the tests are on GitHub (MIT licence). The design system is copied from the companion sites; the README records where each piece came from.