IC基础(六):3x3脉动阵列计算矩阵相乘
本文是在看了一个博客之后才知道怎么做的,就是这个博客FPGA脉动阵列的设计,可惜的是这个博客是转载的,原博客已经找不到了。但是其介绍的还是很详细的,在次基础上我完成了自己的的3*3脉动阵列的设计。本文后面会给出一个PPT文档,也是介绍脉动阵列的,FPGA脉动这列的设计这篇博客似乎也是这个PPT启发的。
一、引言
引言的大部分内容来自《VLSI数字性信号处理系统:设计与实现》一书。
脉动结构(也称脉动阵列)表示一种有节奏的计算并通过系统传输数据的处理单元(Processing elements,PE)网络。强调一下,这里说的是网络,不是单个计算单元!!!!!!!!!!!!!!!这些单元规则的泵入蹦出数据以维持规则的数据流。脉动系统的特征是模块化和规则化,这对于大规模集成电路设计是很重要的性质。脉动阵列可作为和主计算机结合的系处理器,从主计算机接数据样本送到处理单元,并将最终结果返回结算机。这个过程可以用下图说明。这个操作类似心脏血液的流动,因此命名为“脉动”。
典型情况下,脉动阵列的所有处理单元是相同的且全流水的,也就是处理部件的所有通信边沿都包含延时单元,且整个系统通常只包含局部互联。这句话怎么理解呢?我的理解是每个处理单元内部都需要有延时单元?为啥需要延时单元呢?因为处理单元会将输入的数据先拿来做运算,然后在下一个时钟把数据传递到下一个处理单元。因此必须需要延迟单元。那什么又是局部互联呢?局部互联是指每个处理单元只与自己相邻的处理单元有数据交流。但是有时候也会为了算法的需求,处理单元可以跨过相邻的处理单元进行互联。
二、脉动阵列的优势
脉动阵列可以是一维的网络,也可以是二维的,当然还可以有更高维度的。
脉动阵列这个概念其实从1978年就就已经有了,自从谷歌的TPU采用了脉动阵列单元来加速卷积计算后,这个概念又火了起来了。但是本文说的脉动阵列并不是谷歌所说的那种脉动阵列,本文介绍脉动阵列是用来做矩阵乘法的。
由于脉动阵列的输入数据是流过每一个处理单元的,所以就可以减少数据的访存,提高数据的吞吐量。另外一个就是脉动阵列规则,在专用集成电路布线简单,可以提高系统的工作频率。
为啥可以减少访存呢?举个例子,假设矩阵相乘:
要计算C[0][0]=23,需要访问A[0][0],A[0][1],A[0][2],B[0][0],B[1][0],B[2][0]。
C[0][0] = A[0][0]*B[0][0]+A[0][1]*B[1][0]+A[0][2]*B[2][0]
同理:
C[0][1] = A[0][0]*B[0][1]+A[0][1]*B[1][1]+A[0][2]*B[2][1]
计算C[0][0]和C[0][1]需要访问相同的元素:A[0][0],A[0][1],A[0][2]。如果不用脉动阵列,光是在计算C[0][0]和C[0][1]这两个元素上就需要访问A[0][0],A[0][1],A[0][2]两次,因此口带就限制了系统的速度。但是用脉动阵列买个数据就只用访问一次,大大提高了系统的运算速度,代价就是需要用更多的计算单元。
三、脉动阵列的计算过程
这部分的讲解需要画很多图来讲解,幸好有这个网页,这里的脉动阵列处理机讲的明白了。我就大概讲一下计算过程就好了。
首先先给出3x3脉动阵列处理网络,举的例子是在上面提到的矩阵A和矩阵B相乘。
脉动阵列网络结构图:
PE内部结构图:
网络结构图中*代表延迟一个周期的意思。所以两个 ** 代表延迟两个周期。
算了,计算过程不说了。如果你让认真看一定可以看懂,没看懂的一定是你没有认真看。
四、代码设计和功能仿真
这里使用有符号8位位宽的整数设计,输出位宽位16位。有一个问题值得注意就是计算过程中数据不能溢出,溢出就错了。另外还用到了xilinx的乘加器IP。
计算完一次要把计算单元中的寄存器清零**
代码:
1、PE模块代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/04/02 16:55:36
// Design Name:
// Module Name: PE
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module PE #(parameter N = 8)
(
input Clk,
input Rst_n,
input Sclr,
input [N-1:0]A,
input [N-1:0]B,
//input [N*2-1:0]C,
output reg [N-1:0]Next_A,
output reg [N-1:0]Next_B,
output [N*2-1:0]P
);
reg [N*2-1:0] P_reg=0;
wire [N*2-1:0] P_net;
[email protected](posedge Clk or negedge Rst_n)begin
if(!Rst_n) begin
Next_A <=0;
Next_B <=0;
end
else if(Sclr==0)begin
Next_A <=0;
Next_B <=0;
end
else begin
Next_A <= A;
Next_B <= B;
end
end
xbip_multadd_0 MultAccumIP (
.A(A), // input wire [7 : 0] A
.B(B), // input wire [7 : 0] B
.C(P_reg), // input wire [15 : 0] C
.SUBTRACT(1'b0), // input wire SUBTRACT
.P(P_net), // output wire [15 : 0] P
.PCOUT() // output wire [47 : 0] PCOUT
);
[email protected](posedge Clk or posedge Rst_n)begin
if(!Rst_n)
P_reg <= 0;
else if(Sclr==1'b0)
P_reg <= 0;
else
P_reg <= P_net;
end
assign P = P_net;
endmodule
2、顶层模块
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/04/02 20:14:46
// Design Name:
// Module Name: pulsation_array
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module pulsation_array #
(
parameter N = 8
)
(
input Clk,
input Rst_n,
input In_Dv,
input signed [N-1:0] A0,
input signed [N-1:0] A1,
input signed [N-1:0] A2,
input signed [N-1:0] B0,
input signed [N-1:0] B1,
input signed [N-1:0] B2,
output reg signed [N*2-1:0] P11,
output reg signed [N*2-1:0] P12,
output reg signed [N*2-1:0] P13,
output reg signed [N*2-1:0] P21,
output reg signed [N*2-1:0] P22,
output reg signed [N*2-1:0] P23,
output reg signed [N*2-1:0] P31,
output reg signed [N*2-1:0] P32,
output reg signed [N*2-1:0] P33,
output reg Out_Dv
);
wire signed [N-1:0] P11_A,P11_B;
wire signed [N-1:0] P12_A,P12_B;
wire signed [N-1:0] P21_A,P21_B;
wire signed [N-1:0] P22_A,P22_B;
wire signed [N-1:0] P31_A,P32_A;
wire signed [N-1:0] P13_B,P23_B;
wire signed [N*2-1:0] P11_reg,P12_reg,P13_reg;
wire signed [N*2-1:0] P21_reg,P22_reg,P23_reg;
wire signed [N*2-1:0] P31_reg,P32_reg,P33_reg;
reg [2:0] count;
reg [2:0] count_reg;
reg Out_Dv_reg;
reg Sclr;
[email protected](posedge Clk or negedge Rst_n) begin
if(!Rst_n)
count <= 3'b000;
else if(In_Dv==1'b1)
if(count<6)
count <= count+1'b1;
else
count <=3'b000;
else
count <= 3'b000;
end
[email protected](posedge Clk)begin
count_reg<=count;
end
[email protected](posedge Clk or negedge Rst_n) begin
if(!Rst_n)
Out_Dv_reg <= 1'b0;
else if(count_reg==5)
Out_Dv_reg <=1'b1;
else
Out_Dv_reg <=1'b0;
end
[email protected](posedge Clk or Rst_n)begin
if(!Rst_n)
Sclr <= 1'b0;
else if(count_reg==5)
Sclr <= 1'b0;
else
Sclr <=1'b1;
end
[email protected](posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
P11 <=0;
P12 <=0;
P13 <=0;
P21 <=0;
P22 <=0;
P23 <=0;
P31 <=0;
P32 <=0;
P33 <=0;
end
else if(Out_Dv_reg==1'b1) begin
P11 <=P11_reg;
P12 <=P12_reg;
P13 <=P13_reg;
P21 <=P21_reg;
P22 <=P22_reg;
P23 <=P23_reg;
P31 <=P31_reg;
P32 <=P32_reg;
P33 <=P33_reg;
end
else begin
P11 <=0;
P12 <=0;
P13 <=0;
P21 <=0;
P22 <=0;
P23 <=0;
P31 <=0;
P32 <=0;
P33 <=0;
end
end
[email protected](posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Out_Dv <= 0;
else
Out_Dv <= Out_Dv_reg;
end
///////////////////////////First PE
PE #
(
.N(N)
)
PE_11
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(A0),
.B(B0),
.Next_A(P11_A),
.Next_B(P11_B),
.P(P11_reg)
);
/////////////////////////Second PE
PE #
(
.N(N)
)
PE_12
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(P11_A),
.B(B1),
.Next_A(P12_A),
.Next_B(P12_B),
.P(P12_reg)
);
//////////////////////////////
PE #
(
.N(N)
)
PE_13
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(P12_A),
.B(B2),
.Next_A(),
.Next_B(P13_B),
.P(P13_reg)
);
//
PE #
(
.N(N)
)
PE_21
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(A1),
.B(P11_B),
.Next_A(P21_A),
.Next_B(P21_B),
.P(P21_reg)
);
//////////////////////////////////
PE #
(
.N(N)
)
PE_22
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(P21_A),
.B(P12_B),
.Next_A(P22_A),
.Next_B(P22_B),
.P(P22_reg)
);
//////////////////////////////
PE #
(
.N(N)
)
PE_23
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(P22_A),
.B(P13_B),
.Next_A(),
.Next_B(P23_B),
.P(P23_reg)
);
/////////////////////////////////
PE #
(
.N(N)
)
PE_31
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(A2),
.B(P21_B),
.Next_A(P31_A),
.Next_B(),
.P(P31_reg)
);
////////////////////////////////
PE #
(
.N(N)
)
PE_32
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(P31_A),
.B(P22_B),
.Next_A(P32_A),
.Next_B(),
.P(P32_reg)
);
//
PE #
(
.N(N)
)
PE_33
(
.Clk(Clk),
.Rst_n(Rst_n),
.Sclr(Sclr),
.A(P32_A),
.B(P23_B),
.Next_A(),
.Next_B(),
.P(P33_reg)
);
endmodule
3、测试文件
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2019/04/02 20:48:29
// Design Name:
// Module Name: TB_pulsation_array
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module TB_pulsation_array;
parameter N = 8;
parameter CLK_PERIOD = 20;
reg [N-1:0] A0;
reg [N-1:0] A1;
reg [N-1:0] A2;
reg [N-1:0] B0;
reg [N-1:0] B1;
reg [N-1:0] B2;
reg In_Dv;
wire Out_Dv;
wire [N*2-1:0] P11;
wire [N*2-1:0] P12;
wire [N*2-1:0] P13;
wire [N*2-1:0] P21;
wire [N*2-1:0] P22;
wire [N*2-1:0] P23;
wire [N*2-1:0] P31;
wire [N*2-1:0] P32;
wire [N*2-1:0] P33;
reg Clk;
reg Rst_n;
integer i=0;
initial
Clk=0;
always # (CLK_PERIOD/2) Clk=~Clk;
initial begin
Rst_n=1'b0;
In_Dv = 0;
A0=0;
A1=0;
A2=0;
B0=0;
B1=0;
B2=0;
#40;
Rst_n = 1'b1;
//1
#10;
for(i=0;i<25;i=i+1)begin
In_Dv =1'b1;
A0=3+i;
A1=0;
A2=0;
B0=3+i;
B1=0;
B2=0;
//2
#20;
A0=4+i;
A1=2+i;
A2=0;
B0=2+i;
B1=4+i;
B2=0;
//3
#20;
A0=2+i;
A1=5+i;
A2=3+i;
B0=3+i;
B1=5+i;
B2=2+i;
//4
#20;
A0=0;
A1=3+i;
A2=2+i;
B0=0;
B1=2+i;
B2=3+i;
//5
#20;
A0=0;
A1=0;
A2=5+i;
B0=0;
B1=0;
B2=5+i;
#60;
In_Dv = 0;
A0=0;
A1=0;
A2=0;
B0=0;
B1=0;
B2=0;
//Rst_n = 1'b0;
//#40;
//Rst_n = 1'b1;
end
end
pulsation_array #
(
.N(N)
)
uut
(
.Clk(Clk),
.Rst_n(Rst_n),
.In_Dv(In_Dv),
.A0(A0),
.A1(A1),
.A2(A2),
.B0(B0),
.B1(B1),
.B2(B2),
.P11(P11),
.P12(P12),
.P13(P13),
.P21(P21),
.P22(P22),
.P23(P23),
.P31(P31),
.P32(P32),
.P33(P33),
.Out_Dv(Out_Dv)
);
endmodule
五、仿真波形
放大看看: