Interactive lab

Every bit, in motion

Follow numbers through a systolic array. Each clock moves A one cell right and B one cell down. Their product joins the running total stored in that cell. Change the number format, edit the inputs bit by bit, and inspect any cell.

Try your own values

Inputs, in numbers and bits

Matrix A

2 decimal 0000 0010 binary

Click bits or drag the slider. The highest bit is the sign bit for signed formats. Edits recompute the selected cycle.

INT8: signed two’s-complement 8-bit operands, 16-bit products, 32-bit exact accumulation.

Ready
One square, one bit

Bit footprint of one cell

INT8 · 48 bits per cell · 432 bits across 9 cells · 1.00× INT8 bit storage

A operand · 8 bits
B operand · 8 bits
Accumulator · 32 bits

Every square has the same size across all formats. Rows wrap after 16 bits; wider formats add squares and expand the cell. Counts include two operand slots and one accumulator. This represents bit storage, not silicon area or multiplier gate count. Keep zoom at 100% to compare scale. “Fit array” rescales the entire diagram.

The array

A → activationB ↓ weightOutlined cell = active MAC
Moving operands in a 3 by 3 systolic arrayA moves right and B moves down. Each cell keeps a running total of the products that reach it.B ↓ column queuesA → row queuesC[0,0]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[0,1]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[0,2]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[1,0]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[1,1]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[1,2]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[2,0]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[2,1]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00C[2,2]waitingΣ 0Bit 31: 00Bit 30: 00Bit 29: 00Bit 28: 00Bit 27: 00Bit 26: 00Bit 25: 00Bit 24: 00Bit 23: 00Bit 22: 00Bit 21: 00Bit 20: 00Bit 19: 00Bit 18: 00Bit 17: 00Bit 16: 00Bit 15: 00Bit 14: 00Bit 13: 00Bit 12: 00Bit 11: 00Bit 10: 00Bit 9: 00Bit 8: 00Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 00→↓→↓↓→↓→↓↓→→A[0,0] →2Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 00A[0,1] →1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11A[0,2] →3Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 11A[1,0] →1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11A[1,1] →4Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 11Bit 1: 00Bit 0: 00A[1,2] →2Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 00A[2,0] →3Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 11A[2,1] →2Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 00A[2,2] →1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11B[0,0] ↓1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11B[1,0] ↓3Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 11B[2,0] ↓2Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 00B[0,1] ↓2Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 00B[1,1] ↓1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11B[2,1] ↓1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11B[0,2] ↓1Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 00Bit 0: 11B[1,2] ↓2Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 00B[2,2] ↓3Bit 7: 00Bit 6: 00Bit 5: 00Bit 4: 00Bit 3: 00Bit 2: 00Bit 1: 11Bit 0: 11
1 square = 1 bit · 18 × 18 at 100% zoom · filled = 1, empty = 0Scroll to explore expanded cells. Click any cell to inspect it.
Follow the clock

This cycle

The operands are queued. Press Play or Step to begin.

C = A × B

Running output

00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000
00000 0000 0000 0000 0000 0000 0000 0000

Digits processed

INT8 · 0 / 27 MACs
RepresentationRadixDigits
Binary20
M16160
Inside a single cell

From operands to a running total

C[0,0] · INT8
Preview: first term arrives at cycle 1
0 + (2 × 1) = 2
STEP 01

Load INT8 operands

Signed 8-bit integers use two’s complement. The leading bit has negative weight.

OperandValue
A[0,0]2
B[0,0]1

These are directly entered integer values. No real-to-integer quantization scale is assumed.

STEP 02

Move the bits into the cell

The entire operand packet moves one neighbor per clock. Decimal and binary labels move together.

A → 0000 0010
B ↓ 0000 0001

The displayed bits are the stored integer representation, not extra clock cycles.

STEP 03

Multiply the arriving pair

Multiply the signed or unsigned values exactly.

2 × 1 = 2

Product (16 bits)
0000 0000 0000 0010
STEP 04

Add to the accumulator

The 32-bit accumulator keeps all 3 products exactly. Negative products are sign-extended before addition.

Previous: 0
0000 0000 0000 0000
0000 0000 0000 0000

+ Product: 2
0000 0000 0000 0000
0000 0000 0000 0010

= Total: 2
0000 0000 0000 0000
0000 0000 0000 0010
STEP 05

Forward operands; keep the sum

A moves to C[0,1]. B moves to C[1,0]. The accumulated total stays inside C[0,0].

A → 2
B ↓ 1
C stays: 2
STEP 06

Complete the dot product

After 3 operand pairs, this cell holds one element of C. Staggered arrival times complete the full array in 7 cycles.

(2 × 1) +
(1 × 3) +
(3 × 2)
= 11

Widened accumulation avoids overflow for this 3-term dot product, including at the input range limits.

3 × 3 output-stationary array · 7 compute cycles. Binary digits are stored representations, not a bit-serial timing model. Inputs move; partial sums remain in their cells. Video reference Text reference