← Lab

04 · tiny-tensor-core · Verilog · ECP5

Draw a digit. 273 clocks.

The 196 → 32 → 10 network from my Arduino project, with its int8 weights, in the integer-only form the Verilog computes. This JS port matches the Python golden model on every hidden value and every prediction across all 10,000 MNIST test images.

draw here

or pick a real MNIST test image

what the chip sees · 14×14, 0–127
32 lanesidle
outputlogits
–
clock 0 / 273
layer 1 · 197
requantize · 32
layer 2 · 33
argmax · 11

Integer all the way down

The Arduino version rescales between layers with floats. Hardware avoids that, so the core replaces it with one fixed-point multiply and a shift, with the same multiplier shared by every neuron:

acc1[j] = Σ W1[j][i] · x[i] 196 clocks, 32 lanes at once h[j] = clamp((acc1[j]·31,942 + B1q[j] + 2²³) >> 24, 0, 127) acc2[k] = Σ W2[k][j] · h[j] 32 clocks, 10 lanes digit = argmax(acc2[k] + B2q[k]) 10 compares

Layer 2 needs no rescaling at all: every logit is multiplied by the same positive scale, which can't change which one is largest. On the ECP5 this places and routes at ~50 MHz, about 5.5 µs per image. The Arduino UNO took 30.7 ms.

Your drawing is framed the way MNIST is: the ink is scaled into a 20 × 20 box, its centre of mass moved to the middle of 28 × 28, then averaged down to 14 × 14 and rounded to 0–127.

github.com/Jusman0/tiny-tensor-core ↗