3. MAC阵列流水线优化

任务目标

在MAC阵列的数据通路中插入流水线寄存器,将组合逻辑路径分段,从而提升最高时钟频率。通过对比不同流水线级数下的时序余量与吞吐量,理解流水线深度与性能之间的权衡关系。

设计规格

构建一个4×4 MAC阵列,每个MAC单元执行8位有符号乘法累加运算。输入为两个4×4矩阵A和B,输出为4×4累加结果矩阵C。设计三种配置:无流水线(纯组合逻辑)、1级流水线(乘法器输出后插入寄存器)、2级流水线(乘法器输出和加法器输出各插一级寄存器)。

RTL实现(2级流水线版本)

// mac_array_pipelined.v
module mac_array_pipelined #(
    parameter DATA_W = 8,
    parameter ACC_W  = 20,
    parameter N       = 4
)(
    input  wire clk,
    input  wire rst_n,
    input  wire [DATA_W-1:0] a [0:N-1][0:N-1],  // 输入矩阵A
    input  wire [DATA_W-1:0] b [0:N-1][0:N-1],  // 输入矩阵B
    output reg  [ACC_W-1:0]  c [0:N-1][0:N-1]   // 输出矩阵C
);

    // 第0级:乘法结果寄存器
    reg [DATA_W*2-1:0] mult_reg [0:N-1][0:N-1];
    // 第1级:部分累加寄存器
    reg [ACC_W-1:0] acc_reg [0:N-1][0:N-1];

    integer i, j, k;

    // 流水线第1级:乘法
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < N; i = i + 1)
                for (j = 0; j < N; j = j + 1)
                    mult_reg[i][j] <= 0;
        end else begin
            for (i = 0; i < N; i = i + 1)
                for (j = 0; j < N; j = j + 1)
                    mult_reg[i][j] <= a[i][j] * b[i][j];
        end
    end

    // 流水线第2级:沿列方向累加
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < N; i = i + 1)
                for (j = 0; j < N; j = j + 1)
                    acc_reg[i][j] <= 0;
        end else begin
            for (i = 0; i < N; i = i + 1) begin
                for (j = 0; j < N; j = j + 1) begin
                    acc_reg[i][j] <= 0;
                    for (k = 0; k < N; k = k + 1)
                        acc_reg[i][j] <= acc_reg[i][j] + mult_reg[i][k];
                end
            end
        end
    end

    // 输出赋值
    always @(*) begin
        for (i = 0; i < N; i = i + 1)
            for (j = 0; j < N; j = j + 1)
                c[i][j] = acc_reg[i][j];
    end

endmodule

流水线级数切换说明

上述代码为2级流水线结构。若需对比无流水线版本,将两个always块合并为纯组合逻辑(直接assign c[i][j] = sum(a[i][k]*b[k][j]));若需1级流水线,仅保留乘法寄存器,累加部分改为组合逻辑。三种配置的顶层接口保持一致,便于测试平台复用。

测试平台与验证

// tb_mac_pipeline.v
`timescale 1ns/1ps
module tb_mac_pipeline;
    reg clk = 0, rst_n = 0;
    reg [7:0] a [0:3][0:3];
    reg [7:0] b [0:3][0:3];
    wire [19:0] c [0:3][0:3];

    // 实例化2级流水线DUT
    mac_array_pipelined dut (
        .clk(clk), .rst_n(rst_n),
        .a(a), .b(b), .c(c)
    );

    always #5 clk = ~clk;  // 100MHz时钟

    integer i, j, k;
    reg [19:0] expected [0:3][0:3];

    initial begin
        // 输入数据:A[i][j] = i+j+1, B[i][j] = i*2+j
        for (i = 0; i < 4; i = i + 1)
            for (j = 0; j < 4; j = j + 1) begin
                a[i][j] = i + j + 1;
                b[i][j] = i * 2 + j;
            end

        // 计算期望结果(软件参考模型)
        for (i = 0; i < 4; i = i + 1)
            for (j = 0; j < 4; j = j + 1) begin
                expected[i][j] = 0;
                for (k = 0; k < 4; k = k + 1)
                    expected[i][j] = expected[i][j] + (a[i][k] * b[k][j]);
            end

        // 复位释放
        #20 rst_n = 1;

        // 等待流水线填充(2级流水线需2个时钟周期)
        #30;

        // 检查输出
        for (i = 0; i < 4; i = i + 1)
            for (j = 0; j < 4; j = j + 1) begin
                if (c[i][j] !== expected[i][j]) begin
                    $display("MISMATCH at [%0d][%0d]: got %0d, expected %0d",
                             i, j, c[i][j], expected[i][j]);
                    $finish;
                end
            end
        $display("TEST PASSED");
        $finish;
    end
endmodule

运行与综合方法

  1. 仿真验证:使用Vivado或ModelSim运行tb_mac_pipeline.v,观察打印的TEST PASSED信息。
  2. 时序分析:在Vivado中对三种配置分别执行综合与实现,报告WNS(最差负时序裕量)与最高可达时钟频率。
  3. 吞吐量对比:固定输入矩阵,测量从输入有效到输出稳定的时钟周期数。无流水线为1周期,1级流水线为2周期,2级流水线为3周期。

判定标准

  • 仿真通过:测试平台输出TEST PASSED,无MISMATCH报告。
  • 时序改善:2级流水线配置的WNS优于无流水线配置,表明关键路径被有效切断。
  • 吞吐量理解:确认流水线每增加一级,输出延迟增加1个时钟周期,但最高时钟频率提升,整体吞吐量(数据率×频率)随流水线深度增加而提高。
流水线级数对时序与吞吐量的影响 乘法+累加 组合逻辑长路径 Fmax = 低 延迟 = 1周期 乘法器 REG 累加器 Fmax = 中 延迟 = 2周期 乘法器 REG 加法器 REG Fmax = 高 延迟 = 3周期 吞吐量 = 数据率 × Fmax → 流水线加深提升Fmax,整体吞吐量增加

常见问题

  • 输出延迟:流水线版本输出比输入晚2~3个周期,测试平台需等待足够周期再比对结果。
  • 累加顺序:本设计按列方向累加,与数学定义的行列乘法一致;若需行方向,需调整累加索引。
  • 位宽溢出:8位×8位乘法结果为16位,4次累加最大需18位,ACC_W取20位留有余量。