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相乘。

脈動陣列網絡結構圖:

3x3脈動結構圖
PE內部結構圖:
單個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;
    
    always@(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
    );
    always@(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;
    always@(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		
    
    always@(posedge Clk)begin
    	count_reg<=count;
    end
    always@(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
    
    always@(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
    
    always@(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
always@(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

五、仿真波形

在這裏插入圖片描述

放大看看:

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章