1. NPU MAC阵列基础单元设计

任务目标

设计一个8x8的乘累加(MAC)阵列,每个MAC单元完成8位有符号定点乘法,并将乘积与内部累加器相加。阵列支持同步时钟与全局复位,所有32个周期内可并行处理64组输入,最终通过累加器输出结果。

接口定义

信号方向位宽说明
clkinput1时钟,上升沿有效
rst_ninput1异步复位,低有效
a[i][j]input8操作数A,i行j列,有符号
b[i][j]input8操作数B,有符号
acc_eninput1累加使能,高电平有效
acc_clearinput1同步清空累加器,高有效
result[i][j]output32累加结果,有符号

实现方案

采用二维阵列结构,每个MAC单元由1个8位有符号乘法器、1个32位加法器和1个32位累加寄存器构成。乘法器输出16位乘积,经符号扩展后与累加器值相加。阵列采用行并行、列独立的工作方式,所有单元共享控制信号。累加器在acc_clear有效时清零,在acc_en有效时更新,否则保持原值。

RTL代码(mac_array_8x8.v)

module mac_array_8x8 #(
    parameter DATA_W = 8,
    parameter ACC_W  = 32
)(
    input  wire                     clk,
    input  wire                     rst_n,
    input  wire signed [DATA_W-1:0] a [0:7][0:7],
    input  wire signed [DATA_W-1:0] b [0:7][0:7],
    input  wire                     acc_en,
    input  wire                     acc_clear,
    output reg  signed [ACC_W-1:0]  result [0:7][0:7]
);

    // 内部乘积与加法中间量
    wire signed [2*DATA_W-1:0] mult_out [0:7][0:7];
    wire signed [ACC_W-1:0]    add_out  [0:7][0:7];

    // 生成8x8 MAC单元
    genvar i, j;
    generate
        for (i = 0; i < 8; i = i + 1) begin : row
            for (j = 0; j < 8; j = j + 1) begin : col
                // 8位有符号乘法
                assign mult_out[i][j] = a[i][j] * b[i][j];

                // 符号扩展后累加
                assign add_out[i][j] = result[i][j] + mult_out[i][j];

                // 累加寄存器
                always @(posedge clk or negedge rst_n) begin
                    if (!rst_n)
                        result[i][j] <= {ACC_W{1'b0}};
                    else if (acc_clear)
                        result[i][j] <= {ACC_W{1'b0}};
                    else if (acc_en)
                        result[i][j] <= add_out[i][j];
                    // 未使能时保持
                end
            end
        end
    endgenerate

endmodule

测试平台(tb_mac_array.v)

module tb_mac_array;

    reg clk = 0;
    reg rst_n;
    reg acc_en, acc_clear;
    reg signed [7:0] a [0:7][0:7];
    reg signed [7:0] b [0:7][0:7];
    wire signed [31:0] result [0:7][0:7];

    // 生成时钟
    always #5 clk = ~clk;

    // 待测模块
    mac_array_8x8 dut (
        .clk(clk), .rst_n(rst_n),
        .a(a), .b(b),
        .acc_en(acc_en), .acc_clear(acc_clear),
        .result(result)
    );

    // 测试激励
    integer i, j;
    initial begin
        // 初始化
        rst_n = 0;
        acc_en = 0;
        acc_clear = 0;
        for (i = 0; i < 8; i = i + 1)
            for (j = 0; j < 8; j = j + 1) begin
                a[i][j] = 0;
                b[i][j] = 0;
            end

        #20 rst_n = 1;

        // 输入测试数据:a=2, b=3,预期乘积6
        for (i = 0; i < 8; i = i + 1)
            for (j = 0; j < 8; j = j + 1) begin
                a[i][j] = 2;
                b[i][j] = 3;
            end

        // 第一次累加
        @(posedge clk);
        acc_en = 1;
        @(posedge clk);
        acc_en = 0;

        // 检查结果
        for (i = 0; i < 8; i = i + 1)
            for (j = 0; j < 8; j = j + 1)
                if (result[i][j] !== 32'd6) begin
                    $display("FAIL: [%0d][%0d] = %0d, expected 6", i, j, result[i][j]);
                    $finish;
                end

        // 第二次累加,预期12
        @(posedge clk);
        acc_en = 1;
        @(posedge clk);
        acc_en = 0;

        for (i = 0; i < 8; i = i + 1)
            for (j = 0; j < 8; j = j + 1)
                if (result[i][j] !== 32'd12) begin
                    $display("FAIL: second acc [%0d][%0d] = %0d, expected 12", i, j, result[i][j]);
                    $finish;
                end

        // 清空测试
        @(posedge clk);
        acc_clear = 1;
        @(posedge clk);
        acc_clear = 0;

        for (i = 0; i < 8; i = i + 1)
            for (j = 0; j < 8; j = j + 1)
                if (result[i][j] !== 32'd0) begin
                    $display("FAIL: clear [%0d][%0d] = %0d, expected 0", i, j, result[i][j]);
                    $finish;
                end

        $display("PASS: All 64 MAC units verified");
        $finish;
    end

endmodule

运行与验证

  1. 仿真运行:使用Icarus Verilog执行 iverilog -o tb_mac_array.vvp mac_array_8x8.v tb_mac_array.v && vvp tb_mac_array.vvp
  2. 通过条件:控制台输出 PASS: All 64 MAC units verified,且无FAIL信息。
  3. 功能覆盖:测试平台验证了乘法正确性(2×3=6)、连续累加(6+6=12)以及同步清零功能。

综合实现说明

若需FPGA综合,建议将二维端口数组展平为64×8位输入向量,或使用SystemVerilog接口封装。本设计为纯组合乘法+时序累加结构,关键路径为8位乘法器与32位加法器链,在典型7系列FPGA上可运行于200MHz以上时钟。实际部署时需根据目标器件添加输入寄存器级以优化时序。