吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基2FFT的verilog代碼實現及仿真

CHANBAEK ? 來源:FPGA自學筆記分享 ? 作者:FPGA自學筆記分享 ? 2023-06-02 12:38 ? 次閱讀

上文基2FFT的算法推導及python仿真推導了基2FFT的公式,并通過python做了算法驗證,本文使用verilog實現8點基2FFT的代碼。

根據算法推導,8點FFT的verilog代碼整體結構為:

圖片

verilog代碼實現首先進行2點FFT的實現,代碼主要做D0+D1操作和(D0+D1)*W02操作,代碼及操作內容如下:

圖片

// ============================================================
// File Name: cm_fft2_N2
// VERSION  : V1.0
// DATA     : 2023/1/1
// Author   : FPGA干貨分享
// ============================================================
// 功能:基2FFT N=2的數據處理
// delay : 2clk
// ============================================================




`timescale 1ns/100ps
module cm_fft2_N2 #(
    parameter                       C_DATA_WITH     = 16  )
(
    input  wire                     I_sys_clk       , /// 工作時鐘 100M
    input  wire                     I_data_start    , /// 數據開始進入標志,與第一個數據對齊輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real  , /// 數據輸入,從start開始連續輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag  , /// 數據輸入,從start開始連續輸入
    output reg                      O_data_start    , /// 數據開始輸出標志與第一個數據對齊輸出
    output reg  [C_DATA_WITH:0]     O_data_out_real , /// 數據輸出,從start開始連續輸出
    output reg  [C_DATA_WITH:0]     O_data_out_imag   /// 數據輸出,從start開始連續輸出
);


// ============================================================
// 內部參數
// ============================================================
///  W02=1
// ============================================================
// 變量
// ============================================================
reg                     S_data_start         ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d1    ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d2    ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d1    ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d2    ;


// ============================================================
// main code
// ============================================================


always @(posedge I_sys_clk)
    begin
        S_data_start   <= I_data_start ;
        O_data_start   <= S_data_start ;
    end

/// 緩存第一個數
always @(posedge I_sys_clk)
    begin
        S_data_in_real_d1 <= I_data_in_real    ;
        S_data_in_real_d2 <= S_data_in_real_d1 ;
        S_data_in_imag_d1 <= I_data_in_imag    ;
        S_data_in_imag_d2 <= S_data_in_imag_d1 ;
    end


always @(posedge I_sys_clk)
    if(S_data_start)
        /// x(n)+x(n+N/2)
        begin
            O_data_out_real <= {S_data_in_real_d1[C_DATA_WITH-1],S_data_in_real_d1} + {I_data_in_real[C_DATA_WITH-1],I_data_in_real} ;
            O_data_out_imag <= {S_data_in_imag_d1[C_DATA_WITH-1],S_data_in_imag_d1} + {I_data_in_imag[C_DATA_WITH-1],I_data_in_imag} ;
        end
    else if(O_data_start)
        /// [x(n)-x(n+N/2)]C_W02
        begin
            O_data_out_real <= {S_data_in_real_d2[C_DATA_WITH-1],S_data_in_real_d2} - {S_data_in_real_d1[C_DATA_WITH-1],S_data_in_real_d1} ;
            O_data_out_imag <= {S_data_in_imag_d2[C_DATA_WITH-1],S_data_in_imag_d2} - {S_data_in_imag_d1[C_DATA_WITH-1],S_data_in_imag_d1} ;
        end
    else
        begin
            O_data_out_real <= 'd0;
            O_data_out_imag <= 'd0;
        end




endmodule

四點FFT的代碼實現如下,要注意4點FFT中W04=1,W14=-j,代碼實現中要注意。

圖片

// ============================================================
// File Name: cm_fft2_N4
// VERSION  : V1.0
// DATA     : 2023/1/1
// Author   : FPGA干貨分享
// ============================================================
// 功能:基2FFT N=4的數據處理
// delay : 5clk
// ============================================================




`timescale 1ns/100ps
module cm_fft2_N4 #(
    parameter                       C_DATA_WITH     = 16  )
(
    input  wire                     I_sys_clk       , /// 工作時鐘 100M
    input  wire                     I_data_start    , /// 數據開始進入標志,與第一個數據對齊輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real  , /// 數據輸入,從start開始連續輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag  , /// 數據輸入,從start開始連續輸入
    output wire                     O_data_start    , /// 數據開始輸出標志與第一個數據對齊輸出
    output wire [C_DATA_WITH+1:0]   O_data_out_real , /// 數據輸出,從start開始連續輸出
    output wire [C_DATA_WITH+1:0]   O_data_out_imag   /// 數據輸出,從start開始連續輸出
);


// ============================================================
// 內部參數
// ============================================================
///  W04=1
///  W14=-j
// ============================================================
// 變量
// ============================================================
reg                     S_data_start_d1     ;
reg                     S_data_start_d2     ;
reg                     S_data_start_d3     ;
reg                     S_data_start_d4     ;
reg                     S_data_start_d5     ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d1   ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d2   ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d3   ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d4   ;
reg [C_DATA_WITH-1:0]   S_data_in_real_d5   ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d1   ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d2   ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d3   ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d4   ;
reg [C_DATA_WITH-1:0]   S_data_in_imag_d5   ;


reg [C_DATA_WITH:0]     S_data_out_real     ; /// x1 X2
reg [C_DATA_WITH:0]     S_data_out_imag     ; /// x1 X2


// ============================================================
// main code
// ============================================================


always @(posedge I_sys_clk)
    begin
        S_data_start_d1   <= I_data_start ;
        S_data_start_d2   <= S_data_start_d1 ;
        S_data_start_d3   <= S_data_start_d2 ;
        S_data_start_d4   <= S_data_start_d3 ;
        S_data_start_d5   <= S_data_start_d4 ;
    end

/// 緩存數據
always @(posedge I_sys_clk)
    begin
       S_data_in_real_d1 <= I_data_in_real ;
       S_data_in_real_d2 <= S_data_in_real_d1 ;
       S_data_in_real_d3 <= S_data_in_real_d2 ;
       S_data_in_real_d4 <= S_data_in_real_d3 ;
       S_data_in_real_d5 <= S_data_in_real_d4 ;
       S_data_in_imag_d1 <= I_data_in_imag ;
       S_data_in_imag_d2 <= S_data_in_imag_d1 ;
       S_data_in_imag_d3 <= S_data_in_imag_d2 ;
       S_data_in_imag_d4 <= S_data_in_imag_d3 ;
       S_data_in_imag_d5 <= S_data_in_imag_d4 ;
    end


/// 
always @(posedge I_sys_clk)
    if(S_data_start_d4)
        /// (x(n)-x(n+N/2)*W04 = (x(n)-x(n+N/2)
        begin
            S_data_out_real <= {S_data_in_real_d4[C_DATA_WITH-1],S_data_in_real_d4} - {S_data_in_real_d2[C_DATA_WITH-1],S_data_in_real_d2} ;
            S_data_out_imag <= {S_data_in_imag_d4[C_DATA_WITH-1],S_data_in_imag_d4} - {S_data_in_imag_d2[C_DATA_WITH-1],S_data_in_imag_d2} ;
        end
    else if(S_data_start_d5)
        /// (x(n)-x(n+N/2)*W14 = (x(n)-x(n+N/2)*(-j) = (x(n+N/2)-x(n))*j
        begin
            S_data_out_real <= {S_data_in_imag_d2[C_DATA_WITH-1],S_data_in_imag_d2} - {S_data_in_imag_d4[C_DATA_WITH-1],S_data_in_imag_d4} ;
            S_data_out_imag <= {S_data_in_real_d2[C_DATA_WITH-1],S_data_in_real_d2} - {S_data_in_real_d4[C_DATA_WITH-1],S_data_in_real_d4} ;  
        end
    else
    /// x(n)+x(n+N/2)  x(0)+x(2)
    begin
        S_data_out_real <= {S_data_in_real_d2[C_DATA_WITH-1],S_data_in_real_d2} + {I_data_in_real[C_DATA_WITH-1],I_data_in_real} ;
        S_data_out_imag <= {S_data_in_imag_d2[C_DATA_WITH-1],S_data_in_imag_d2} + {I_data_in_imag[C_DATA_WITH-1],I_data_in_imag} ;
    end

///delay 2clk
cm_fft2_N2 #(
    .C_DATA_WITH        (C_DATA_WITH+1                      ) )
u0_cm_fft2_N2(
    .I_sys_clk          (I_sys_clk                          ) , /// 工作時鐘 100M
    .I_data_start       (S_data_start_d3|S_data_start_d5    ) , /// 數據開始進入標志,與第一個數據對齊輸入
    .I_data_in_real     (S_data_out_real                    ) , /// 數據輸入,從start開始連續輸入
    .I_data_in_imag     (S_data_out_imag                    ) , /// 數據輸入,從start開始連續輸入
    .O_data_start       (                                   ) , /// 數據開始輸出標志與第一個數據對齊輸出
    .O_data_out_real    (O_data_out_real                    ) , /// 數據輸出,從start開始連續輸出
    .O_data_out_imag    (O_data_out_imag                    )   /// 數據輸出,從start開始連續輸出
);


assign O_data_start = S_data_start_d5 ;




endmodule

同理,進行8點FFT的計算,8點FFT的計算用到,W08=1,W18=0.707 - 0.707*1j,W28=-1j,W38=-0.707 - 0.707*1j,為了方便計算對其進行1024倍的量化,即1=1024,代碼中使用W08=1024,W18=724 - 724*1j,W28=-1024j,W38=-724 - 724*1j。同時調用cmult復乘核進行復乘運算。代碼如下:

// ============================================================
// File Name: cm_fft2_N8
// VERSION  : V1.0
// DATA     : 2023/1/1
// Author   : FPGA干貨分享
// ============================================================
// 功能:基2FFT N=8的數據處理
// delay : 12clk
// ============================================================




`timescale 1ns/100ps
module cm_fft2_N8 #(
    parameter                       C_DATA_WITH     = 16  )
(
    input  wire                     I_sys_clk       , /// 工作時鐘 100M
    input  wire                     I_data_start    , /// 數據開始進入標志,與第一個數據對齊輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real  , /// 數據輸入,從start開始連續輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag  , /// 數據輸入,從start開始連續輸入
    output wire                     O_data_start    , /// 數據開始輸出標志與第一個數據對齊輸出
    output wire [C_DATA_WITH+2:0]   O_data_out_real , /// 數據輸出,從start開始連續輸出
    output wire [C_DATA_WITH+2:0]   O_data_out_imag   /// 數據輸出,從start開始連續輸出
);


// ============================================================
// 內部參數
// ============================================================
///  W08=1
///  W18=0.707 - 0.707*1j
///  W28=-1j
///  W38=-0.707 - 0.707*1j
// ============================================================
// 變量
// ============================================================
reg                      S_data_start_d1     ;
reg                      S_data_start_d2     ;
reg                      S_data_start_d3     ;
reg                      S_data_start_d4     ;
reg                      S_data_start_d5     ;
reg                      S_data_start_d6     ;
reg                      S_data_start_d7     ;
reg                      S_data_start_d8     ;
reg                      S_data_start_d9     ;
reg                      S_data_start_d10    ;
reg                      S_data_start_d11    ;
reg                      S_data_start_d12    ;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d1   ;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d2   ;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d3   ;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d4   ;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d5   ;
reg  [C_DATA_WITH-1:0]   S_data_in_real_d6   ;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d1   ;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d2   ;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d3   ;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d4   ;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d5   ;
reg  [C_DATA_WITH-1:0]   S_data_in_imag_d6   ;

reg  [11:0]              S_Wn8_real          ;
reg  [11:0]              S_Wn8_imag          ;
reg  [C_DATA_WITH:0]     S_data_cut_real     ;
reg  [C_DATA_WITH:0]     S_data_cut_imag     ;
wire [C_DATA_WITH+13:0]  S_data_multW_real   ; /// X2
wire [C_DATA_WITH+13:0]  S_data_multW_imag   ; /// X2


reg  [C_DATA_WITH:0]     S_data_add_real     ; /// x1
reg  [C_DATA_WITH:0]     S_data_add_imag     ; /// x1

wire [C_DATA_WITH:0]     S_data_out_real     ; /// x1 X2
wire [C_DATA_WITH:0]     S_data_out_imag     ; /// x1 X2
// ============================================================
// main code
// ============================================================


always @(posedge I_sys_clk)
    begin
        S_data_start_d1   <= I_data_start ;
        S_data_start_d2   <= S_data_start_d1 ;
        S_data_start_d3   <= S_data_start_d2 ;
        S_data_start_d4   <= S_data_start_d3 ;
        S_data_start_d5   <= S_data_start_d4 ;
        S_data_start_d6   <= S_data_start_d5 ;
        S_data_start_d7   <= S_data_start_d6 ;
        S_data_start_d8   <= S_data_start_d7 ;
        S_data_start_d9   <= S_data_start_d8 ;
        S_data_start_d10  <= S_data_start_d9 ;
        S_data_start_d11  <= S_data_start_d10;
        S_data_start_d12  <= S_data_start_d11;
    end

/// 緩存數據
always @(posedge I_sys_clk)
    begin
       S_data_in_real_d1 <= I_data_in_real ;
       S_data_in_real_d2 <= S_data_in_real_d1 ;
       S_data_in_real_d3 <= S_data_in_real_d2 ;
       S_data_in_real_d4 <= S_data_in_real_d3 ;
       S_data_in_real_d5 <= S_data_in_real_d4 ;
       S_data_in_real_d6 <= S_data_in_real_d5 ;
       S_data_in_imag_d1 <= I_data_in_imag ;
       S_data_in_imag_d2 <= S_data_in_imag_d1 ;
       S_data_in_imag_d3 <= S_data_in_imag_d2 ;
       S_data_in_imag_d4 <= S_data_in_imag_d3 ;
       S_data_in_imag_d5 <= S_data_in_imag_d4 ;
       S_data_in_imag_d6 <= S_data_in_imag_d5 ;
    end


always @(posedge I_sys_clk)
    begin
        S_data_cut_real <= {S_data_in_real_d4[C_DATA_WITH-1],S_data_in_real_d4} - {I_data_in_real[C_DATA_WITH-1],I_data_in_real} ;
        S_data_cut_imag <= {S_data_in_imag_d4[C_DATA_WITH-1],S_data_in_imag_d4} - {I_data_in_imag[C_DATA_WITH-1],I_data_in_imag} ;
    end




always @(*)
    if(S_data_start_d5)
        begin
            S_Wn8_real = 12'd1024   ;
            S_Wn8_imag = 12'd0      ;
        end
    else if(S_data_start_d6)
        begin
            S_Wn8_real = 12'd724    ;
            S_Wn8_imag = -12'd724   ;
        end
    else if(S_data_start_d7)
        begin
            S_Wn8_real = 12'd0      ;
            S_Wn8_imag = -12'd1024  ;
        end
    else
        begin
            S_Wn8_real = -12'd724   ;
            S_Wn8_imag = -12'd724   ;
        end

/// 調用復乘 delay 6clk
cmult # (.AWIDTH    (C_DATA_WITH+1      ) ,
         .BWIDTH    (12                 ) )
u0_cmult
        (
         .clk       (I_sys_clk          ) ,
         .ar        (S_data_cut_real    ) ,
         .ai        (S_data_cut_imag    ) ,
         .br        (S_Wn8_real         ) ,
         .bi        (S_Wn8_imag         ) ,
         .pr        (S_data_multW_real  ) ,
         .pi        (S_data_multW_imag  ) 
        );


/// 
always @(posedge I_sys_clk)
    /// x(n)+x(n+N/2)  x(0)+x(4) ...
    begin
        S_data_add_real <= {S_data_in_real_d6[C_DATA_WITH-1],S_data_in_real_d6} + {S_data_in_real_d2[C_DATA_WITH-1],S_data_in_real_d2} ;
        S_data_add_imag <= {S_data_in_imag_d6[C_DATA_WITH-1],S_data_in_imag_d6} + {S_data_in_imag_d2[C_DATA_WITH-1],S_data_in_imag_d2} ;
    end

assign S_data_out_real = (S_data_start_d7|S_data_start_d8|S_data_start_d9|S_data_start_d10) ? S_data_add_real : (S_data_multW_real[10+:(C_DATA_WITH+1)] + S_data_multW_real[9]) ;
assign S_data_out_imag = (S_data_start_d7|S_data_start_d8|S_data_start_d9|S_data_start_d10) ? S_data_add_imag : (S_data_multW_imag[10+:(C_DATA_WITH+1)] + S_data_multW_imag[9]) ;


///delay 5clk
cm_fft2_N4 #(
    .C_DATA_WITH        (C_DATA_WITH+1                      ) )
u0_cm_fft2_N4(
    .I_sys_clk          (I_sys_clk                          ) , /// 工作時鐘 100M
    .I_data_start       (S_data_start_d7|S_data_start_d11   ) , /// 數據開始進入標志,與第一個數據對齊輸入
    .I_data_in_real     (S_data_out_real                    ) , /// 數據輸入,從start開始連續輸入
    .I_data_in_imag     (S_data_out_imag                    ) , /// 數據輸入,從start開始連續輸入
    .O_data_start       (                                   ) , /// 數據開始輸出標志與第一個數據對齊輸出
    .O_data_out_real    (O_data_out_real                    ) , /// 數據輸出,從start開始連續輸出
    .O_data_out_imag    (O_data_out_imag                    )   /// 數據輸出,從start開始連續輸出
);


assign O_data_start = S_data_start_d12 ;






endmodule

輸出倒序模塊主要是用來實現下圖中的地址轉換,代碼使用分布式RAM的乒乓操作,緩存兩組數據信息,然后使用計數器的bit翻轉達到輸出倒序的目的。

圖片

// ============================================================
// File Name: cm_fft2_top
// VERSION  : V1.0
// DATA     : 2023/1/2
// Author   : FPGA干貨分享
// ============================================================
// 功能:基2FFT 輸出數據倒換
// delay : fft N=8 delay8clk
// ============================================================




`timescale 1ns/100ps
module cm_fft2_output_change #(
    parameter                       C_DATA_WIDTH      = 16  ,
    parameter                       C_ADDR_NUM       = 4   ) ///fft點數為2**C_ADDR_NUM
(
    input  wire                     I_sys_clk              , /// 工作時鐘 100M
    input  wire                     I_data_start           , /// 數據開始進入標志,與第一個數據對齊輸入
    input  wire [C_DATA_WIDTH-1:0]  I_data_in_real         , /// 數據輸入,從start開始連續輸入
    input  wire [C_DATA_WIDTH-1:0]  I_data_in_imag         , /// 數據輸入,從start開始連續輸入
    output wire                     O_data_start           , /// 數據開始輸出標志與第一個數據對齊輸出
    output wire [C_DATA_WIDTH-1:0]  O_data_out_real        , /// 數據輸出,從start開始連續輸出,位寬按照最大能力輸出
    output wire [C_DATA_WIDTH-1:0]  O_data_out_imag          /// 數據輸出,從start開始連續輸出,位寬按照最大能力輸出
);


// ============================================================
// 內部參數
// ============================================================
localparam  C_DATA_NUM = 2**C_ADDR_NUM ;
// ============================================================
// 變量
// ============================================================
reg                         S_pingpang_flag     ;
reg  [C_ADDR_NUM:0]         S_wr_addr           ;
wire                        S_wr_en             ;
reg  [C_DATA_WIDTH*2-1:0]   S_data_in           ;
reg  [C_ADDR_NUM-1:0]       S_rd_addr           ;
wire                        S_change_start      ;
reg  [C_ADDR_NUM-1:0]       S_data_cnt          ;
reg                         S_start_d1          ;
reg                         S_start_d2          ;
reg                         S_start_d3          ;
reg                         S_pingpang_flag_rd  ;


// ============================================================
// main code
// ============================================================


always @(posedge I_sys_clk)
    if(I_data_start)
        S_pingpang_flag <= ~S_pingpang_flag;
    else
        S_pingpang_flag <= S_pingpang_flag ;


always @(posedge I_sys_clk)
    if(I_data_start)
        S_wr_addr <= 'b0;
    else if(S_wr_en)
        S_wr_addr <= S_wr_addr + 'd1;
    else
        S_wr_addr <= S_wr_addr ;


assign S_wr_en = ~S_wr_addr[C_ADDR_NUM];


always @(posedge I_sys_clk)
    S_data_in <={I_data_in_real,I_data_in_imag} ;


assign S_change_start = ({S_wr_addr[C_ADDR_NUM-1],|S_wr_addr[C_ADDR_NUM-2:0]} == 2'b10);


always @(posedge I_sys_clk)
    if(S_change_start)
        S_data_cnt <= 'd0;
    else
        S_data_cnt <= S_data_cnt + 'd1;

genvar j;
generate for(j=0;j< C_ADDR_NUM;j=j+1)
    begin:addr_change
        always @(posedge I_sys_clk)
            S_rd_addr[j] <= S_data_cnt[C_ADDR_NUM-j-1];
    end
endgenerate


always @(posedge I_sys_clk)
    if(S_start_d1)
        S_pingpang_flag_rd <= S_pingpang_flag ;
    else
        S_pingpang_flag_rd <= S_pingpang_flag_rd ;




cm_dis_sdp_ram #(
    .C_DATA_WIDTH           ( C_DATA_WIDTH*2            ) , // Specify RAM data width
    .C_ADDR_WIDTH           ( C_ADDR_NUM+1              ) , // Specify RAM depth 2**C_ADDR_WIDTH
    .C_DELAY_NUM            ( 1                         ) , // delay
    .INIT_FILE              ( ""                        ) ) // Specify name/location of RAM initialization file if using one (leave blank if not)
