0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基2FFT的verilog代碼實(shí)現(xiàn)及仿真

CHANBAEK ? 來(lái)源:FPGA自學(xué)筆記分享 ? 作者:FPGA自學(xué)筆記分享 ? 2023-06-02 12:38 ? 次閱讀

上文基2FFT的算法推導(dǎo)及python仿真推導(dǎo)了基2FFT的公式,并通過(guò)python做了算法驗(yàn)證,本文使用verilog實(shí)現(xiàn)8點(diǎn)基2FFT的代碼。

根據(jù)算法推導(dǎo),8點(diǎn)FFT的verilog代碼整體結(jié)構(gòu)為:

圖片

verilog代碼實(shí)現(xiàn)首先進(jìn)行2點(diǎn)FFT的實(shí)現(xiàn),代碼主要做D0+D1操作和(D0+D1)*W02操作,代碼及操作內(nèi)容如下:

圖片

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




`timescale 1ns/100ps
module cm_fft2_N2 #(
    parameter                       C_DATA_WITH     = 16  )
(
    input  wire                     I_sys_clk       , /// 工作時(shí)鐘 100M
    input  wire                     I_data_start    , /// 數(shù)據(jù)開(kāi)始進(jìn)入標(biāo)志,與第一個(gè)數(shù)據(jù)對(duì)齊輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real  , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag  , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    output reg                      O_data_start    , /// 數(shù)據(jù)開(kāi)始輸出標(biāo)志與第一個(gè)數(shù)據(jù)對(duì)齊輸出
    output reg  [C_DATA_WITH:0]     O_data_out_real , /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
    output reg  [C_DATA_WITH:0]     O_data_out_imag   /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
);


// ============================================================
// 內(nèi)部參數(shù)
// ============================================================
///  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

/// 緩存第一個(gè)數(shù)
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

四點(diǎn)FFT的代碼實(shí)現(xiàn)如下,要注意4點(diǎn)FFT中W04=1,W14=-j,代碼實(shí)現(xiàn)中要注意。

圖片

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




`timescale 1ns/100ps
module cm_fft2_N4 #(
    parameter                       C_DATA_WITH     = 16  )
(
    input  wire                     I_sys_clk       , /// 工作時(shí)鐘 100M
    input  wire                     I_data_start    , /// 數(shù)據(jù)開(kāi)始進(jìn)入標(biāo)志,與第一個(gè)數(shù)據(jù)對(duì)齊輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_real  , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    input  wire [C_DATA_WITH-1:0]   I_data_in_imag  , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    output wire                     O_data_start    , /// 數(shù)據(jù)開(kāi)始輸出標(biāo)志與第一個(gè)數(shù)據(jù)對(duì)齊輸出
    output wire [C_DATA_WITH+1:0]   O_data_out_real , /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
    output wire [C_DATA_WITH+1:0]   O_data_out_imag   /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
);


// ============================================================
// 內(nèi)部參數(shù)
// ============================================================
///  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

/// 緩存數(shù)據(jù)
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                          ) , /// 工作時(shí)鐘 100M
    .I_data_start       (S_data_start_d3|S_data_start_d5    ) , /// 數(shù)據(jù)開(kāi)始進(jìn)入標(biāo)志,與第一個(gè)數(shù)據(jù)對(duì)齊輸入
    .I_data_in_real     (S_data_out_real                    ) , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    .I_data_in_imag     (S_data_out_imag                    ) , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    .O_data_start       (                                   ) , /// 數(shù)據(jù)開(kāi)始輸出標(biāo)志與第一個(gè)數(shù)據(jù)對(duì)齊輸出
    .O_data_out_real    (O_data_out_real                    ) , /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
    .O_data_out_imag    (O_data_out_imag                    )   /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
);


assign O_data_start = S_data_start_d5 ;




endmodule

同理,進(jìn)行8點(diǎn)FFT的計(jì)算,8點(diǎn)FFT的計(jì)算用到,W08=1,W18=0.707 - 0.707*1j,W28=-1j,W38=-0.707 - 0.707*1j,為了方便計(jì)算對(duì)其進(jìn)行1024倍的量化,即1=1024,代碼中使用W08=1024,W18=724 - 724*1j,W28=-1024j,W38=-724 - 724*1j。同時(shí)調(diào)用cmult復(fù)乘核進(jìn)行復(fù)乘運(yùn)算。代碼如下:

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




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


// ============================================================
// 內(nèi)部參數(shù)
// ============================================================
///  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

/// 緩存數(shù)據(jù)
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

