A streaming signed multiply-accumulate / dot-product engine. Each accepted
beat computes a*b and adds it to a running accumulator; asserting in_last on
the final element emits the completed dot-product and clears the accumulator for
the next vector. Fully parameterized by input width and accumulator width.
This is the core compute primitive behind neural-network inference — the same kind of MAC-heavy math the APEX SoC ran in firmware on its Cortex-M0 for TinyML perception, here as dedicated hardware.
| Signal | Dir | Width | Meaning |
|---|---|---|---|
clk |
in | 1 | clock |
rst_n |
in | 1 | async, active-low reset |
in_valid |
in | 1 | a/b form a valid beat this cycle |
in_last |
in | 1 | marks the final element of a dot-product |
a, b |
in | DATA_W |
signed operands |
out_data |
out | ACC_W |
completed dot-product |
out_valid |
out | 1 | 1-cycle pulse when a result is ready |
Parameters: DATA_W (signed input width, default 8), ACC_W (accumulator width, default 32).
iverilog -g2012 -o sim.out rtl/mac.sv tb/mac_tb.sv
vvp sim.out # 4 dot-products incl. signed/negative, self-checking- Signed arithmetic.
a,b, and the accumulator are declaredsigned, soa*bis a signed product and the accumulate sign-extends correctly — essential for ML weights/activations that are negative. - Accumulator width.
ACC_Wis sized wider than2*DATA_Wso a long dot-product can grow without overflow; choosing it is a real datapath trade-off (area vs. max vector length). - Streaming
valid/lastprotocol. One beat per cycle, within_lastdelimiting vectors — the same shape as an AXI-Stream "tlast", so it drops into a larger dataflow design. - Self-clearing. The accumulator resets on
in_last, so back-to-back vectors need no external flush.
A row of these (a systolic/parallel array) forms a matrix-multiply unit — the heart of an NPU. This single lane is the defensible, verifiable starting point.
Built by Efe Demir.