A systolic engine is a pipeline of multiply-accumulate stages. Weights stay at their stage while one activation row per cycle flows in.
Throughput is one row per cycle after fill. Latency is 3 cycles here, and it is paid on every short phase.
Rows fed (latency 3) | Cycles (latency + rows) | Active slots / total | Utilization |
|---|---|---|---|
64 (long stream) | 67 | 256 / 268 | 96% |
4 (full tile) | 7 | 16 / 28 | 57% |
3 (short phase) | 6 | 12 / 24 | 50% |
3 wide on 4-wide array | 6 | 9 / 24 | 38% |
Padding a 3-wide tile to width 4 multiplies the 50% phase efficiency by 3/4. The result is 37.5%, about 38%.
4 rows: cycles = 3 + 4 = 7, util = (4 x 4) / (4 x 7) = 16 / 28 = 57.1% ≈ 57%
3 rows: cycles = 3 + 3 = 6, util = (3 x 4) / (4 x 6) = 12 / 24 = 50%
3 rows padded to width 4: 50% x 3 / 4 = 37.5% ≈ 38%
64 rows: cycles = 3 + 64 = 67, util = 256 / 268 = 95.5% ≈ 96%The model below is a pipelined MAC stage with stationary weights. The testbench feeds 4 rows then 3 padded rows and checks every sum plus the first-result latency of 3.
module mac_pipe4 (
input logic clk,
input logic rst_n,
input logic in_valid,
input logic [7:0] a_vec0,
input logic [7:0] a_vec1,
input logic [7:0] a_vec2,
input logic [7:0] a_vec3,
input logic [7:0] w0,
input logic [7:0] w1,
input logic [7:0] w2,
input logic [7:0] w3,
output logic out_valid,
output logic [15:0] sum_out
);
logic [15:0] s0, q1, q2, q3;
logic v1, v2, v3;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
s0 <= 16'd0; q1 <= 16'd0; q2 <= 16'd0; q3 <= 16'd0;
v1 <= 1'b0; v2 <= 1'b0; v3 <= 1'b0; out_valid <= 1'b0;
end else begin
s0 <= a_vec0 * w0 + a_vec1 * w1 + a_vec2 * w2 + a_vec3 * w3;
q1 <= s0; q2 <= q1; q3 <= q2;
v1 <= in_valid; v2 <= v1; v3 <= v2; out_valid <= v3;
end
end
assign sum_out = q3;
endmodule
7 cycles. Active slots are 16 over 28 total, so about 57%.
Phase gives 12/24 = 50%, times width 3/4, giving 37.5%, about 38%.