FIR調用DSP48E_05


作者:桂。

時間:2018-02-06  17:52:38

鏈接:http://www.cnblogs.com/xingshansi/p/8423457.html 


前言

  到目前為止,本文沒有對濾波器實現進行梳理,FIR仿真驗證的平台(基於FPGA實現)包括HLS、Systemgenerator,至於*.v 與*.sv可通過程序(如python實現)完成轉化,FIR的零散記錄到本篇告一段落,本文重點記錄DSP48E的使用

一、DSP48E

  A-基本結構

主要參考UG479.pdf,DSP48E1結構:

可以看出主要功能為:P = (A±D)×B±C。具體功能可參考IP核:

slice結構及位寬關系:

DSP48E在Xilinx內部的布局:

常用器件DSP48E資源:

  B-原語調用

原語類似C語言的匯編,直接關聯器件的底層結構,因此通常時序可以做的更好。

DSP48E支持原語調用,記錄兩個例子:

Ex1:

`timescale 1ns / 1ps

// m = b * (a + d)
// p = c+m or p+m
module dsp48_wrap_f
  (
   input 		  clock,
   input 		  ce1,
   input 		  ce2,
   input 		  cem,
   input 		  cep,
   input signed [24:0] 	  a,
   input signed [17:0] 	  b,
   input signed [47:0] 	  c,
   input signed [24:0] 	  d, // this has two fewer pipe stages
   // X+Y is usually the multiplier output (M)
   // Z is either P, PCIN or C
   // bit 1:0: 0: Z+X+Y 3:Z-(X+Y) 1: -Z + (X+Y) 2: -1*(Z+X+Y+1)
   // bits 3:2, 0: Z=0, 1: Z=PCIN, 2: Z=P, 3: Z = C
   // bit 4: sub in pre add
   input [4:0] 		  mode,
   input signed [47:0] 	  pcin,
   output signed [47:0]   pcout,
   output signed [47-S:0] p);

   parameter S = 0;

   parameter USE_DPORT = "FALSE"; // enabling adds 1 reg to A path
   parameter AREG = 1;
   parameter BREG = 1; // 0 - 2

   wire signed [47:0] 	   dsp_p;
   assign p = dsp_p[47:S];

   DSP48E1
     #(
       .A_INPUT("DIRECT"),   // "DIRECT" "CASCADE"
       .B_INPUT("DIRECT"),   // "DIRECT" "CASCADE"
       .USE_DPORT(USE_DPORT),
       .USE_MULT("MULTIPLY"),// "MULTIPLY" "DYNAMIC" "NONE"
       .USE_SIMD("ONE48"),   // "ONE48" "TWO24" "FOUR12"
       // pattern detector - not used
       .AUTORESET_PATDET("NO_RESET"), .MASK(48'h3fffffffffff),
       .PATTERN(48'h000000000000), .SEL_MASK("MASK"),
       .SEL_PATTERN("PATTERN"), .USE_PATTERN_DETECT("NO_PATDET"),
       // register enables
       .ACASCREG(1),   // pipeline stages between A/ACIN and ACOUT (0, 1 or 2)
       .ADREG(1),      // pipeline stages for pre-adder (0 or 1)
       .ALUMODEREG(1), // pipeline stages for ALUMODE (0 or 1)
       .AREG(AREG),       // pipeline stages for A (0, 1 or 2)
       .BCASCREG(1),   // pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
       .BREG(BREG),    // pipeline stages for B (0, 1 or 2)
       .CARRYINREG(1), // this and below are 0 or 1
       .CARRYINSELREG(1),
       .CREG(1),
       .DREG(1),
       .INMODEREG(1),
       .MREG(1),
       .OPMODEREG(1),
       .PREG(1))
   dsp48_i
     (
      // status
      .OVERFLOW(),
      .PATTERNDETECT(), .PATTERNBDETECT(),
      .UNDERFLOW(),
      // outs
      .CARRYOUT(),
      .P(dsp_p),
      // control
      .ALUMODE({2'd0, mode[1:0]}),
      .CARRYINSEL(3'd0),
      .CLK(clock),
      .INMODE({1'b0,mode[4],3'b100}),
      .OPMODE({1'b0,mode[3:2],4'b0101}),
      // signal inputs
      .A({5'd0,a}), // 30
      .B(b), // 18
      .C(c), // 48
      .CARRYIN(1'b0),
      .D(d), // 25
      // cascade ports
      .ACOUT(),
      .BCOUT(),
      .CARRYCASCOUT(),
      .MULTSIGNOUT(),
      .PCOUT(pcout),
      .ACIN(30'h0),
      .BCIN(18'h0),
      .CARRYCASCIN(1'b0),
      .MULTSIGNIN(1'b0),
      .PCIN(pcin),
      // clock enables
      .CEA1(ce1), .CEA2(ce2),
      .CEAD(1'b1),
      .CEALUMODE(1'b1),
      .CEB1(ce1), .CEB2(ce2),
      .CEC(1'b1),
      .CECARRYIN(1'b1),
      .CECTRL(1'b1), // opmode
      .CED(1'b1),
      .CEINMODE(1'b1),
      .CEM(cem), .CEP(cep),
      .RSTA(1'b0),
      .RSTALLCARRYIN(1'b0),
      .RSTALUMODE(1'b0),
      .RSTB(1'b0),
      .RSTC(1'b0),
      .RSTCTRL(1'b0),
      .RSTD(1'b0),
      .RSTINMODE(1'b0),
      .RSTM(1'b0),
      .RSTP(1'b0)
      );

endmodule // dsp48_wrap_f

Ex2

// p = c + b * a 3 cycles if r else p = p + b * a
module macc
  (
   input 		  clock,
   input [2:0] 		  ce, // bit 0 = a, 1 = b , 2 = c
   input 		  r, // reset accumulator to c + a*b
   input signed [24:0] 	  a,
   input signed [17:0] 	  b,
   input signed [47:0] 	  c,
   output signed [47-S:0] p);

   parameter S = 0;
   parameter AREG = 1; // 0 - 2
   parameter BREG = 1; // 0 - 2

   wire signed [47:0] 	   dsp_p;
   assign p = dsp_p[47:S];

   // X+Y is usually the multiplier output (M)
   // Z is either P, PCIN or C
   // bit 1:0: 0: Z+X+Y 3:Z-(X+Y) 1: -Z + (X+Y) 2: -1*(Z+X+Y+1)
   // bits 3:2, 0: Z=0, 1: Z=PCIN, 2: Z=P, 3: Z = C
   // bit 4: sub in pre add
   wire [4:0]  mode = {1'b0, r ? 2'b11 : 2'b10, 2'b00};

   DSP48E1
     #(
       .A_INPUT("DIRECT"),   // "DIRECT" "CASCADE"
       .B_INPUT("DIRECT"),   // "DIRECT" "CASCADE"
       .USE_DPORT("FALSE"),
       .USE_MULT("MULTIPLY"),// "MULTIPLY" "DYNAMIC" "NONE"
       .USE_SIMD("ONE48"),   // "ONE48" "TWO24" "FOUR12"
       // pattern detector - not used
       .AUTORESET_PATDET("NO_RESET"), .MASK(48'h3fffffffffff),
       .PATTERN(48'h000000000000), .SEL_MASK("MASK"),
       .SEL_PATTERN("PATTERN"), .USE_PATTERN_DETECT("NO_PATDET"),
       // register enables
       .ACASCREG(1),   // pipeline stages between A/ACIN and ACOUT (0, 1 or 2)
       .ADREG(1),      // pipeline stages for pre-adder (0 or 1)
       .ALUMODEREG(1), // pipeline stages for ALUMODE (0 or 1)
       .AREG(AREG),       // pipeline stages for A (0, 1 or 2)
       .BCASCREG(1),   // pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
       .BREG(BREG),    // pipeline stages for B (0, 1 or 2)
       .CARRYINREG(1), // this and below are 0 or 1
       .CARRYINSELREG(1),
       .CREG(1),
       .DREG(1),
       .INMODEREG(1),
       .MREG(1),
       .OPMODEREG(1),
       .PREG(1))
   dsp48_i
     (
      // status
      .OVERFLOW(),
      .PATTERNDETECT(), .PATTERNBDETECT(),
      .UNDERFLOW(),
      // outs
      .CARRYOUT(),
      .P(dsp_p),
      // control
      .ALUMODE({2'd0, mode[1:0]}),
      .CARRYINSEL(3'd0),
      .CLK(clock),
      .INMODE({1'b0,mode[4],3'b100}),
      .OPMODE({1'b0,mode[3:2],4'b0101}),
      // signal inputs
      .A({5'd0,a}), // 30
      .B(b), // 18
      .C(c), // 48
      .CARRYIN(1'b0),
      .D(25'd0), // 25
      // cascade ports
      .ACOUT(),
      .BCOUT(),
      .CARRYCASCOUT(),
      .MULTSIGNOUT(),
      .PCOUT(),
      .ACIN(30'h0),
      .BCIN(18'h0),
      .CARRYCASCIN(1'b0),
      .MULTSIGNIN(1'b0),
      .PCIN(48'h0),
      // clock enables
      .CEA1(1'b1), .CEA2(ce[0]),
      .CEAD(1'b1),
      .CEALUMODE(1'b1),
      .CEB1(1'b1), .CEB2(ce[1]),
      .CEC(ce[2]),
      .CECARRYIN(1'b1),
      .CECTRL(1'b1), // opmode
      .CED(1'b1),
      .CEINMODE(1'b1),
      .CEM(1'b1), .CEP(1'b1),
      .RSTA(1'b0),
      .RSTALLCARRYIN(1'b0),
      .RSTALUMODE(1'b0),
      .RSTB(1'b0),
      .RSTC(1'b0),
      .RSTCTRL(1'b0),
      .RSTD(1'b0),
      .RSTINMODE(1'b0),
      .RSTM(1'b0),
      .RSTP(1'b0)
      );

endmodule

  

二、FIR實現思路

考慮到調用DSP48E,首先分析DSP48E乘法/乘加的時序特性:

可以看出輸出相比輸入,延遲4拍,仿真3*5,結果與理論一致:

以N-1(不失一般性,N=6)階FIR為例,由於乘法可支持25*18,假設數據18(bit),濾波器系數25(bit)。濾波器系數個數為6:

因此可得FIR實現的基本流程:

  • Step1:對於t時刻,輸入數據與濾波器系數相乘,得到y(t)[N-1:0]
  • Step2:更新數據流:data_chain(t) = y(t)[N-1:0] + [data_chain(t-1) [N-2:0],0]
  • Step3:輸出濾波結果:output = data_chain(t) [N-1]

根據算法流程,設計FPGA數據流:

   1)參數位寬定義

  • 輸入數據:parameter indatwidth = 18;
  • 濾波器系數:parameter coefwidth = 25;
  • DSP48核輸出位寬:localparam multoutwidth = coefwidth + indatwidth;
  • 輸出數據(自定義):parameter outdatwidth = 18;
  • 數據流(截斷位寬自定義):這里 localparam chainwidth 用multoutwidth替代;

  2)數據運算拆解

結合上文Step2的特性,細節上:a)可針對coef0單獨用乘法運算、其他coef利用乘加運算,b)也可以對datachain補零,這里采用后一種思路。

  • 輸入輸出  

  input [indatwidth-1:0] datin;

  input [5:0][coefwidth-1:0] coef;

  input clk,rst;

  output signed [outdatwidth-1:0] datout;

  • DSP48的乘加操作

  genvar ii;

  generate
    for(ii = 0; ii < N; ii++)
    begin
    multiplus mpu(
    .CLK(clk),
    .A(coef[ii]),
    .B(datin),
    .C(dti[ii]),
    .P(mres[ii])
    );
    end
  endgenerate

  • 關於截位

  對數據進行截位,例如對x截位,通常不是直接舍去其他位數,而是對x進行4舍5入,轉化到FPGA就是:

  x1 <= x[起始位置 -:  有效位數] + 1;

  result <= (x1>>>1);

   這里僅論證實現思路,截位的細節操作不再添加。

  • 乘法器的延拍

genvar ii;
generate
for(ii = 1; ii < N; ii++)
begin
always @(posedge clk) begin
dtchain[ii][fixdelay-1:1] <= dtchain[ii][fixdelay-2:0];
dtchain[ii][0] <= mres[ii-1][multoutwidth-1:0];
end
end
endgenerate

三、仿真驗證

 首先MATLAB仿真驗證上述步驟的有效性:

%FIR功能驗證
clc;clear all;close all;
coef = [-15,19,123,123,19,-15];
datin = [3,13,17,21,24,28,31];
%main
%不考慮延拍,datachain不必引入
N = 6;
mres = zeros(1,N);
dto = zeros(1,N);
result = [];
for i = 1:length(datin)
    dto(2:N) = mres(1:N-1);
    mres = datin(i)*coef + dto;
    result = [result,mres(N)];
end
%compare
conv_res = conv(datin,coef);
[result;conv_res(1:length(datin))]

  算法運算結果與理論一致:

編寫測試模塊及testbench:

winfilter.sv

`timescale 1ns / 1ps
module winfilter(coef, datin, clk, rst, datout);
//parameter
parameter indatwidth = 18;
parameter outdatwidth = 18;
parameter coefwidth = 25;
localparam multoutwidth = coefwidth + indatwidth;
localparam N = 6;
localparam fixdelay = 4;//smultplus delay
//port
input [indatwidth-1:0] datin;
input [N-1:0][coefwidth-1:0] coef;
input clk,rst;
output [outdatwidth-1:0] datout;
//define
reg signed [outdatwidth-1:0] datout;
reg  [N-1:0][fixdelay-1:0][multoutwidth-1:0] dtchain;
wire [N-1:0][multoutwidth:0] mres;
//initial
initial
begin
	dtchain <= 0;
	datout <= 0;
