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
    +关注

    关注

    1602

    文章

    21320

    浏览量

    593194
  • 算法
    +关注

    关注

    23

    文章

    4455

    浏览量

    90755
  • 仿真
    +关注

    关注

    50

    文章

    3872

    浏览量

    132158
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66766
  • python
    +关注

    关注

    51

    文章

    4675

    浏览量

    83466
收藏 人收藏

    评论

    相关推荐

    【NUCLEO-F412ZG试用体验】ARM的FFT使用及误差分析

    的数字信号,就可以做FFT变换了。N个采样点数据,在经过FFT之后,就可以得到N个点的FFT结果。对于快速FFT算法,有
    发表于 12-16 20:31

    modelsim 仿真fft

    modelsim 仿真fft ,自己用Verilog写的程序,我给一个正弦波,发现仿真后的结果是四个尖峰,按道理说应该是两个尖峰相互对称,我是512点的。为什么中间多出两个尖峰,不知道
    发表于 01-20 08:53

    一种基于FPGA的可配置FFT IP核实现设计

    摘要针对FFT算法基于FPGA实现可配置的IP核。采用基于流水线结构和快速并行算法实现了蝶形运算和4k点FFT的输入点数、数据位宽、分解
    发表于 07-03 07:56

    Verilog代码书写规范

    Verilog代码书写规范 本规范的目的是提高书写代码的可读性、可修改性、可重用性,优化代码综合和仿真的结果,指导设计工程师使用
    发表于 04-15 09:47 106次下载

    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代码覆盖率检查

    Verilog代码覆盖率检查是检查验证工作是否完全的重要方法,代码覆盖率(codecoverge)可以指示Verilog代码描述的功能有多少
    发表于 04-29 12:35 7943次阅读

    八选一多路选择器Verilog代码仿真结果MUX_8

    八选一多路选择器 Verilog代码仿真结果(modelsim仿真
    发表于 03-28 15:27 32次下载

    快速傅里叶变换FFT的C程序代码实现

    本文为您讲解快速傅里叶变换FFT的C语言程序代码实现的具体方法,C编程需要解决的问题及FFT计算结果验证。
    发表于 10-08 16:38 6w次阅读
    快速傅里叶变换<b class='flag-5'>FFT</b>的C程序<b class='flag-5'>代码</b><b class='flag-5'>实现</b>

    浮点型算法的加、减、乘、除的verilog代码

    描述了浮点型算法的加、减、乘、除的verilog代码,编写了6位指数位,20位小数位的功能实现并且通过仿真验证
    发表于 01-16 14:15 1次下载

    Vivado:ROM和RAM的verilog代码实现

    本文主要介绍ROM和RAM实现verilog代码版本,可以借鉴参考下。
    的头像 发表于 05-16 16:57 926次阅读

    2FFT的算法推导及python仿真

    FFT的算法推导主要用到旋转因子的周期性、对称性和可约性。
    的头像 发表于 06-02 12:38 1168次阅读
    基<b class='flag-5'>2FFT</b>的算法推导及python<b class='flag-5'>仿真</b>

    Verilog代码封装后门访问

    关于仿真里的后门访问,之前的文章《三分钟教会你SpinalHDL仿真中的后门读写》中有做过介绍,其针对的都是针对以SpinalHDL中的代码进行的后门访问。今天来看看当封装了Verilog
    的头像 发表于 07-15 10:22 510次阅读
    <b class='flag-5'>Verilog</b><b class='flag-5'>代码</b>封装后门访问