本文使用verilog实现25点基5FFT的代码。
根据算法推导,基5FFT的verilog代码整体结构为:
verilog代码实现首先进行5点FFT的实现,代码主要做:
O0=D0+D1+D2+D3+D4O1=(D0+D1*W15+D2*W25+D3*W35+D4*W45O2=(D0+D1*W25+D2*W45+D3*W15+D4*W35O3=(D0+D1*W35+D2*W15+D3*W45+D4*W25)O4=(D0+D1*W45+D2*W35+D3*W25+D4*W15)
代码内容如下,因为代码较长下面代码删除了数据和start信号的打拍,代码中S_data_add_real_p0/p1p2/p3/p4对应上边式子中的O0/O1/O2/O3/O4.
=========================================================== =File Name: cm_fft5_N5 VERSION : V1.0 DATA : 2023/1/1 Author : FPGA干货分享 =========================================================== =功能:基5FFT N=5的数据处理 delay : 11clk =========================================================== = 1ns/100ps module cm_fft5_N5 #( 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 reg [C_DATA_WITH+2:0] O_data_out_real , /// 数据输出,从start开始连续输出 output reg [C_DATA_WITH+2:0] O_data_out_imag /// 数据输出,从start开始连续输出); =========================================================== =内部参数 =========================================================== =W05=1 W15=0.30901699437494745-0.9510565162951535j W25=-0.8090169943749473-0.5877852522924732j W35=-0.8090169943749475+0.587785252292473j W45=0.30901699437494723+0.9510565162951536j W15 = (0.30901699437494745-0.9510565162951535j)*1024 = 316 - 974j W25 = (-0.8090169943749473-0.5877852522924732j)*1024 = -828- 602j W35 = (-0.8090169943749473+0.5877852522924732j)*1024 = -828+ 602j W45 = (0.30901699437494745+0.9510565162951535j)*1024 = 316 + 974j always @(posedge I_sys_clk) if(S_data_start_d5) begin S_data_add_real_p0 <= {{3{S_data_in_real_d5[C_DATA_WITH-1]}},S_data_in_real_d5}; S_data_add_imag_p0 <= {{3{S_data_in_imag_d5[C_DATA_WITH-1]}},S_data_in_imag_d5}; end else begin S_data_add_real_p0 <= S_data_add_real_p0 + {{3{S_data_in_real_d5[C_DATA_WITH-1]}},S_data_in_real_d5}; S_data_add_imag_p0 <= S_data_add_imag_p0 + {{3{S_data_in_imag_d5[C_DATA_WITH-1]}},S_data_in_imag_d5}; end W15 = 316 - 974j W25 = -828- 602j W35 = -828+ 602j W45 = 316 + 974j always @(*) if(S_data_start_d1) begin S_Wn5_real_p1 = 12'd316 ; S_Wn5_imag_p1 = -12'd974 ; end else if(S_data_start_d2) begin S_Wn5_real_p1 = -12'd828 ; S_Wn5_imag_p1 = -12'd602 ; end else if(S_data_start_d3) begin S_Wn5_real_p1 = -12'd828 ; S_Wn5_imag_p1 = 12'd602 ; end else begin S_Wn5_real_p1 = 12'd316 ; S_Wn5_imag_p1 = 12'd974 ; end 调用复乘 delay 6clk cmult # (.AWIDTH (C_DATA_WITH ) , (12 ) ) u0_cmult_p1 ( (I_sys_clk ) , (I_data_in_real ) , (I_data_in_imag ) , (S_Wn5_real_p1 ) , (S_Wn5_imag_p1 ) , (S_data_multp1_real ) , (S_data_multp1_imag ) ); always @(posedge I_sys_clk) if(S_data_start_d6) begin S_data_add_real_p1 <= {{3{S_data_in_real_d6[C_DATA_WITH-1]}},S_data_in_real_d6}; S_data_add_imag_p1 <= {{3{S_data_in_imag_d6[C_DATA_WITH-1]}},S_data_in_imag_d6}; end else begin S_data_add_real_p1 <= S_data_add_real_p1 + S_data_multp1_real[(C_DATA_WITH+12):10] + S_data_multp1_real[9]; S_data_add_imag_p1 <= S_data_add_imag_p1 + S_data_multp1_imag[(C_DATA_WITH+12):10] + S_data_multp1_imag[9]; end W25 = -828- 602j W45 = 316 + 974j W15 = 316 - 974j W35 = -828+ 602j always @(*) if(S_data_start_d2) begin S_Wn5_real_p2 = -12'd828 ; S_Wn5_imag_p2 = -12'd602 ; end else if(S_data_start_d3) begin S_Wn5_real_p2 = 12'd316 ; S_Wn5_imag_p2 = 12'd974 ; end else if(S_data_start_d4) begin S_Wn5_real_p2 = 12'd316 ; S_Wn5_imag_p2 = -12'd974 ; end else begin S_Wn5_real_p2 = -12'd828 ; S_Wn5_imag_p2 = 12'd602 ; end 调用复乘 delay 6clk cmult # (.AWIDTH (C_DATA_WITH ) , (12 ) ) u0_cmult_p2 ( (I_sys_clk ) , (S_data_in_real_d1 ) , (S_data_in_imag_d1 ) , (S_Wn5_real_p2 ) , (S_Wn5_imag_p2 ) , (S_data_multp2_real ) , (S_data_multp2_imag ) ); always @(posedge I_sys_clk) if(S_data_start_d7) begin S_data_add_real_p2 <= {{3{S_data_in_real_d7[C_DATA_WITH-1]}},S_data_in_real_d7}; S_data_add_imag_p2 <= {{3{S_data_in_imag_d7[C_DATA_WITH-1]}},S_data_in_imag_d7}; end else begin S_data_add_real_p2 <= S_data_add_real_p2 + S_data_multp2_real[(C_DATA_WITH+12):10] + S_data_multp2_real[9]; S_data_add_imag_p2 <= S_data_add_imag_p2 + S_data_multp2_imag[(C_DATA_WITH+12):10] + S_data_multp2_imag[9]; end W35 = -828+ 602j W15 = 316 - 974j W45 = 316 + 974j W25 = -828- 602j always @(*) if(S_data_start_d3) begin S_Wn5_real_p3 = -12'd828 ; S_Wn5_imag_p3 = 12'd602 ; end else if(S_data_start_d4) begin S_Wn5_real_p3 = 12'd316 ; S_Wn5_imag_p3 = -12'd974 ; end else if(S_data_start_d5) begin S_Wn5_real_p3 = 12'd316 ; S_Wn5_imag_p3 = 12'd974 ; end else begin S_Wn5_real_p3 = -12'd828 ; S_Wn5_imag_p3 = -12'd602 ; end 调用复乘 delay 6clk cmult # (.AWIDTH (C_DATA_WITH ) , (12 ) ) u0_cmult_p3 ( (I_sys_clk ) , (S_data_in_real_d2 ) , (S_data_in_imag_d2 ) , (S_Wn5_real_p3 ) , (S_Wn5_imag_p3 ) , (S_data_multp3_real ) , (S_data_multp3_imag ) ); always @(posedge I_sys_clk) if(S_data_start_d8) begin S_data_add_real_p3 <= {{3{S_data_in_real_d8[C_DATA_WITH-1]}},S_data_in_real_d8}; S_data_add_imag_p3 <= {{3{S_data_in_imag_d8[C_DATA_WITH-1]}},S_data_in_imag_d8}; end else begin S_data_add_real_p3 <= S_data_add_real_p3 + S_data_multp3_real[(C_DATA_WITH+12):10] + S_data_multp3_real[9]; S_data_add_imag_p3 <= S_data_add_imag_p3 + S_data_multp3_imag[(C_DATA_WITH+12):10] + S_data_multp3_imag[9]; end W45 = 316 + 974j W35 = -828+ 602j W25 = -828- 602j W15 = 316 - 974j always @(*) if(S_data_start_d4) begin S_Wn5_real_p4 = 12'd316 ; S_Wn5_imag_p4 = 12'd974 ; end else if(S_data_start_d5) begin S_Wn5_real_p4 = -12'd828 ; S_Wn5_imag_p4 = 12'd602 ; end else if(S_data_start_d6) begin S_Wn5_real_p4 = -12'd828 ; S_Wn5_imag_p4 = -12'd602 ; end else if(S_data_start_d7) begin S_Wn5_real_p4 = 12'd316 ; S_Wn5_imag_p4 = -12'd974 ; end 调用复乘 delay 6clk cmult # (.AWIDTH (C_DATA_WITH ) , (12 ) ) u0_cmult_p4 ( (I_sys_clk ) , (S_data_in_real_d3 ) , (S_data_in_imag_d3 ) , (S_Wn5_real_p4 ) , (S_Wn5_imag_p4 ) , (S_data_multp4_real ) , (S_data_multp4_imag ) ); always @(posedge I_sys_clk) if(S_data_start_d9) begin S_data_add_real_p4 <= {{3{S_data_in_real_d9[C_DATA_WITH-1]}},S_data_in_real_d9}; S_data_add_imag_p4 <= {{3{S_data_in_imag_d9[C_DATA_WITH-1]}},S_data_in_imag_d9}; end else begin S_data_add_real_p4 <= S_data_add_real_p4 + S_data_multp4_real[(C_DATA_WITH+12):10] + S_data_multp4_real[9]; S_data_add_imag_p4 <= S_data_add_imag_p4 + S_data_multp4_imag[(C_DATA_WITH+12):10] + S_data_multp4_imag[9]; end always @(posedge I_sys_clk) if(S_data_start_d10) begin O_data_out_real <= S_data_add_real_p0 ; O_data_out_imag <= S_data_add_imag_p0 ; end else if(S_data_start_d11) begin O_data_out_real <= S_data_add_real_p1 ; O_data_out_imag <= S_data_add_imag_p1 ; end else if(S_data_start_d12) begin O_data_out_real <= S_data_add_real_p2 ; O_data_out_imag <= S_data_add_imag_p2 ; end else if(S_data_start_d13) begin O_data_out_real <= S_data_add_real_p3 ; O_data_out_imag <= S_data_add_imag_p3 ; end else if(S_data_start_d14) begin O_data_out_real <= S_data_add_real_p4 ; O_data_out_imag <= S_data_add_imag_p4 ; end else begin O_data_out_real <= 'd0 ; O_data_out_imag <= 'd0 ; end assign O_data_start = S_data_start_d11 ; endmodule
随后进行25点FFT代码的实现,代码主要计算
代码如下,显然25点的FFT要缓存的数据量是非常大的,使用功打拍的方法是不合适的,这里使用分布式ram建立缓存空间,直接使用功5块ram缓存相应的数据:
// ============================================================// File Name: cm_fft5_N25// VERSION : V1.0// DATA : 2023/2/20// Author : FPGA干货分享// ============================================================// 功能:基5FFT N=25的数据处理// delay : 42clk// ============================================================ `timescale 1ns/100psmodule cm_fft5_N25 #( parameter C_DATA_WIDTH = 16 )( 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 reg O_data_start , /// 数据开始输出标志与第一个数据对齐输出 output wire [C_DATA_WIDTH+5:0] O_data_out_real , /// 数据输出,从start开始连续输出 output wire [C_DATA_WIDTH+5:0] O_data_out_imag /// 数据输出,从start开始连续输出); // ============================================================// 内部参数// ============================================================/// W05=1/// W15=0.30901699437494745-0.9510565162951535j /// W25=-0.8090169943749473-0.5877852522924732j /// W35=-0.8090169943749475+0.587785252292473j /// W45=0.30901699437494723+0.9510565162951536j /// W15 = (0.30901699437494745-0.9510565162951535j)*1024 = 316 - 974j/// W25 = (-0.8090169943749473-0.5877852522924732j)*1024 = -828- 602j/// W35 = (-0.8090169943749473+0.5877852522924732j)*1024 = -828+ 602j/// W45 = (0.30901699437494745+0.9510565162951535j)*1024 = 316 + 974j// ============================================================// 变量// ============================================================reg [2:0] S_data_cnt5 ;reg [2:0] S_cnt5_rd ;reg [4:0] S_wr_en ;reg [C_DATA_WIDTH*2-1:0] S_data_in ;reg S_pingpang_flag ;reg [3:0] S_rd_addr ;wire [C_DATA_WIDTH-1:0] S_ram_out_i[4:0] ;wire [C_DATA_WIDTH-1:0] S_ram_out_q[4:0] ;reg [11:0] S_Wn5_real[4:1] ;reg [11:0] S_Wn5_imag[4:1] ;wire [C_DATA_WIDTH+12:0] S_data_multp_real[4:1] ;wire [C_DATA_WIDTH+12:0] S_data_multp_imag[4:1] ;reg [C_DATA_WIDTH-1:0] S_ram_out_i0_d ;reg [C_DATA_WIDTH-1:0] S_ram_out_q0_d ; reg [C_DATA_WIDTH+2:0] S_data_add_real_p0 ; reg [C_DATA_WIDTH+2:0] S_data_add_imag_p0 ;reg [C_DATA_WIDTH+2:0] S_data_add_real_p0_d1 ; reg [C_DATA_WIDTH+2:0] S_data_add_imag_p0_d1 ;reg [C_DATA_WIDTH+2:0] S_data_add_real_p0_d2 ; reg [C_DATA_WIDTH+2:0] S_data_add_imag_p0_d2 ; reg [C_DATA_WIDTH+2:0] S_data_add_real_p2 ; reg [C_DATA_WIDTH+2:0] S_data_add_imag_p2 ; reg [4:0] s_data_w25_cnt ;reg [11:0] S_Wn25_real ;reg [11:0] S_Wn25_imag ;wire [C_DATA_WIDTH+15:0] S_data_multw25_real ;wire [C_DATA_WIDTH+15:0] S_data_multw25_imag ;reg [C_DATA_WIDTH+2:0] S_data_out_real ;reg [C_DATA_WIDTH+2:0] S_data_out_imag ;reg S_data_start_5 ;// ============================================================// 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) S_data_in <={I_data_in_real,I_data_in_imag} ; always @(posedge I_sys_clk) if(I_data_start) S_data_cnt5 <= 3'd0; else if(S_data_cnt5 == 3'd4) S_data_cnt5 <= 3'd0; else S_data_cnt5 <= S_data_cnt5 + 'd1; always @(posedge I_sys_clk) if(I_data_start) S_wr_en <= 5'b00001; else if(S_data_cnt5 == 3'd4) S_wr_en <= {S_wr_en[3:0],1'b0}; else S_wr_en <= S_wr_en ; genvar j;generate for (j=0;j<5;j=j+1) begin cm_dis_sdp_ram #( .C_DATA_WIDTH ( C_DATA_WIDTH*2 ) , // Specify RAM data width .C_ADDR_WIDTH ( 4 ) , // 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_data_cnt5} ) , // Write address bus, width determined from RAM_DEPTH .I_addrb (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[j] ) , // Write enable .O_doutb ({S_ram_out_i[j],S_ram_out_q[j]} ) // RAM output data ); if(j != 0) begin /// 调用复乘 delay 6clk cmult # (.AWIDTH (C_DATA_WIDTH ) , .BWIDTH (12 ) ) u0_cmult_p1 ( .clk (I_sys_clk ) , .ar (S_ram_out_i[j] ) , .ai (S_ram_out_q[j] ) , .br (S_Wn5_real[j] ) , .bi (S_Wn5_imag[j] ) , .pr (S_data_multp_real[j] ) , .pi (S_data_multp_imag[j] ) ); end endendgenerate always @(posedge I_sys_clk) if(S_wr_en[4]&(S_data_cnt5==0)) S_rd_addr[3] <= S_pingpang_flag; else S_rd_addr[3] <= S_rd_addr[3] ; always @(posedge I_sys_clk) if(S_wr_en[4]&(S_data_cnt5==0)) S_cnt5_rd <= 3'd0; else if((S_data_cnt5==0)) if(S_cnt5_rd == 3'd5) S_cnt5_rd <= S_cnt5_rd; else S_cnt5_rd <= S_cnt5_rd + 'd1; else S_cnt5_rd <= S_cnt5_rd ; always @(posedge I_sys_clk) if((S_data_cnt5==0)) S_rd_addr[2:0] <= 3'd0; else S_rd_addr[2:0] <= S_rd_addr[2:0] + 'd1; always @(posedge I_sys_clk) case(S_cnt5_rd) 3'd0: begin S_Wn5_real[1] <= 12'd316 ; S_Wn5_imag[1] <= -12'd974; S_Wn5_real[2] <= -12'd828 ; S_Wn5_imag[2] <= -12'd602 ; S_Wn5_real[3] <= -12'd828 ; S_Wn5_imag[3] <= 12'd602 ; S_Wn5_real[4] <= 12'd316 ; S_Wn5_imag[4] <= 12'd974; end 3'd1: begin S_Wn5_real[1] <= -12'd828 ; S_Wn5_imag[1] <= -12'd602 ; S_Wn5_real[2] <= 12'd316 ; S_Wn5_imag[2] <= 12'd974; S_Wn5_real[3] <= 12'd316 ; S_Wn5_imag[3] <= -12'd974; S_Wn5_real[4] <= -12'd828 ; S_Wn5_imag[4] <= 12'd602 ; end 3'd2: begin S_Wn5_real[1] <= -12'd828 ; S_Wn5_imag[1] <= 12'd602 ; S_Wn5_real[2] <= 12'd316 ; S_Wn5_imag[2] <= -12'd974; S_Wn5_real[3] <= 12'd316 ; S_Wn5_imag[3] <= 12'd974; S_Wn5_real[4] <= -12'd828 ; S_Wn5_imag[4] <= -12'd602 ; end default: begin S_Wn5_real[1] <= 12'd316 ; S_Wn5_imag[1] <= 12'd974; S_Wn5_real[2] <= -12'd828 ; S_Wn5_imag[2] <= 12'd602 ; S_Wn5_real[3] <= -12'd828 ; S_Wn5_imag[3] <= -12'd602 ; S_Wn5_real[4] <= 12'd316 ; S_Wn5_imag[4] <= -12'd974; end endcase always @(posedge I_sys_clk) begin S_data_add_real_p0 <= {{3{S_ram_out_i[0][C_DATA_WIDTH-1]}},S_ram_out_i[0]} + {{3{S_ram_out_i[1][C_DATA_WIDTH-1]}},S_ram_out_i[1]} + {{3{S_ram_out_i[2][C_DATA_WIDTH-1]}},S_ram_out_i[2]} + {{3{S_ram_out_i[3][C_DATA_WIDTH-1]}},S_ram_out_i[3]} + {{3{S_ram_out_i[4][C_DATA_WIDTH-1]}},S_ram_out_i[4]} ; S_data_add_imag_p0 <= {{3{S_ram_out_q[0][C_DATA_WIDTH-1]}},S_ram_out_q[0]} + {{3{S_ram_out_q[1][C_DATA_WIDTH-1]}},S_ram_out_q[1]} + {{3{S_ram_out_q[2][C_DATA_WIDTH-1]}},S_ram_out_q[2]} + {{3{S_ram_out_q[3][C_DATA_WIDTH-1]}},S_ram_out_q[3]} + {{3{S_ram_out_q[4][C_DATA_WIDTH-1]}},S_ram_out_q[4]} ; S_data_add_real_p0_d1 <= S_data_add_real_p0 ; S_data_add_imag_p0_d1 <= S_data_add_imag_p0 ; S_data_add_real_p0_d2 <= S_data_add_imag_p0_d1 ; S_data_add_imag_p0_d2 <= S_data_add_imag_p0_d1 ; end always @(posedge I_sys_clk) begin S_ram_out_i0_d <= S_ram_out_i[0] ; S_ram_out_q0_d <= S_ram_out_q[0] ; end always @(posedge I_sys_clk) begin S_data_add_real_p2 <= {{3{S_ram_out_i0_d[C_DATA_WIDTH-1]}},S_ram_out_i0_d} + S_data_multp_real[1][(C_DATA_WIDTH+12):10] + S_data_multp_real[1][9] + S_data_multp_real[2][(C_DATA_WIDTH+12):10] + S_data_multp_real[2][9] + S_data_multp_real[3][(C_DATA_WIDTH+12):10] + S_data_multp_real[3][9] + S_data_multp_real[4][(C_DATA_WIDTH+12):10] + S_data_multp_real[4][9] ; S_data_add_imag_p2 <= {{3{S_ram_out_q0_d[C_DATA_WIDTH-1]}},S_ram_out_q0_d} + S_data_multp_imag[1][(C_DATA_WIDTH+12):10] + S_data_multp_imag[1][9] + S_data_multp_imag[2][(C_DATA_WIDTH+12):10] + S_data_multp_imag[2][9] + S_data_multp_imag[3][(C_DATA_WIDTH+12):10] + S_data_multp_imag[3][9] + S_data_multp_imag[4][(C_DATA_WIDTH+12):10] + S_data_multp_imag[4][9] ; end always @(posedge I_sys_clk) if((S_rd_addr[2:0] == 3'd1)&(S_cnt5_rd==1)) s_data_w25_cnt <= 5'd0; else if(&s_data_w25_cnt) s_data_w25_cnt <= s_data_w25_cnt; else s_data_w25_cnt <= s_data_w25_cnt + 'd1 ; always @(posedge I_sys_clk) case(s_data_w25_cnt) 5'd0 : begin S_Wn25_real <= 12'd1024; S_Wn25_imag <= 12'd0 ; end /// W0 25 5'd1 : begin S_Wn25_real <= 12'd992 ; S_Wn25_imag <=-12'd255 ; end /// W1 25 5'd2 : begin S_Wn25_real <= 12'd897 ; S_Wn25_imag <=-12'd493 ; end /// W2 25 5'd3 : begin S_Wn25_real <= 12'd946 ; S_Wn25_imag <=-12'd701 ; end /// W3 25 5'd4 : begin S_Wn25_real <= 12'd549 ; S_Wn25_imag <=-12'd865 ; end /// W4 25 5'd5 : begin S_Wn25_real <= 12'd1024; S_Wn25_imag <= 12'd0 ; end /// W0 25 5'd6 : begin S_Wn25_real <= 12'd897 ; S_Wn25_imag <=-12'd493 ; end /// W2 25 5'd7 : begin S_Wn25_real <= 12'd549 ; S_Wn25_imag <=-12'd865 ; end /// W4 25 5'd8 : begin S_Wn25_real <= 12'd64 ; S_Wn25_imag <=-12'd1022; end /// W6 25 5'd9 : begin S_Wn25_real <=-12'd436 ; S_Wn25_imag <=-12'd927 ; end /// W8 25 5'd10 : begin S_Wn25_real <= 12'd1024; S_Wn25_imag <= 12'd0 ; end /// W0 25 5'd11 : begin S_Wn25_real <= 12'd746 ; S_Wn25_imag <=-12'd701 ; end /// W3 25 5'd12 : begin S_Wn25_real <= 12'd64 ; S_Wn25_imag <=-12'd1022; end /// W6 25 5'd13 : begin S_Wn25_real <=-12'd653 ; S_Wn25_imag <=-12'd789 ; end /// W9 25 5'd14 : begin S_Wn25_real <=-12'd1016; S_Wn25_imag <=-12'd128 ; end /// W12 25 5'd15 : begin S_Wn25_real <= 12'd1024; S_Wn25_imag <= 12'd0 ; end /// W0 25 5'd16 : begin S_Wn25_real <= 12'd549 ; S_Wn25_imag <=-12'd865 ; end /// W4 25 5'd17 : begin S_Wn25_real <=-12'd436 ; S_Wn25_imag <=-12'd927 ; end /// W8 25 5'd18 : begin S_Wn25_real <=-12'd1016; S_Wn25_imag <=-12'd128 ; end /// W12 25 5'd19 : begin S_Wn25_real <=-12'd653 ; S_Wn25_imag <= 12'd786 ; end /// W16 25 default:begin S_Wn25_real <= 12'd1024; S_Wn25_imag <= 12'd0 ; end /// W0 25 endcase /// 调用复乘 delay 6clkcmult # (.AWIDTH (C_DATA_WIDTH+3 ) , .BWIDTH (12 ) )u1_cmult_ ( .clk (I_sys_clk ) , .ar (S_data_add_real_p2 ) , .ai (S_data_add_imag_p2 ) , .br (S_Wn25_real ) , .bi (S_Wn25_imag ) , .pr (S_data_multw25_real ) , .pi (S_data_multw25_imag ) ); always @(posedge I_sys_clk) if((s_data_w25_cnt > 5'd1) &&(s_data_w25_cnt < 5'd7)) begin S_data_out_real <= S_data_add_real_p0_d2 ; S_data_out_imag <= S_data_add_imag_p0_d2 ; end else begin S_data_out_real <= S_data_multw25_real[(C_DATA_WIDTH+12):10] + S_data_multw25_real[9]; S_data_out_imag <= S_data_multw25_imag[(C_DATA_WIDTH+12):10] + S_data_multw25_imag[9]; end always @(posedge I_sys_clk) S_data_start_5 <= (s_data_w25_cnt == 2) || (s_data_w25_cnt == 7) || (s_data_w25_cnt == 12) || (s_data_w25_cnt == 17) || (s_data_w25_cnt == 22) ; ///delay clkcm_fft5_N5 #( .C_DATA_WITH (C_DATA_WIDTH+3 ) )u0_cm_fft5_N5( .I_sys_clk (I_sys_clk ) , /// 工作时钟 100M .I_data_start (S_data_start_5 ) , /// 数据开始进入标志,与第一个数据对齐输入 .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开始连续输出); always @(posedge I_sys_clk) O_data_start <= (s_data_w25_cnt == 13) ; endmodule
最后是5点FFT的倒序,输出倒序模块主要是用来实现下图中的地址转换,代码使用分布式RAM的乒乓操作,缓存两组数据信息,然后使用计数器的bit翻转达到输出倒序的目的,倒序代码和基3fft的倒序代码进本一样,这里就不再展示代码了(参考基3FFT的verilog代码实现及仿真)。
仿真TB和基2FFT(基2FFT的verilog代码实现及仿真)实现中的仿真类似同样使用python生成激励源和结果与verilog的结果做对比,得到最终输出。