end
//main
genvar ii;
generate
	for(ii = 1; ii < N; ii++)
	begin
    always @(posedge clk)  begin
        dtchain[ii][fixdelay-1:1] <= dtchain[ii][fixdelay-2:0];
        dtchain[ii][0] <= mres[ii-1][multoutwidth-1:0];
    end
	end
endgenerate
generate
	for(ii = 0; ii < N; ii++)
	begin
    multiplus multp_inst(
        .CLK(clk),
        .A(coef[ii]),
        .B(datin),
        .C(dtchain[ii][fixdelay-1]),
        .P(mres[ii])
        );
	end
endgenerate
//output 	
always @(posedge clk)
begin
	if(rst)
	begin
		datout <= 0;
	end
	else
	begin
        datout <= mres[N-1][multoutwidth-19 -: outdatwidth];
		//datout <= mres[N-1][multoutwidth-2 -: outdatwidth];
	end
end
endmodule

  tb

`timescale 1ns / 1ps
module tb();
logic [17:0] datin;
logic clk,rst;
logic [5:0][24:0] coef;
logic [17:0] datout;

//-------------------------------------//
parameter data_num = 32'd1024;
reg [17:0]  data_men[1:data_num];
initial begin
    $readmemb("D:/PRJ/vivado/simulation_ding/009_lpf6tap/matlab/sin_data.txt",data_men);
end
integer   i = 1;
always @(posedge clk) begin
    datin <= data_men[i];
    i <= i + 8'd1;
end

initial begin
    clk <= 0;
    rst <= 0;
    datin <= 0;
    coef <= 0;
#4
coef <= {-25'd15,25'd19,25'd123,25'd123,25'd19,-25'd15};
#6000
$stop;
end

always #2 clk = ~clk;

winfilter wininst(
.coef(coef), 
.datin(datin), 
.clk(clk), 
.rst(rst), 
.datout(datout)
);
endmodule

  其中dsp48參數設置:

 

 仿真結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM