Vivado FFT和IFFT的仿真验证

目录

1、FFT IP核简介

2、数据流程

3、顶层模块代码       

 3.2 异步FIFO配置

4、FFT和IFF处理模块

4.1 FFT配置界面

4.2  IFFT配置界面

4.3  SYNC_FIFO配置界面

5、仿真

5.1、testbench代码

5.2 仿真波形 

5.2.1 输入波形连续


1、FFT IP核简介

        Vivado FFT IP核是Xilinx公司推出的针对FPGA设备的快速傅里叶变换专用IP核。它提供了一个高效的硬件解决方案来执行频域分析,广泛应用于数字信号处理领域,如无线通信、雷达系统和音频处理等。通过利用FPGA的并行处理能力,FFT IP核能够处理高速数据流,实现低延迟和高吞吐量的信号变换。它不仅可以用于正向FFT转换,还可以通过逆FFT支持频域信号的重构,本文对FFT和IFFT进行配置仿真验证。

2、数据流程

        ADC 采样数据首先通过一个异步跨时钟域 FIFO 进行缓冲。该 FIFO 的写时钟(100 MHz)与 ADC 采样率匹配,读时钟(300 MHz)或者工作在更高频率以确保数据的高速稳定输出。我们通过控制读、写使能信号,维持 FIFO 在一个动态平衡中,合理深度(即不能写满和读空)的前提下精确管理数据的读、写速率。

        从 FIFO 高速读出的数据流被依次送入 FFT IP 核进行处理。鉴于 FFT IP 核本身存在固有的处理延迟,为了确保经过整个处理流程(包括 FFT 和后续的 IFFT)后的数据连续性,选定的 FFT 变换长度(512点)需要小于 IFFT 变换的长度(1024点),最后通过同步FIFO将数据输出。整体流程如下图所示。

3、顶层模块代码       

        顶层模块主要实现数据的跨时钟的处理,实现fifo的动态平衡。

