verilog FFT Vivado IP core implementation

1. First use matlab to generate 16-bit binary sinusoidal signal data and store it in rom:

%Set parameters
fi=5000;
L=1024;
N=16;
fs=20000;

% generate signal
t=0:1/fs:(L-1)/fs;
theta=rand()*2*pi;
si=sin(2*pi*fi*t + theta);

f_s=si/max(abs(si));
Q_s=round(f_s*(2^(N-1)-1));

fid=fopen('C:\Users\HLPC\Desktop\Sin.txt','w');
for k=1:length(Q_s)
    B_s=dec2bin(Q_s(k) + (Q_s(k)<0)*2^N,N);
    for j=1:N
        if B_s(j)=='1'
            tb=1;
        else
            tb=0;
        end
        fprintf(fid,'%d',tb);
    end
    fprintf(fid,'\r\\
');
end
fprintf(fid,';');
fclose(fid);

2. Store data in rom ip core
For the application of ROM core, see: https://blog.csdn.net/qq_39005414/article/details/109552835

3. FFT ip core configuration


`timescale 1ns / 1ps
module rom_fft(
    input sys_clk_n,
    input sys_clk_p,
    input rst_n,
    output [9:0] a,
    output reg [15:0]data_i,
    output m_axis_data_tvalid,
    output [63:0] data_o,
    output reg [26:0]fft_re,
    output reg [26:0]fft_im,
    output reg [54:0]fft_amp
    );
wire clk;
wire [15:0]spo;
reg s_axis_config_tvalid;
wire s_axis_config_tready;
reg s_axis_data_tvalid;
reg s_axis_data_tlast;
wire m_axis_data_tlast;
wire s_axis_data_tready;
wire [63:0] m_axis_data_tdata;
wire event_frame_started;
wire event_tlast_unexpected;
wire event_tlast_missing;
wire event_status_channel_halt;
wire event_data_in_channel_halt;
wire event_data_out_channel_halt;
reg cnt_flag;
reg[10:0]cnt;
wire [53:0] xkre_square, xkim_square;
assign data_o = m_axis_data_tdata;
IBUFDS CLK(
    .I(sys_clk_n),
    .IB(sys_clk_p),
    .O(clk)
);

xfft_0 your_instance_name (
  .aclk(clk), // input wire aclk
  .aresetn(rst_n),
  .s_axis_config_tdata(8'd1), // input wire [15 : 0] s_axis_config_tdata
  .s_axis_config_tvalid(s_axis_config_tvalid), // input wire s_axis_config_tvalid
  .s_axis_config_tready(s_axis_config_tready), // output wire s_axis_config_tready
  .s_axis_data_tdata({16'd0,data_i}), // input wire [31 : 0] s_axis_data_tdata
  .s_axis_data_tvalid(s_axis_data_tvalid), // input wire s_axis_data_tvalid
  .s_axis_data_tready(s_axis_data_tready), // output wire s_axis_data_tready
  .s_axis_data_tlast(s_axis_data_tlast), // input wire s_axis_data_tlast
  .m_axis_data_tdata(m_axis_data_tdata), // output wire [31 : 0] m_axis_data_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
  .m_axis_data_tready(1'b1), // input wire m_axis_data_tready
  .m_axis_data_tlast(m_axis_data_tlast), // output wire m_axis_data_tlast
  .event_frame_started(event_frame_started), // output wire event_frame_started
  .event_tlast_unexpected(event_tlast_unexpected), // output wire event_tlast_unexpected
  .event_tlast_missing(event_tlast_missing), // output wire event_tlast_missing
  .event_status_channel_halt(event_status_channel_halt), // output wire event_status_channel_halt
  .event_data_in_channel_halt(event_data_in_channel_halt), // output wire event_data_in_channel_halt
  .event_data_out_channel_halt(event_data_out_channel_halt) // output wire event_data_out_channel_halt
);

reg [9:0] cnt1;
always @(posedge clk)begin
    if(~rst_n)
        cnt1 <= 1'b0;
    else if(cnt1 < 10'd200)
        cnt1 <= cnt1 + 1'b1;
end

always @(posedge clk)begin
    if(~rst_n)
        cnt_flag <= 1'b0;
    else if(s_axis_config_tvalid)
        cnt_flag <= 1'b1;
end

always @(posedge clk)begin
    if(~rst_n)
        s_axis_config_tvalid <= 1'b0;
    else if(cnt1 < 10'd200)
        s_axis_config_tvalid <= 1'b1;
    else
        s_axis_config_tvalid <= 1'b0;
end

always @(posedge clk)begin
    if(~rst_n)
        cnt <= 11'd0;
    else if(cnt_flag)
        if(cnt <= 11'd1023)
            cnt <= 11'd1 + cnt;
        else
            cnt <= cnt;
    else
        cnt <= 11'd0;
end

always @(posedge clk)begin
    if(~rst_n)
        s_axis_data_tvalid <= 1'b0;
    else if(cnt_flag & amp; & amp; cnt <= 11'd1023)
        s_axis_data_tvalid <= 1'b1;
    else
        s_axis_data_tvalid <= 1'b0;
end

always @(posedge clk)begin
    if(~rst_n)
        s_axis_data_tlast <= 1'b0;
    else if(cnt == 11'd1023)
        s_axis_data_tlast <= 1'b1;
    else
        s_axis_data_tlast <= 1'b0;
end

always @(posedge clk)begin
    if(~rst_n)
        fft_im <= 27'd0;
    else
        fft_im <= data_o[58:32];
end
always @(posedge clk)begin
    if(~rst_n)
        fft_re <= 27'd0;
    else
        fft_re <= data_o[26:0];
end

mult_gen_0 your_instance_name3 (
  .CLK(clk), // input wire CLK
  .A(fft_re), // input wire [26 : 0] A
  .B(fft_re), // input wire [26 : 0] B
  .P(xkre_square) // output wire [53 : 0] P
);

mult_gen_0 your_instance_name4 (
  .CLK(clk), // input wire CLK
  .A(fft_im), // input wire [26 : 0] A
  .B(fft_im), // input wire [26 : 0] B
  .P(xkim_square) // output wire [53 : 0] P
);

always @(posedge clk)
   if(~rst_n)
      fft_amp <= 55'd0;
   else
      fft_amp <= xkre_square + xkim_square;

dist_mem_gen_0 your_instance_name1 (
  .a(a), // input wire [9 : 0] a
  .clk(clk), // input wire clk
  .qspo_rst(~rst_n), // input wire qspo_rst
  .qspo(spo) // output wire [15 : 0] qspo
);

assign a = cnt;
 always@(posedge clk or negedge rst_n)begin
    if(~rst_n )
        data_i <= 16'd0;
    else if(a <= 10'd1023)
        data_i <= spo;
    end

endmodule

testbench simulation

module vtf_test(

    );
    
wire sys_clk_n;
reg sys_clk_p;
reg rst_n;
wire [15:0] data_i;
wire [63:0] data_o;
wire [26:0] fft_re;
wire [26:0] fft_im;
wire [54:0] fft_amp;
wire [9:0] a;
wire clk;
wire m_axis_data_tvalid;

rom_fft u_rom_fft(
    .sys_clk_n(sys_clk_n),
    .sys_clk_p(sys_clk_p),
    .rst_n(rst_n),
    .a(a),
    .data_i(data_i),
    .m_axis_data_tvalid(m_axis_data_tvalid),
   .data_o(data_o),
   .fft_re(fft_re),
   .fft_im(fft_im),
   .fft_amp(fft_amp)
    );
    
  
initial begin
    rst_n = 0;
    sys_clk_p = 0;
    #20;
    rst_n = 1;
    #2000000;
end

IBUFDS CLK(
    .I(sys_clk_n),
    .IB(sys_clk_p),
    .O(clk)
);

integer file_out;
initial
begin
   //The file is placed in the "project directory\simulation\modelsim" path
file_out = $fopen("out.txt");
if(!file_out)
begin
$display("could not open file!");
$finish;
end
end
always @(posedge clk)begin
    if(m_axis_data_tvalid)
$fdisplay(file_out,"%d",fft_amp);
end

integer file_out1;
initial
begin
   //The file is placed in the "project directory\simulation\modelsim" path
file_out1 = $fopen("out1.txt");
if(!file_out)
begin
$display("could not open file!");
$finish;
end
end
always @(posedge clk)begin
    if((a>0) & amp; & amp; (a<10'd1023))
$fdisplay(file_out1,"%d",data_i);
end

always #5 sys_clk_p=~sys_clk_p;
assign sys_clk_n=~sys_clk_p;

endmodule

Simulation results

4. Compare the result output with the result after matlab fft:

subplot(2,1,1)
cstr = textread('D:\fpga_test\rom_fft\rom_fft.sim\sim_1\behav\xsim\out.txt','%d');
plot(cstr)
subplot(2,1,2)
cstr1 = textread('C:\Users\HLPC\Desktop\Sin.txt','%d');
plot(abs(fft(cstr1)))