/// 調(diào)用復(fù)乘 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                          ) , /// 工作時(shí)鐘 100M
    .I_data_start       (S_data_start_d7|S_data_start_d11   ) , /// 數(shù)據(jù)開(kāi)始進(jìn)入標(biāo)志,與第一個(gè)數(shù)據(jù)對(duì)齊輸入
    .I_data_in_real     (S_data_out_real                    ) , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    .I_data_in_imag     (S_data_out_imag                    ) , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    .O_data_start       (                                   ) , /// 數(shù)據(jù)開(kāi)始輸出標(biāo)志與第一個(gè)數(shù)據(jù)對(duì)齊輸出
    .O_data_out_real    (O_data_out_real                    ) , /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
    .O_data_out_imag    (O_data_out_imag                    )   /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
);


assign O_data_start = S_data_start_d12 ;






endmodule

輸出倒序模塊主要是用來(lái)實(shí)現(xiàn)下圖中的地址轉(zhuǎn)換,代碼使用分布式RAM的乒乓操作,緩存兩組數(shù)據(jù)信息,然后使用計(jì)數(shù)器的bit翻轉(zhuǎn)達(dá)到輸出倒序的目的。

圖片

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




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


// ============================================================
// 內(nèi)部參數(shù)
// ============================================================
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如下,仿真調(diào)用三組數(shù)據(jù),將輸出結(jié)果與上文python代碼的輸出進(jìn)行對(duì)比,證明代碼正確。

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




`timescale 1ns/100ps
module tb_cm_fft2_8_top ;
    parameter                           C_DATA_WITH_IN   = 16  ;
    parameter                           C_DATA_WITH_OUT  = 19  ; ///要根據(jù)FFT點(diǎn)數(shù)合理設(shè)置
    parameter                           C_N_NUM          = 8   ; ///fft點(diǎn)數(shù) 2,4,8,16...


    reg                          I_sys_clk             ='d0 ; /// 工作時(shí)鐘 100M
    reg                          I_data_start          ='d0 ; /// 數(shù)據(jù)開(kāi)始進(jìn)入標(biāo)志,與第一個(gè)數(shù)據(jù)對(duì)齊輸入
    reg  [C_DATA_WITH_IN-1:0]    I_data_in_real        ='d0 ; /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    reg  [C_DATA_WITH_IN-1:0]    I_data_in_imag        ='d0 ; /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    wire                         O_data_start           ; /// 數(shù)據(jù)開(kāi)始輸出標(biāo)志與第一個(gè)數(shù)據(jù)對(duì)齊輸出
    wire [C_DATA_WITH_OUT-1:0]   O_data_out_real        ; /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出,位寬按照最大能力輸出
    wire [C_DATA_WITH_OUT-1:0]   O_data_out_imag        ; /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出,位寬按照最大能力輸出



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                          ) , /// 工作時(shí)鐘 100M
    .I_data_start       (I_data_start                       ) , /// 數(shù)據(jù)開(kāi)始進(jìn)入標(biāo)志,與第一個(gè)數(shù)據(jù)對(duì)齊輸入
    .I_data_in_real     (I_data_in_real                     ) , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    .I_data_in_imag     (I_data_in_imag                     ) , /// 數(shù)據(jù)輸入,從start開(kāi)始連續(xù)輸入
    .O_data_start       (O_data_start                       ) , /// 數(shù)據(jù)開(kāi)始輸出標(biāo)志與第一個(gè)數(shù)據(jù)對(duì)齊輸出
    .O_data_out_real    (O_data_out_real                    ) , /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
    .O_data_out_imag    (O_data_out_imag                    )   /// 數(shù)據(jù)輸出,從start開(kāi)始連續(xù)輸出
);






endmodule

輸入信號(hào)

圖片

輸出信號(hào):

圖片

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1625

    文章

    21620

    瀏覽量

    601232
  • 算法
    +關(guān)注

    關(guān)注

    23

    文章

    4587

    瀏覽量

    92501
  • 仿真
    +關(guān)注

    關(guān)注

    50

    文章

    4023

    瀏覽量

    133336
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68229
  • python
    +關(guān)注

    關(guān)注

    55

    文章

    4767

    瀏覽量

    84375
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【NUCLEO-F412ZG試用體驗(yàn)】ARM的FFT使用及誤差分析

    的數(shù)字信號(hào),就可以做FFT變換了。N個(gè)采樣點(diǎn)數(shù)據(jù),在經(jīng)過(guò)FFT之后,就可以得到N個(gè)點(diǎn)的FFT結(jié)果。對(duì)于快速FFT算法,有
    發(fā)表于 12-16 20:31

    modelsim 仿真fft

    modelsim 仿真fft ,自己用Verilog寫(xiě)的程序,我給一個(gè)正弦波,發(fā)現(xiàn)仿真后的結(jié)果是四個(gè)尖峰,按道理說(shuō)應(yīng)該是兩個(gè)尖峰相互對(duì)稱(chēng),我是512點(diǎn)的。為什么中間多出兩個(gè)尖峰,不知道
    發(fā)表于 01-20 08:53

    Verilog代碼書(shū)寫(xiě)規(guī)范

    Verilog代碼書(shū)寫(xiě)規(guī)范 本規(guī)范的目的是提高書(shū)寫(xiě)代碼的可讀性、可修改性、可重用性,優(yōu)化代碼綜合和仿真的結(jié)果,指導(dǎo)設(shè)計(jì)工程師使用
    發(fā)表于 04-15 09:47 ?106次下載

    FFT Verilog RTL

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

    FFT變換

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

    fpga實(shí)現(xiàn)jpeg Verilog代碼

    本站提供的fpga實(shí)現(xiàn)jpeg Verilog代碼資料,希望能夠幫你的學(xué)習(xí)。
    發(fā)表于 05-27 15:09 ?200次下載

    基于FPGA高精度浮點(diǎn)運(yùn)算器的FFT設(shè)計(jì)與仿真

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

    八選一多路選擇器Verilog代碼仿真結(jié)果MUX_8

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

    快速傅里葉變換FFT的C程序代碼實(shí)現(xiàn)

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

    可配置FFT IP核的實(shí)現(xiàn)及基礎(chǔ)教程

    針對(duì)FFT算法基于FPGA實(shí)現(xiàn)可配置的IP核。采用基于流水線(xiàn)結(jié)構(gòu)和快速并行算法實(shí)現(xiàn)了蝶形運(yùn)算和4k點(diǎn)FFT的輸入點(diǎn)數(shù)、數(shù)據(jù)位寬、分解自由配
    發(fā)表于 11-18 06:32 ?7978次閱讀
    可配置<b class='flag-5'>FFT</b> IP核的<b class='flag-5'>實(shí)現(xiàn)</b>及基礎(chǔ)教程

    24時(shí)分FFT算法淺析及其比較

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

    如何使用Icarus Verilog+GTKWave來(lái)進(jìn)行verilog文件的編譯和仿真

    Windows+Linux+MacOS,并且源代碼開(kāi)源。通過(guò)tb文件可以生成對(duì)應(yīng)的仿真波形數(shù)據(jù)文件,通過(guò)GTKWave可以查看仿真波形圖,支持將Verilog轉(zhuǎn)換為VHDL文件。 1.
    的頭像 發(fā)表于 07-27 09:16 ?5276次閱讀
    如何使用Icarus <b class='flag-5'>Verilog</b>+GTKWave來(lái)進(jìn)行<b class='flag-5'>verilog</b>文件的編譯和<b class='flag-5'>仿真</b>

    Vivado:ROM和RAM的verilog代碼實(shí)現(xiàn)

    本文主要介紹ROM和RAM實(shí)現(xiàn)verilog代碼版本,可以借鑒參考下。
    的頭像 發(fā)表于 05-16 16:57 ?1543次閱讀

    2FFT的算法推導(dǎo)及python仿真

    FFT的算法推導(dǎo)主要用到旋轉(zhuǎn)因子的周期性、對(duì)稱(chēng)性和可約性。
    的頭像 發(fā)表于 06-02 12:38 ?2073次閱讀
    <b class='flag-5'>基</b><b class='flag-5'>2FFT</b>的算法推導(dǎo)及python<b class='flag-5'>仿真</b>

    Verilog代碼封裝后門(mén)訪(fǎng)問(wèn)

    關(guān)于仿真里的后門(mén)訪(fǎng)問(wèn),之前的文章《三分鐘教會(huì)你SpinalHDL仿真中的后門(mén)讀寫(xiě)》中有做過(guò)介紹,其針對(duì)的都是針對(duì)以SpinalHDL中的代碼進(jìn)行的后門(mén)訪(fǎng)問(wèn)。今天來(lái)看看當(dāng)封裝了Verilog
    的頭像 發(fā)表于 07-15 10:22 ?814次閱讀
    <b class='flag-5'>Verilog</b><b class='flag-5'>代碼</b>封裝后門(mén)訪(fǎng)問(wèn)