u0_cm_dis_sdp_ram(
    .I_addra                ({S_pingpang_flag,S_wr_addr[C_ADDR_NUM-1:0]}  ) , // Write address bus, width determined from RAM_DEPTH
    .I_addrb                ({S_pingpang_flag_rd,S_rd_addr}               ) , // Read address bus, width determined from RAM_DEPTH
    .I_dina                 (S_data_in                  ) , // RAM input data
    .I_clka                 (I_sys_clk                  ) , // Write clock
    .I_clkb                 (I_sys_clk                  ) , // Read clock
    .I_wea                  (S_wr_en                    ) , // Write enable
    .O_doutb                ({O_data_out_real,O_data_out_imag}        )   // RAM output data
);


always @(posedge I_sys_clk)
    begin
        S_start_d1 <= S_change_start ;
        S_start_d2 <= S_start_d1     ;
        S_start_d3 <= S_start_d2     ;
    end


assign O_data_start = S_start_d3 ;


endmodule

將代碼封裝仿真tb如下,仿真調用三組數據,將輸出結果與上文python代碼的輸出進行對比,證明代碼正確。

// ============================================================
// File Name: tb_cm_fft2_8_top
// VERSION  : V1.0
// DATA     : 2023/1/2
// Author   : FPGA干貨分享
// ============================================================
// 功能:基2FFT N=8的數據處理
// delay : clk
// ============================================================




