1. NPU MAC阵列基础单元设计
任务目标
设计一个8x8的乘累加(MAC)阵列,每个MAC单元完成8位有符号定点乘法,并将乘积与内部累加器相加。阵列支持同步时钟与全局复位,所有32个周期内可并行处理64组输入,最终通过累加器输出结果。
接口定义
| 信号 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| clk | input | 1 | 时钟,上升沿有效 |
| rst_n | input | 1 | 异步复位,低有效 |
| a[i][j] | input | 8 | 操作数A,i行j列,有符号 |
| b[i][j] | input | 8 | 操作数B,有符号 |
| acc_en | input | 1 | 累加使能,高电平有效 |
| acc_clear | input | 1 | 同步清空累加器,高有效 |
| result[i][j] | output | 32 | 累加结果,有符号 |
实现方案
采用二维阵列结构,每个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
运行与验证
- 仿真运行:使用Icarus Verilog执行
iverilog -o tb_mac_array.vvp mac_array_8x8.v tb_mac_array.v && vvp tb_mac_array.vvp - 通过条件:控制台输出
PASS: All 64 MAC units verified,且无FAIL信息。 - 功能覆盖:测试平台验证了乘法正确性(2×3=6)、连续累加(6+6=12)以及同步清零功能。
综合实现说明
若需FPGA综合,建议将二维端口数组展平为64×8位输入向量,或使用SystemVerilog接口封装。本设计为纯组合乘法+时序累加结构,关键路径为8位乘法器与32位加法器链,在典型7系列FPGA上可运行于200MHz以上时钟。实际部署时需根据目标器件添加输入寄存器级以优化时序。