`timescale 1 ns / 10ps
// 
module adc_iq_cail
#(		BIT_NUM							= 24
)(
    input                                          SYS_CLK                        , // (input )
    input                                          SYS_RSTN                       , // (input )
    input                         [BIT_NUM-1'b1:0] I_DATA_IN                      , // (input )
    input                         [BIT_NUM-1'b1:0] Q_DATA_IN                      , // (input )
    input                                          DATA_IN_VALID                  , // (input )

    output                        [BIT_NUM-1'b1:0] I_DATA_OUT                     , // (output)
    output                        [BIT_NUM-1'b1:0] Q_DATA_OUT                     , // (output)
    output                                         DATA_OUT_VALID                 // (output)         
);
localparam                                    FFT_LEN = 512                        ;
reg                                           locrstn,locrstn_buf                  ; 
//=================================================================================/
// fifo
//=================================================================================/
wire                                          fifo_rd_en                           ; 
wire                                 [47 : 0] fifo_dout                            ; 
wire                                          fifo_full                            ; 
wire                                          fifo_empty                           ; 
wire                                          fifo_valid                           ; 
wire                                          fifo_wr_rst_busy                     ; 
wire                                          fifo_rd_rst_busy                     ;
reg                                    [15:0] fifo_read_cunt                       ; 
reg                                    [15:0] data_cunt                            ;
wire                                   [12:0] wr_data_count                	   	   ;
//=================================================================================/
// FFT
//=================================================================================/
reg                                    [15:0] tlast_cnt                            ; 
wire                                          fft_tlast_path                       ; 
wire                                   [47:0] fft_data_tdata                       ; 
wire                                          fft_tvalid_path                      ; 
wire                                          fft_tready_path                      ; 
wire                                   	      m_axis_data_tvalid                   ; 
wire                                   [47:0] m_dds_tdata                          ; 
//=================================================================================/
// 状态机
//=================================================================================/
reg                                    [2:0]  fifo_read_state             	   	   ;
reg                                    [2:0]  fifo_next__state             	   	   ;

parameter      							      FIFO_READ_IDLE   =  'd0 			   ;
parameter      							      FIFO_READ_WAIT   =  'd1 			   ;
parameter      							      FIFO_READ        =  'd2 			   ;
parameter      							      FIFO_READ_DONE   =  'd3 			   ;

	always@(posedge clk_300m or negedge locked)begin
		if(locked == 1'b0)begin
			locrstn_buf		<= 1'b0;
			locrstn			<= 1'b0;
		end else begin
			locrstn_buf		<= 1'b1;
			locrstn			<= locrstn_buf;
		end
	end

//=================================================================================/
// 生成仿真数据
//=================================================================================/

	dds_compiler_0 dds_compiler_1m (
		.aclk                             (clk_100m                             ), // input wire aclk
		.s_axis_phase_tvalid              (1'b1                                 ), // input wire s_axis_phase_tvalid
		.s_axis_phase_tdata               (16'd655                              ), // input wire [15 : 0] s_axis_phase_tdata
		.m_axis_data_tvalid               (m_axis_data_tvalid                   ), // output wire m_axis_data_tvalid
		.m_axis_data_tdata                (m_dds_tdata                      	)  // output wire [47 : 0] m_axis_data_tdata
	);
//=================================================================================/
// 状态机 控制FIFO数据流
//=================================================================================/
	always @(posedge clk_300m or posedge locrstn) begin
		if( locrstn ==1'b0)
			fifo_read_state <= FIFO_READ_IDLE;
		else
			fifo_read_state <= fifo_next__state;
	end

//     always @(*) begin
        always @(posedge clk_300m or posedge locrstn) begin
                case (fifo_read_state)
                    FIFO_READ_IDLE             :    fifo_next__state = FIFO_READ_WAIT;

                    // FIFO_READ_WAIT             :    fifo_next__state = (wr_data_count>=1100)&&(data_cunt<=5) ? FIFO_READ : FIFO_READ_WAIT;
            		FIFO_READ_WAIT             :    fifo_next__state = ((fft_tready_path==1'b1)&&(wr_data_count>1100)) ? FIFO_READ : FIFO_READ_WAIT;

                    FIFO_READ                  :    fifo_next__state = fft_tlast_path ? FIFO_READ_DONE : FIFO_READ;

                    FIFO_READ_DONE             :    fifo_next__state = FIFO_READ_IDLE;

                    default		       		   :    fifo_next__state = FIFO_READ_IDLE;
                endcase
        end

	always@(posedge clk_300m or negedge locrstn)begin
		if(locrstn==1'b0)
			data_cunt<='d0;
		else if(data_cunt==30)
			data_cunt<=data_cunt;       			                
		else if(fft_tlast_path)begin
			data_cunt<=data_cunt+1'b1; 
		end     
		else
			data_cunt<=data_cunt;
	end
//=================================================================================/
//----------------------------------------FIFO模块---------------------------------
//=================================================================================/
	fifo_ddc2fft_48bit u_fifo_ddc2fft_48bit (
		.wr_clk                           (clk_100m                                   ), // input wire wr_clk
		.rd_clk                           (clk_300m                                   ), // input wire rd_clk	
		.din                              (m_dds_tdata                      	      ), // input wire [47 : 0] din
		.wr_en                            (m_axis_data_tvalid                         ), // input wire wr_en
		.rd_en                            (fifo_rd_en                                 ), // input wire rd_en
		.dout                             (fifo_dout                                  ), // output wire [47 : 0] dout
		.full                             (fifo_full                                  ), // output wire full
		.empty                            (fifo_empty                                 ), // output wire empty
		.valid                            (fifo_valid                                 ), // output wire valid
		.wr_data_count			  		  (wr_data_count    			      		  )  // output wire [12 : 0] wr_data_count	

	);

//=================================================================================/
// 产生FIFO读使能信号fifo_rd_en,在FFT核准备好且FIFO非空时
//=================================================================================/
	always@(posedge clk_300m or negedge locrstn) begin
		if(locrstn==1'b0)
			fifo_read_cunt<='d0;
		else if(fifo_read_state == FIFO_READ)begin
			fifo_read_cunt<=fifo_read_cunt+1'b1; 
		end     
		else
			fifo_read_cunt<='d0;		
	end	
//=================================================================================/
//用于产生FFT模块每帧输入最后(第1024个数据)一个数据的控制信息s_axis_data_tlast
//=================================================================================/
	always@(posedge clk_300m or negedge locrstn) begin
		if(locrstn==1'b0)
			tlast_cnt<='d0;
		else if((tlast_cnt==FFT_LEN-1)&&(fifo_valid==1'b1)||(fifo_read_state != FIFO_READ))
			tlast_cnt<='d0;        
		else if(fifo_valid==1'b1)
			tlast_cnt<=tlast_cnt+1'b1;
	end	
	
assign fifo_rd_en = (fft_tready_path==1'b1) && (1<=fifo_read_cunt)&& (fifo_read_cunt<=FFT_LEN)&& (fifo_empty==1'b0)?  1'b1 : 1'b0;
// assign fifo_rd_en = (1<=fifo_read_cunt)&& (fifo_read_cunt<FFT_LEN+1)&& (fifo_empty==1'b0)?  1'b1 : 1'b0;
//-----------------------------------------FFT模块----------------------------------------------
//=================================================================================/
//输入的正弦信号为实信号放在实部
//=================================================================================/
	assign fft_data_tdata   = fifo_dout;
	assign fft_tvalid_path  = fifo_valid;
	assign fft_tlast_path 	= ((tlast_cnt==FFT_LEN-1)&&(fifo_valid)) ? 1'b1 : 1'b0;

	cail_fft_ifft #(
		.BIT_NUM                          ( 24                                       )  //BIT_NUM
	)u_cail_fft_ifft
	(
		.SYS_CLK                          (clk_300m                                	 ), // (input ) (input ) 
		.SYS_RSTN                         (locrstn                                   ), // (input ) (input ) 
	
		.fft_data_tdata                   (fft_data_tdata                            ), // (input ) (input )   
		.fft_tvalid_path                  (fft_tvalid_path                           ), // (input ) (input ) 
		.fft_tlast_path                   (fft_tlast_path                            ), // (input ) (input ) 

		.fft_tready_path                  (fft_tready_path                           ), // (output ) (output ) 
		.I_DATA_OUT                       (				                             ), // (output) (output)
		.Q_DATA_OUT                       (				                             ), // (output) (output)
		.DATA_OUT_VALID                   (				                             ) // (output) (output)       
	);

endmodule

 3.2 异步FIFO配置

        

4、FFT和IFF处理模块

// +FHDR============================================================================/
// Author       : 
// Creat Time   : 2024/09/23 14:07:27
// File Name    : cail_fft_ifft.v
// Module Ver   : V1.0
//
// CopyRight(c) 2024, UNI_T 
// All Rights Reserved
//
// ---------------------------------------------------------------------------------/
//
//                                              ------------------------------       
//                                              |                            |       
//                                              |       -^-        -^-       |       
//                                              |                            |       
//                                              |            -<>-            |       
//                                              |                            |       
//                                              ------------------------------       
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//                                                                                   
//
// Modification History:
// V1.0         initial
//
// -FHDR============================================================================/
// 
// 
// 
// 
`timescale 1 ns / 10ps
// 
module cail_fft_ifft
#(	parameter 	BIT_NUM							= 32
)(
    input                                          pcie_user_clk                  , // (input ) 
    input                                          pcie_user_rst_n                , // (input ) 
    input                                          SYS_CLK                        , // (input ) 
    input                                          SYS_RSTN                       , // (input ) 
    input                                          caild_en                       , // (input ) 

    input                                   	   fft_cail_init_flag             , // (input )   
    input                                   [31:0] fft_cail_init_data             , // (input ) 
    input                                          fft_cail_init_en               , // (input ) 

    (*mark_debug = "true"*)input                     [BIT_NUM*2-1'b1 : 0] fft_data_tdata                 , // (input )   
    (*mark_debug = "true"*)input                                          fft_tvalid_path                , // (input ) 
    (*mark_debug = "true"*)input                                          fft_tlast_path                 , // (input ) 

    (*mark_debug = "true"*)output                                         fft_tready_path                , // (output)
    (*mark_debug = "true"*)output                        			[31:0] I_DATA_OUT                     , // (output)
    (*mark_debug = "true"*)output                        			[31:0] Q_DATA_OUT                     , // (output)
    (*mark_debug = "true"*)output 	                                       DATA_OUT_VALID                 // (output)         

);
//=================================================================================/
// REST
//=================================================================================/
reg                                           rstn_buf,rstn                        ; 
reg                                           fft_rst                              ; 

//=================================================================================/
// FFT CONFIG 
//=================================================================================/
reg                                     [1:0] fft_ip_state                         ; 
reg                                    [15:0] fft_config_dat                       ; 
reg                                    [15:0] ifft_config_dat                      ; 
reg                                           fft_config_tvalid                    ; 
wire                                          fft_config_tdy_path                  ; 
wire                                          ifft_config_tdy_path                 ; 
//=================================================================================/
// FFT DATA 
//=================================================================================/
wire                     [BIT_NUM*2-1'b1 : 0] fft_m_axis_data_tdata                ; 
// wire                     [79 : 0] fft_m_axis_data_tdata                ; 
wire                                 [15 : 0] fft_m_axis_data_tuser                ; 
wire                                          fft_m_axis_data_tvalid               ; 
wire                                          fft_m_axis_data_tlast                ; 
//=================================================================================/
// IFFT DATA 
//=================================================================================/
wire                     [BIT_NUM*2-1'b1 : 0] ifft_m_axis_data_tdata               ; 
// wire                                 [95 : 0] ifft_m_axis_data_tdata               ; 
wire                                 [15 : 0] ifft_m_axis_data_tuser               ; 
wire                                          ifft_m_axis_data_tvalid              ; 
wire                                          ifft_m_axis_data_tlast               ; 
wire                                          ifft_tready_path                     ; 

reg                  	[BIT_NUM*2-1'b1 : 0]  m_axis_data                          ; 
// reg                  	 [79 : 0]  m_axis_data                          ; 
reg                                           m_axis_tlast                         ; 
reg                                           m_axis_tvalid                        ; 
//=================================================================================/
// CAIL DATA 
//=================================================================================/
wire                                [31 : 0]  fft_cail_dout                  	   ; 
reg                      [BIT_NUM + 'd15 : 0] FFT_DATA_I                           ; 
reg                      [BIT_NUM + 'd15 : 0] FFT_DATA_Q                           ; 
reg                                           FFT_DATA_VLD                         ; 
reg                                           FFT_DATA_LAST                        ; 
//=================================================================================/
//DATA  截位 
//=================================================================================/
wire                                          fft_data_cbit_i               	  ; 
wire                                          fft_data_cbit_q               	  ; 
wire                                 [31 : 0] fft_data_round_i               	  ; 
wire                                 [31 : 0] fft_data_round_q               	  ;

wire                                          ifft_data_cbit_i               	  ; 
wire                                          ifft_data_cbit_q               	  ; 
wire                                 [23 : 0] ifft_data_round_i               	  ; 
wire                                 [23 : 0] ifft_data_round_q               	  ; 

wire                                        [7 : 0] ifft_m_axis_status_tdata             ; 
wire                                                ifft_m_axis_status_tvalid            ; 
wire                                                ifft_m_axis_status_tready            ; 
reg                                         [7 : 0] ifftdat_delay                        ; 
reg                                                 ifftdat_vlid                         ; 

always@(posedge	SYS_CLK or negedge SYS_RSTN)
begin
	if(SYS_RSTN == 1'b0)begin
		rstn_buf	<= 1'b0;	
		rstn		<= 1'b0;
	end else begin
		rstn_buf	<= 1'b1;	
		rstn		<= rstn_buf;
	end
end

always@(posedge	SYS_CLK or negedge rstn)
begin
	if(rstn	== 1'b0)begin  
		fft_rst					<= 1'b0;
		fft_ip_state			<= 2'd0;
		fft_config_tvalid		<= 1'b0;
		fft_config_dat			<= {7'd0,1'b1,3'b000,5'b01001};	
		ifft_config_dat			<= {7'd0,1'b0,3'b000,5'b01001};			
	end 
	else begin		
		case(fft_ip_state)
		2'd0:begin	
				fft_rst				<= 1'b1;
				fft_ip_state		<= 2'd1;					
			 end
		2'd1:begin
				fft_ip_state		<= 2'd2;
				fft_config_dat		<= {7'd0,1'b1,3'b000,5'b01001};	
				ifft_config_dat		<= {7'd0,1'b0,3'b000,5'b01001};	
				fft_config_tvalid	<= 1'b1;
			 end
		2'd2:begin	
				if(fft_config_tdy_path==1'b1)
					begin
						fft_config_tvalid	<= 1'b0;
						fft_ip_state		<= 2'd3;
					end
				 else;						
			 end
		2'd3:begin
				fft_ip_state		<= 2'd3;
			end
		default:fft_ip_state		<= 2'd0;
		endcase			
	end
end	

//生成FFT的IP模块
fft_cail	u_fft_cail (                       
    .aclk                                          ( SYS_CLK                             ), // input wire aclk                                  
    .aresetn                                       ( fft_rst                             ), // input wire aresetn                                  
// .s_axis_config_tdata              ( fft_config_dat                            ), // input wire [15 : 0] s_axis_config_tdata          
    .s_axis_config_tdata                           ( 8'd1                                ), // input wire [15 : 0] s_axis_config_tdata          
    .s_axis_config_tvalid                          ( fft_config_tvalid                   ), // input wire s_axis_config_tvalid        
    .s_axis_config_tready                          ( fft_config_tdy_path                 ), // output wire s_axis_config_tready       

    .s_axis_data_tdata                             ( fft_data_tdata                      ), // input wire [47 : 0] s_axis_data_tdata     
    .s_axis_data_tvalid                            ( fft_tvalid_path                     ), // input wire s_axis_data_tvalid            
    .s_axis_data_tready                            ( fft_tready_path                     ), // output wire s_axis_data_tready                              
    .s_axis_data_tlast                             ( fft_tlast_path                      ), // input wire s_axis_data_tlast  

    .m_axis_data_tdata                             ( fft_m_axis_data_tdata               ), // output wire [47 : 0] m_axis_data_tdata 
    .m_axis_data_tuser                             (                                     ), // output wire [7 : 0] m_axis_data_tuser
    // .m_axis_data_tready                            ( 1'b1                                ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready    
    .m_axis_data_tready                            ( ifftdat_vlid                        ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready    
    .m_axis_data_tvalid                            ( fft_m_axis_data_tvalid              ), // output wire m_axis_data_tvalid                     
    .m_axis_data_tlast                             ( fft_m_axis_data_tlast               ), // output wire m_axis_data_tlast 

    .m_axis_status_tdata                           (                                     ), // output wire [7 : 0] m_axis_status_tdata
    .m_axis_status_tvalid                          (                                     ), // output wire m_axis_status_tvalid
    .m_axis_status_tready                          ( 1'b1                                ), // input wire m_axis_status_tready

    .event_frame_started                           (                                     ), // output wire event_frame_started    
    .event_tlast_unexpected                        (                                     ), // output wire event_tlast_unexpected 
    .event_tlast_missing                           (                                     ), // output wire event_tlast_missing    
    .event_data_in_channel_halt                    (                                     ), // output wire event_data_in_channel_halt
    .event_status_channel_halt                     (                                     ), // output wire event_status_channel_halt
    .event_data_out_channel_halt                   (                                     )  // output wire event_data_out_channel_halt
  );

always@(posedge	SYS_CLK or negedge rstn)
begin
	if(rstn	== 1'b0)begin
		m_axis_data		<= 'd0;
		m_axis_tlast	<= 1'b0;
		m_axis_tvalid	<= 1'b0;
	end else begin
		m_axis_data		<= fft_m_axis_data_tdata;	
		m_axis_tlast	<= fft_m_axis_data_tlast;
		m_axis_tvalid	<= fft_m_axis_data_tvalid;
	end
end


always@(posedge	SYS_CLK or negedge rstn)
begin
	if(rstn	== 1'b0)begin
		FFT_DATA_I			<= 'd0;
		FFT_DATA_Q			<= 'd0;
		FFT_DATA_VLD		<= 1'b0;
		FFT_DATA_LAST		<= 1'b0;
	end 
	else begin
		if(m_axis_tvalid ==	1'b1)begin
				FFT_DATA_I			<= m_axis_data[32+:32]*fft_cail_dout[15: 0] - m_axis_data[0 +:32]*fft_cail_dout[31:16] ;
				FFT_DATA_Q			<= m_axis_data[32+:32]*fft_cail_dout[31:16] + m_axis_data[0 +:32]*fft_cail_dout[15: 0] ;
				FFT_DATA_VLD		<= 1'b1;				
		end 
		else begin             
				FFT_DATA_VLD		<= 1'b0;	
				FFT_DATA_I			<= 'd0;
				FFT_DATA_Q			<= 'd0;
		end
		FFT_DATA_LAST   <=  	m_axis_tlast;
	end
end	

assign fft_data_cbit_i		= FFT_DATA_I[47]?(FFT_DATA_I[14]&(|FFT_DATA_I[13:0])):FFT_DATA_I[14];
assign fft_data_round_i		= FFT_DATA_I[46-:32]+fft_data_cbit_i;
assign fft_data_cbit_q		= FFT_DATA_Q[47]?(FFT_DATA_Q[14]&(|FFT_DATA_Q[13:0])):FFT_DATA_Q[14];
assign fft_data_round_q		= FFT_DATA_Q[46-:32]+fft_data_cbit_q;


reg                                          [63:0] IFFT_DATA_IN                       	 ; 
reg                                                 IFFT_DATA_VALID_IN                   ; 
wire                                                 cail_data_chose                   	 ; 

always@(posedge	SYS_CLK or negedge rstn)
begin
	if(rstn	== 1'b0)begin
		IFFT_DATA_IN     		<= 'd0;
		IFFT_DATA_VALID_IN 		<= 1'b0;
	end 
	else begin
		if(caild_en  ==	1'b1)begin
			IFFT_DATA_IN     		<= {fft_data_round_i,fft_data_round_q};
			IFFT_DATA_VALID_IN 		<= FFT_DATA_VLD;			
		end 
		else begin             
			IFFT_DATA_IN     		<= m_axis_data;
			IFFT_DATA_VALID_IN 		<= m_axis_tvalid;
		end
	end
end	

//生成IFFT的IP模块
ifft_cail u_ifft_cail (
    .aclk                                          ( SYS_CLK                             ), // input wire aclk                                  
    .aresetn                                       ( fft_rst                             ), // input wire aresetn                                  
    .s_axis_config_tdata                           ( ifft_config_dat                     ), // input wire [15 : 0] s_axis_config_tdata          
// .s_axis_config_tdata              ( 8'b0                             		  ), // input wire [15 : 0] s_axis_config_tdata          
    .s_axis_config_tvalid                          ( fft_config_tvalid                   ), // input wire s_axis_config_tvalid        
    .s_axis_config_tready                          ( ifft_config_tdy_path                ), // output wire s_axis_config_tready  
    .s_axis_data_tdata                             ( IFFT_DATA_IN               		 ), // input wire [47 : 0] s_axis_data_tdata   
    .s_axis_data_tvalid                            ( IFFT_DATA_VALID_IN             	 ), // input wire s_axis_data_tvalid            
    .s_axis_data_tready                            ( ifft_tready_path                    ), // output wire s_axis_data_tready 
    .s_axis_data_tlast                             (                                     ), // input wire s_axis_data_tlast      

    .m_axis_data_tdata                             ( ifft_m_axis_data_tdata              ), // output wire [47 : 0] m_axis_data_tdata                 
    // .m_axis_data_tready                            ( 1'b1                                ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready    
    .m_axis_data_tready                            ( ifftdat_vlid                        ), //取数延时,使最后一级fifo能够无损传输数据给ps// input wire m_axis_data_tready    
    .m_axis_data_tvalid                            ( ifft_m_axis_data_tvalid             ), // output wire m_axis_data_tvalid                     
    .m_axis_data_tlast                             ( ifft_m_axis_data_tlast              ), // output wire m_axis_data_tlast 

    .m_axis_status_tdata                           (ifft_m_axis_status_tdata             ), // output wire [7 : 0] m_axis_status_tdata
    .m_axis_status_tvalid                          (ifft_m_axis_status_tvalid            ), // output wire m_axis_status_tvalid
    .m_axis_status_tready                          ( 1'b1	            				 ), // input wire m_axis_status_tready

    .event_frame_started                           (                                     ), // output wire event_frame_started    
    .event_tlast_unexpected                        (                                     ), // output wire event_tlast_unexpected 
    .event_tlast_missing                           (                                     ), // output wire event_tlast_missing    
    .event_data_in_channel_halt                    (                                     ), // output wire event_data_in_channel_halt
    .event_status_channel_halt                     (                                     ), // output wire event_status_channel_halt
    .event_data_out_channel_halt                   (                                     )  // output wire event_data_out_channel_halt
  );

always@(posedge	SYS_CLK or negedge rstn)
begin
	if(rstn	== 1'b0)begin
		ifftdat_delay		<=	6'd6;
		ifftdat_vlid		<=	1'b0;
	end else begin
		if(ifftdat_delay >= 6'd31)begin//fft 取数延时,使得最后一级fifo 能够无损传输数据给ps
			ifftdat_delay	<=	6'd0;
			ifftdat_vlid	<=	1'b1;
		end else begin
			ifftdat_delay	<=	ifftdat_delay + 1'b1;
			ifftdat_vlid	<=	1'b0;
		end
	end
end


reg                                           fifo_rd_en                           ; 
reg                                  [5  : 0] fifo_rd_cunt                         ; 
wire                                 [63 : 0] dout                                 ; 
wire                                 [9  : 0] data_count                           ; 
wire                                          full                                 ; 
wire                                          empty                                ; 
wire                                          valid                                ; 

ifft_fifo_data_300m  u_ifft_fifo_data_300m(
    .clk                              (SYS_CLK                                    ), // input wire rd_clk
    .din                              (ifft_m_axis_data_tdata 					  ), // input wire [75 : 0] din
    .wr_en                            (ifft_m_axis_data_tvalid                    ), // input wire wr_en
    .rd_en                            (fifo_rd_en                                 ), // input wire rd_en
    .dout                             (dout                                       ), // output wire [63 : 0] dout
	.data_count					  	  (data_count    						  	  ),  // output wire [12 : 0] wr_data_count		
    .full                             (full                                       ), // output wire full
    .empty                            (empty                                      ), // output wire empty
    .valid                            (valid                                      )  // output wire valid
);


always@(posedge	SYS_CLK or negedge rstn)
begin
	if(rstn	== 1'b0)begin
		fifo_rd_en			<=	1'b0;
	end else begin
		if(empty==1'b0)
			fifo_rd_en		<=	1'b1;
		else 
			fifo_rd_en			<=	1'b0;
	end			
end	

assign  I_DATA_OUT  	= dout[63-:32]	;
assign  Q_DATA_OUT  	= dout[31-:32]	;
assign  DATA_OUT_VALID  = valid			;

endmodule

4.1 FFT配置界面

4.2  IFFT配置界面

4.3  SYNC_FIFO配置界面

5、仿真

5.1、testbench代码

        仿真时用dds模拟adc产生数据,并且控制输入6次数据,做FFT、IFFT后连续输出

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/08/12 14:14:51
// Design Name: 
// Module Name: cail_testbench
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`timescale 1ns / 1ps
module cail_testbench;

reg                                           clk 		= 0                        ; 
reg                                           rst_n 	= 0                    	   ; 
wire                                          clk_300m                             ; 
wire                                          clk_100m                             ; 
wire                                          locked                               ; 


	initial
	begin
			rst_n   =0;
			#100;
			rst_n      =1;
	end
	
	always #5 clk = ~clk;

//   clk_wiz_1 instance_name
//    (
//     // Clock out ports
//     .clk_out1                         (clk_100m                                   ), // output clk_out1
//     .clk_out2                         (clk_300m                                   ), // output clk_out2
//     // Status and control signals
//     .reset                            (!rst_n                                     ), // input reset
//     .locked                           (                                           ), // output locked
//    // Clock in ports
//     .clk_in1                          (clk                                    	  ) // input clk_in1
// 	);
	

globaclk_clk300m u_globaclk_clk300m
(
// Clock out ports
    .clk_300m_g                       (clk_300m                                 ), // output clk_300_g
    .clk_100m_g                       (clk_100m                                 ), // output clk_100_g
// Status and control signals
    .reset                            (1'b0                                       ), // input reset
    .locked                           (locked                                     ), // output locked
// Clock in ports
    .global_clk                       (clk                                        )  // input global_clk
);


reg [47 : 0] m_dds_tdata_r;
reg [31 : 0] m_dds_tdata_cunt;
reg 	 	 m_dds_tdata_valid;

	always@(posedge clk_300m or negedge locrstn)begin
		if(locrstn==1'b0)begin
			m_dds_tdata_cunt<='d0;
			m_dds_tdata_r<='d0;
			m_dds_tdata_valid<='d0;
		end
		else if(m_dds_tdata_cunt == 'd2) begin
			m_dds_tdata_cunt<='d0;
			m_dds_tdata_r<=m_dds_tdata;
			m_dds_tdata_valid<='d1;  			                
		end
		else begin
			m_dds_tdata_cunt<=m_dds_tdata_cunt + 'd1;
			m_dds_tdata_r <= m_dds_tdata_r;
			m_dds_tdata_valid<='d0;
		end
	end






localparam                                    FFT_LEN = 512                        ;
reg                                           locrstn,locrstn_buf                  ; 
//=================================================================================/
// fifo
//=================================================================================/
wire                                          fifo_rd_en                           ; 
wire                                 [47 : 0] fifo_dout                            ; 
wire                                          fifo_full                            ; 
wire                                          fifo_empty                           ; 
wire                                          fifo_valid                           ; 
wire                                          fifo_wr_rst_busy                     ; 
wire                                          fifo_rd_rst_busy                     ;
(*mark_debug = "true"*)reg                                    [15:0] fifo_read_cunt                       ; 
reg                                    [15:0] data_cunt                            ;
wire                                   [10:0] wr_data_count                	   	   ;
//=================================================================================/
// FFT
//=================================================================================/
reg                                    [15:0] tlast_cnt                            ; 
wire                                          fft_tlast_path                       ; 
wire                                   [47:0] fft_data_tdata                       ; 
wire                                          fft_tvalid_path                      ; 
wire                                          fft_tready_path                      ; 
wire                                   	      m_axis_data_tvalid                   ; 
wire                                   [47:0] m_dds_tdata                          ; 
//=================================================================================/
// 状态机
//=================================================================================/
reg                                    [2:0]  fifo_read_state             	   	   ;
reg                                    [2:0]  fifo_next__state             	   	   ;

parameter      							      FIFO_READ_IDLE   =  'd0 			   ;
parameter      							      FIFO_READ_WAIT   =  'd1 			   ;
parameter      							      FIFO_READ        =  'd2 			   ;
parameter      							      FIFO_READ_DONE   =  'd3 			   ;

	always@(posedge clk_300m or negedge locked)begin
		if(locked == 1'b0)begin
			locrstn_buf		<= 1'b0;
			locrstn			<= 1'b0;
		end else begin
			locrstn_buf		<= 1'b1;
			locrstn			<= locrstn_buf;
		end
	end

//=================================================================================/
// 状态机 控制FIFO数据流
//=================================================================================/
	always @(posedge clk_300m or posedge locrstn) begin
		if( locrstn ==1'b0)
			fifo_read_state <= FIFO_READ_IDLE;
		else
			fifo_read_state <= fifo_next__state;
	end

    always @(*) begin
        // always @(posedge clk_300m or posedge locrstn) begin
                case (fifo_read_state)
                    FIFO_READ_IDLE             :    fifo_next__state = FIFO_READ_WAIT;

                    FIFO_READ_WAIT             :    fifo_next__state = (wr_data_count>=1500)&&(data_cunt<=5) ? FIFO_READ : FIFO_READ_WAIT;//仿真时连续6次输入数据
            		// FIFO_READ_WAIT             :    fifo_next__state = ((fft_tready_path==1'b1)&&(wr_data_count>1100)) ? FIFO_READ : FIFO_READ_WAIT;

                    FIFO_READ                  :    fifo_next__state = fft_tlast_path ? FIFO_READ_DONE : FIFO_READ;
        			// FIFO_READ                  :    fifo_next__state = (fifo_read_cunt==FFT_LEN) ? FIFO_READ_DONE : FIFO_READ;

                    FIFO_READ_DONE             :    fifo_next__state = FIFO_READ_IDLE;

                    default		       :    fifo_next__state = FIFO_READ_IDLE;
                endcase
        end

	always@(posedge clk_300m or negedge locrstn)begin
		if(locrstn==1'b0)
			data_cunt<='d0;
		else if(data_cunt==30)
			data_cunt<=data_cunt;       			                
		else if(fft_tlast_path)begin
			data_cunt<=data_cunt+1'b1; 
		end     
		else
			data_cunt<=data_cunt;
	end

//=================================================================================/
//----------------------------------------FIFO模块---------------------------------
//=================================================================================/
	fifo_ddc2fft_48bit u_fifo_ddc2fft_48bit (
		.wr_clk                           (clk_300m                                   ), // input wire wr_clk
		.rd_clk                           (clk_300m                                   ), // input wire rd_clk	
		.din                              (m_dds_tdata_r                      	      ), // input wire [47 : 0] din
		.wr_en                            (m_dds_tdata_valid                          ), // input wire wr_en
		.rd_en                            (fifo_rd_en                                 ), // input wire rd_en
		.dout                             (fifo_dout                                  ), // output wire [47 : 0] dout
		.full                             (fifo_full                                  ), // output wire full
		.empty                            (fifo_empty                                 ), // output wire empty
		.valid                            (fifo_valid                                 ), // output wire valid
		.wr_data_count			  (	wr_data_count    			      )  // output wire [12 : 0] wr_data_count	

	);

//=================================================================================/
// 产生FIFO读使能信号fifo_rd_en,在FFT核准备好且FIFO非空时
// 在使能信号连续拉高1024个周期以后等待3个周期再拉高,用于分割一次1024长度的FFT
//=================================================================================/
	always@(posedge clk_300m or negedge locrstn) begin
		if(locrstn==1'b0)
			fifo_read_cunt<='d0;
		else if(fifo_read_state == FIFO_READ)begin
			fifo_read_cunt<=fifo_read_cunt+1'b1; 
		end     
		else
			fifo_read_cunt<='d0;		
	end	
//=================================================================================/
//用于产生FFT模块每帧输入最后(第1024个数据)一个数据的控制信息s_axis_data_tlast
//=================================================================================/
	always@(posedge clk_300m or negedge locrstn) begin
		if(locrstn==1'b0)
			tlast_cnt<='d0;
		else if((tlast_cnt==FFT_LEN-1)&&(fifo_valid==1'b1)||(fifo_read_state != FIFO_READ))
			tlast_cnt<='d0;        
		else if(fifo_valid==1'b1)
			tlast_cnt<=tlast_cnt+1'b1;
	end	
	
assign fifo_rd_en = (fft_tready_path==1'b1) && (1<=fifo_read_cunt)&& (fifo_read_cunt<=FFT_LEN)&& (fifo_empty==1'b0)?  1'b1 : 1'b0;
// assign fifo_rd_en = (1<=fifo_read_cunt)&& (fifo_read_cunt<FFT_LEN+1)&& (fifo_empty==1'b0)?  1'b1 : 1'b0;
//-----------------------------------------FFT模块----------------------------------------------
//=================================================================================/
//输入的正弦信号为实信号放在实部
//=================================================================================/
	assign fft_data_tdata   = fifo_dout;
	assign fft_tvalid_path  = fifo_valid;
	assign fft_tlast_path 	= ((tlast_cnt==FFT_LEN-1)&&(fifo_valid)) ? 1'b1 : 1'b0;

	dds_compiler_0 dds_compiler_1m (
		.aclk                             (clk_100m                             ), // input wire aclk
		.s_axis_phase_tvalid              (1'b1                                 ), // input wire s_axis_phase_tvalid
		.s_axis_phase_tdata               (16'd655                              ), // input wire [15 : 0] s_axis_phase_tdata
		.m_axis_data_tvalid               (m_axis_data_tvalid                   ), // output wire m_axis_data_tvalid
		.m_axis_data_tdata                (m_dds_tdata                      	)  // output wire [47 : 0] m_axis_data_tdata
	);

	cail_fft_ifft #(
		.BIT_NUM                          ( 24                                       )  //BIT_NUM
	)u_cail_fft_ifft
	(
		.SYS_CLK                          (clk_300m                                	 ), // (input ) (input ) 
		.SYS_RSTN                         (locrstn                                   ), // (input ) (input ) 
	
		.fft_data_tdata                   (fft_data_tdata                            ), // (input ) (input )   
		.fft_tvalid_path                  (fft_tvalid_path                           ), // (input ) (input ) 
		.fft_tlast_path                   (fft_tlast_path                            ), // (input ) (input ) 

		.fft_tready_path                  (fft_tready_path                           ), // (output ) (output ) 
		.I_DATA_OUT                       (				                             ), // (output) (output)
		.Q_DATA_OUT                       (				                             ), // (output) (output)
		.DATA_OUT_VALID                   (				                             ) // (output) (output)       
	);



////////仿真数据保存为TXT文件
////integer     dout_file_imag;
////
////initial
////begin
////        dout_file_imag =$fopen("F:/shx/Matalb/test/f_imag.txt");
////        if(dout_file_imag == 0)begin
////                $display("can not open file!");
////                $stop;
////        end  
////end
////always @(posedge clk_300m)
////begin 
////        if(m_axis_data_tvalid) begin  
////                $fdisplay(dout_file_imag,"%d",$signed(f_imag)); 
////        end
////end

endmodule

5.2 仿真波形 

5.2.1 输入波形连续

5.2.2输出波形

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值