基2FFT的verilog代码实现及仿真

描述

上文基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

输入信号:

代码

输出信号:

代码

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分