`timescale 1ns/100ps
module tb_cm_fft2_8_top ;
    parameter                           C_DATA_WITH_IN   = 16  ;
    parameter                           C_DATA_WITH_OUT  = 19  ; ///要根據FFT點數合理設置
    parameter                           C_N_NUM          = 8   ; ///fft點數 2,4,8,16...


    reg                          I_sys_clk             ='d0 ; /// 工作時鐘 100M
    reg                          I_data_start          ='d0 ; /// 數據開始進入標志,與第一個數據對齊輸入
    reg  [C_DATA_WITH_IN-1:0]    I_data_in_real        ='d0 ; /// 數據輸入,從start開始連續輸入
    reg  [C_DATA_WITH_IN-1:0]    I_data_in_imag        ='d0 ; /// 數據輸入,從start開始連續輸入
    wire                         O_data_start           ; /// 數據開始輸出標志與第一個數據對齊輸出
    wire [C_DATA_WITH_OUT-1:0]   O_data_out_real        ; /// 數據輸出,從start開始連續輸出,位寬按照最大能力輸出
    wire [C_DATA_WITH_OUT-1:0]   O_data_out_imag        ; /// 數據輸出,從start開始連續輸出,位寬按照最大能力輸出



always #1 I_sys_clk = ~I_sys_clk;


initial begin

    repeat(100) @(posedge I_sys_clk);
    @(posedge I_sys_clk);
    I_data_start   <= 1'b1;
    I_data_in_real <= 16'd1024;
    I_data_in_imag <= 16'd0;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= 16'd0;
    repeat(6)   @(posedge I_sys_clk);


    @(posedge I_sys_clk);
    I_data_start   <= 1'b1;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= 16'd1024;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd724;
    I_data_in_imag <= 16'd724;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd1024;
    I_data_in_imag <= 16'd0;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd724;
    I_data_in_imag <= -16'd724;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= -16'd1024;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= -16'd724;
    I_data_in_imag <= -16'd724;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= -16'd1024;
    I_data_in_imag <= 16'd0;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= -16'd724;
    I_data_in_imag <= 16'd724;

    //
    @(posedge I_sys_clk);
    I_data_start   <= 1'b1;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= 16'd1024;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd1024;
    I_data_in_imag <= 16'd0;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= -16'd1024;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= -16'd1024;
    I_data_in_imag <= 16'd0;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= 16'd1024;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd1024;
    I_data_in_imag <= 16'd0;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= 16'd0;
    I_data_in_imag <= -16'd1024;
    @(posedge I_sys_clk);
    I_data_start   <= 1'b0;
    I_data_in_real <= -16'd1024;
    I_data_in_imag <= 16'd0;


end




cm_fft2_8_top #(
    .C_DATA_WITH_IN     (C_DATA_WITH_IN                     ) ,
    .C_DATA_WITH_OUT    (C_DATA_WITH_OUT                    ) ,
    .C_N_NUM            (C_N_NUM                            ) )
cm_fft2_8_top  (
    .I_sys_clk          (I_sys_clk                          ) , /// 工作時鐘 100M
    .I_data_start       (I_data_start                       ) , /// 數據開始進入標志,與第一個數據對齊輸入
    .I_data_in_real     (I_data_in_real                     ) , /// 數據輸入,從start開始連續輸入
    .I_data_in_imag     (I_data_in_imag                     ) , /// 數據輸入,從start開始連續輸入
    .O_data_start       (O_data_start                       ) , /// 數據開始輸出標志與第一個數據對齊輸出
    .O_data_out_real    (O_data_out_real                    ) , /// 數據輸出,從start開始連續輸出
    .O_data_out_imag    (O_data_out_imag                    )   /// 數據輸出,從start開始連續輸出
);






endmodule

輸入信號

圖片

輸出信號:

圖片

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • FPGA
    +關注

    關注

    1630

    文章

    21796

    瀏覽量

    605998
  • 算法
    +關注

    關注

    23

    文章

    4630

    瀏覽量

    93352
  • 仿真
    +關注

    關注

    50

    文章

    4124

    瀏覽量

    133991
  • 代碼
    +關注

    關注

    30

    文章

    4825

    瀏覽量

    69046
  • python
    +關注

    關注

    56

    文章

    4807

    瀏覽量

    85037
收藏 人收藏

    評論

    相關推薦

    【NUCLEO-F412ZG試用體驗】ARM的FFT使用及誤差分析

    的數字信號,就可以做FFT變換了。N個采樣點數據,在經過FFT之后,就可以得到N個點的FFT結果。對于快速FFT算法,有
    發表于 12-16 20:31

    modelsim 仿真fft

    modelsim 仿真fft ,自己用Verilog寫的程序,我給一個正弦波,發現仿真后的結果是四個尖峰,按道理說應該是兩個尖峰相互對稱,我是512點的。為什么中間多出兩個尖峰,不知道
    發表于 01-20 08:53

    FFT Verilog RTL

    FFT Verilog RTL
    發表于 07-08 15:55 ?41次下載

    FFT變換

      4.1 引言   4.2 2FFT算法   4.3 進一步減少運算量的措施   4.4 分裂FFT算法   4.5 離散哈特萊變換(DHT)
    發表于 08-11 16:50 ?0次下載

    fpga實現jpeg Verilog代碼

    本站提供的fpga實現jpeg Verilog代碼資料,希望能夠幫你的學習。
    發表于 05-27 15:09 ?200次下載

    基于FPGA高精度浮點運算器的FFT設計與仿真

    提出一種2FFT的FPGA方法,完成了基于FPGA高精度浮點運算器的FFT的設計。利用VHDL語言描述了蝶形運算過程及地址產生單元,其仿真波形基本能正確的表示輸出結果。
    發表于 12-23 14:24 ?46次下載
    基于FPGA高精度浮點運算器的<b class='flag-5'>FFT</b>設計與<b class='flag-5'>仿真</b>

    八選一多路選擇器Verilog代碼仿真結果MUX_8

    八選一多路選擇器 Verilog代碼仿真結果(modelsim仿真
    發表于 03-28 15:27 ?33次下載

    快速傅里葉變換FFT的C程序代碼實現

    本文為您講解快速傅里葉變換FFT的C語言程序代碼實現的具體方法,C編程需要解決的問題及FFT計算結果驗證。
    發表于 10-08 16:38 ?6.1w次閱讀
    快速傅里葉變換<b class='flag-5'>FFT</b>的C程序<b class='flag-5'>代碼</b><b class='flag-5'>實現</b>

    可配置FFT IP核的實現及基礎教程

    針對FFT算法基于FPGA實現可配置的IP核。采用基于流水線結構和快速并行算法實現了蝶形運算和4k點FFT的輸入點數、數據位寬、分解自由配
    發表于 11-18 06:32 ?8224次閱讀
    可配置<b class='flag-5'>FFT</b> IP核的<b class='flag-5'>實現</b>及基礎教程

    24時分FFT算法淺析及其比較

    FFT 算法的實質是把一長序列的 DFT 計算分割為較短序列的 DFT 計算,對于2算法而言,是把序列每次一分為二,最后分割成兩點 DFT,也可以采用別的分割法,每次一分為三,四,五等,就得到了
    發表于 11-23 10:58 ?3w次閱讀
    <b class='flag-5'>基</b><b class='flag-5'>2</b>與<b class='flag-5'>基</b>4時分<b class='flag-5'>FFT</b>算法淺析及其比較

    如何使用Icarus Verilog+GTKWave來進行verilog文件的編譯和仿真

    Windows+Linux+MacOS,并且源代碼開源。通過tb文件可以生成對應的仿真波形數據文件,通過GTKWave可以查看仿真波形圖,支持將Verilog轉換為VHDL文件。 1.
    的頭像 發表于 07-27 09:16 ?5479次閱讀
    如何使用Icarus <b class='flag-5'>Verilog</b>+GTKWave來進行<b class='flag-5'>verilog</b>文件的編譯和<b class='flag-5'>仿真</b>

    使用Matlab和Verilog實現fibonacci序列包括源代碼和testbench

    使用Matlab和Verilog實現fibonacci序列包括源代碼和testbench(電源技術論壇app)-使用Matlab和Verilog實現
    發表于 09-16 14:41 ?13次下載
    使用Matlab和<b class='flag-5'>Verilog</b><b class='flag-5'>實現</b>fibonacci序列包括源<b class='flag-5'>代碼</b>和testbench

    Vivado:ROM和RAM的verilog代碼實現

    本文主要介紹ROM和RAM實現verilog代碼版本,可以借鑒參考下。
    的頭像 發表于 05-16 16:57 ?1856次閱讀

    2FFT的算法推導及python仿真

    FFT的算法推導主要用到旋轉因子的周期性、對稱性和可約性。
    的頭像 發表于 06-02 12:38 ?3167次閱讀
    <b class='flag-5'>基</b><b class='flag-5'>2FFT</b>的算法推導及python<b class='flag-5'>仿真</b>

    Verilog代碼封裝后門訪問

    關于仿真里的后門訪問,之前的文章《三分鐘教會你SpinalHDL仿真中的后門讀寫》中有做過介紹,其針對的都是針對以SpinalHDL中的代碼進行的后門訪問。今天來看看當封裝了Verilog
    的頭像 發表于 07-15 10:22 ?922次閱讀
    <b class='flag-5'>Verilog</b><b class='flag-5'>代碼</b>封裝后門訪問
    百家乐国际娱乐网| 菲律宾百家乐官网娱乐平台| 大发888怎样存款| 嘉年华百家乐官网的玩法技巧和规则| 赌博技巧| 广州百家乐娱乐场开户注册| 中国百家乐官网的玩法技巧和规则 | 永利博百家乐官网的玩法技巧和规则 | 百家乐的桌布| 百家乐官网技巧头头娱乐| 钱柜娱乐城现金网| 百家乐游戏作弊| 沙龙百家乐官网赌场娱乐网规则| 利博| 威尼斯人娱乐城澳门赌场| 24山向内什么山向最好| 真钱百家乐官网公司哪个好| 大发888登陆| 百家乐赌机凤凰软件| 线上百家乐官网试玩| 澳门在线赌场| 威尼斯人娱乐城存取款| 谈谈百家乐赢钱技巧| 百家乐官网皇室百家乐官网| 永利娱乐| 汇丰百家乐的玩法技巧和规则 | 百家乐赢钱密籍| MG百家乐官网大转轮| 百家乐官网美女视频| 澳门顶级赌场| 嘉禾百家乐的玩法技巧和规则| 蚌埠市| 德州扑克入门与提高| 新濠峰百家乐的玩法技巧和规则| 百家乐发牌铲| 最好的百家乐官网博彩网站 | 百家乐用什么平台| 华泰百家乐官网的玩法技巧和规则| 上海百家乐官网赌博| 西华县| 注册娱乐城送体验金|