1 介绍
只作为本人调试笔记使用,如有错误,请指正,感谢。
2 生成IP
软件版本基于2023.2。
使用ooc方式编译IP,会生成cmodel文件,可以直接在matlab中仿真使用:
3 编写HDL测试文件:
以512个数据长度为例:
module tb();
reg clk250 = 1'b0;
always #2 clk250 <= ~clk250;
reg nRst = 1'b0;
reg signed [15:0] mem_data_I[511:0];
reg signed [15:0] mem_data_O[0:511];
integer outputfile;
integer outputfile1;
reg [8:0] n;
initial begin
clk250 <= 1'b0;
nRst <= 1'b0;
#101
nRst <= 1'b1;
$readmemh("G:/FFT/fft_ip_in.txt",mem_data_I);
outputfile = $fopen("G:/FFT/fft_ip_out_re.txt","w");
outputfile1 = $fopen("G:/FFT/fft_ip_out_im.txt","w");
#23000
// for(n=0;n<=511;n=n+1)
// $fwrite(outputfile,"%x\n",mem_data_O);
$fclose(outputfile);
$fclose(outputfile1);
end
reg [9:0] cnt = 'd0;
reg signed [31:0] s_axis_data_tdata = 'd0;
reg s_axis_data_tvalid = 1'b0;
reg s_axis_data_tlast = 1'b0;
wire s_axis_data_tready;
reg m_axis_data_tready = 1'b1;
wire m_axis_data_tvalid;
wire m_axis_data_tlast;
wire signed [31:0] m_axis_data_tdata;
reg [9:0] m_cnt = 'd0;
always@(*) begin
if(cnt == 511) begin
if(s_axis_data_tready) begin
s_axis_data_tvalid <= 1'b1;
s_axis_data_tlast <= 1'b1;
s_axis_data_tdata <= {16'd0,mem_data_I[cnt]};
end else begin
s_axis_data_tvalid <= 1'b0;
s_axis_data_tlast <= 1'b0;
end
end else if(cnt < 511) begin
if(s_axis_data_tready) begin
s_axis_data_tvalid <= 1'b1;
s_axis_data_tlast <= 1'b0;
s_axis_data_tdata <= {16'd0,mem_data_I[cnt]};
end else begin
s_axis_data_tvalid <= 1'b0;
s_axis_data_tlast <= 1'b0;
end
end else begin
s_axis_data_tvalid <= 1'b0;
s_axis_data_tlast <= 1'b0;
end
end
always@(posedge clk250) begin
if(cnt > 511) begin
// s_axis_data_tvalid <= 1'b0;
// s_axis_data_tlast <= 1'b0;
// s_axis_data_tdata <= 32'd0;
cnt <= cnt;
end else begin
// if(s_axis_data_tready && s_axis_data_tvalid) begin
if(s_axis_data_tready) begin
if(cnt == 511) begin
cnt <= cnt + 1'b1;
// s_axis_data_tvalid <= 1'b1;
// s_axis_data_tlast <= 1'b1;
// s_axis_data_tdata <= {16'd0,mem_data_I[cnt]};
end else begin
cnt <= cnt + 1'b1;
// s_axis_data_tvalid <= 1'b1;
// s_axis_data_tlast <= 1'b0;
// s_axis_data_tdata <= {16'd0,mem_data_I[cnt]};
end
end else begin
cnt <= cnt;
// s_axis_data_tdata <= s_axis_data_tdata;
end
end
if(m_axis_data_tready && m_axis_data_tvalid) begin
m_cnt <= m_cnt + 1'b1;
// mem_data_O[m_cnt] <= m_axis_data_tdata[31:16];
$fwrite(outputfile,"%x\n",m_axis_data_tdata[15:0]);
$fwrite(outputfile1,"%x\n",m_axis_data_tdata[31:16]);
end else begin
m_cnt <= m_cnt;
end
end
xfft_0 fft_ip (
.aclk(clk250), // input wire aclk
.aclken(nRst), // input wire aclken
.s_axis_config_tdata({4'd0,20'b00_01_01_01_01_01_01_01_01_01,1'b0,3'd0,5'd9}), // input wire [31 : 0] s_axis_config_tdata
// .s_axis_config_tdata({4'd0,20'b10_10_10_10_10_10_10_10_10_10,1'b0,3'd0,5'd9}), // input wire [31 : 0] s_axis_config_tdata
.s_axis_config_tvalid(1'b1), // input wire s_axis_config_tvalid
.s_axis_config_tready(), // output wire s_axis_config_tready
.s_axis_data_tdata(s_axis_data_tdata), // 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(m_axis_data_tready), // input wire m_axis_data_tready
.m_axis_data_tlast(m_axis_data_tlast), // output wire m_axis_data_tlast
.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_status_channel_halt(), // output wire event_status_channel_halt
.event_data_in_channel_halt(), // output wire event_data_in_channel_halt
.event_data_out_channel_halt() // output wire event_data_out_channel_halt
);
endmodule
将IP仿真后的输出数写入到fft_ip_out_im.txt文件中,方便在matlab中作图比较。
4 Matlab仿真
第一步:进入ip产生的cmodel文件夹下,或将xfft_v9_1_bitacc_cmodel_nt64.zip文件解压到自定义的文件夹下,matlab进入该文件夹,刚开始是没有xfft_v9_1_bitacc_mex.mexw64文件的;
第二步:在matlab命令窗口中输入mex -setup -v,查看当前编译器,如果没有找到编译器,需要安装一个vs或MinGW64。我这里使用mingw64编译器,下载链接:TDM-GCC 10.3.0 release | tdm-gcc (jmeubank.github.io)
第三步:命令行窗口输入run make_xfft_v9_1_mex.m,编译成功会产生一个xfft_v9_1_bitacc_mex.mexw64文件
第四步:修改run_xfft_v9_1_mex.m文件
% Generics for this smoke test
generics.C_NFFT_MAX = 9;
generics.C_ARCH = 2;
generics.C_HAS_NFFT = 1;
generics.C_USE_FLT_PT = 0;
generics.C_INPUT_WIDTH = 16; % Must be 32 if C_USE_FLT_PT = 1
generics.C_TWIDDLE_WIDTH = 26; % Must be 24 or 25 if C_USE_FLT_PT = 1
generics.C_HAS_SCALING = 1; % Set to 0 if C_USE_FLT_PT = 1
generics.C_HAS_BFP = 0; % Set to 0 if C_USE_FLT_PT = 1
generics.C_HAS_ROUNDING = 0; % Set to 0 if C_USE_FLT_PT = 1
channels = 1;
samples = 2^generics.C_NFFT_MAX;
X=textread('G:\AvnetWork\Customer\SenardMicro\FFT\matlab\test\fft_ip_in.txt','%s')
data_before_fft = hex2dec(X);
for i=1:1:length(data_before_fft)
if(data_before_fft(i) > 2^16/2-1)
data_before_signed(i) = data_before_fft(i) - 2^16;
else
data_before_signed(i) = data_before_fft(i);
end
end
data_before_signed = data_before_signed/(2^16);
% data_before_signed = data_before_signed';
% Handle multichannel FFTs if required
for channel = 1:channels
% Create input data frame: constant data
% constant_input = 0.5 + 0.5j;
constant_input = data_before_signed + 0*j;
% input_raw(1:samples) = constant_input;
% input_raw(1:samples) = data_before_signed;
if generics.C_USE_FLT_PT == 0
% Set up quantizer for correct twos's complement, fixed-point format: one sign bit, C_INPUT_WIDTH-1 fractional bits
% Alas, this function is not available in Octave, but the test values of 0.5+0.5j do not cause quantization errors anyway.
% q = quantizer([generics.C_INPUT_WIDTH, generics.C_INPUT_WIDTH-1], 'fixed', 'convergent', 'saturate');
% Format data for fixed-point input
% input = quantize(q,input_raw);
input = constant_input;
else
% Floating point interface - use data directly
input = constant_input;
end
% Set point size for this transform
nfft = generics.C_NFFT_MAX;
% Set up scaling schedule: scaling_sch[1] is the scaling for the first stage
% Scaling schedule to 1/N:
% 2 in each stage for Radix-4/Pipelined, Streaming I/O
% 1 in each stage for Radix-2/Radix-2 Lite
if generics.C_ARCH == 1 || generics.C_ARCH == 3
scaling_sch = ones(1,floor(nfft/2)) * 2;
if mod(nfft,2) == 1
scaling_sch = [scaling_sch 1];
end
else
scaling_sch = ones(1,nfft);
end
% Set FFT (1) or IFFT (0)
direction = 1;
if channels > 1
fprintf('Running the MEX function for channel %d...\n',channel)
else
fprintf('Running the MEX function...\n')
end
% Run the MEX function
[output, blkexp, overflow] = xfft_v9_1_bitacc_mex(generics, nfft, input, scaling_sch, direction);
output = output*2^16;
o_re = real(output);
o_im = imag(output);
fprintf('Running the MEX function...Done\n')
Re=textread('G:\AvnetWork\Customer\SenardMicro\FFT\fft_ip_out_re.txt','%s')
data_re = hex2dec(Re);
for i=1:1:length(data_re)
if(data_re(i) > 2^16/2-1)
data_re_signed(i) = data_re(i) - 2^16;
else
data_re_signed(i) = data_re(i);
end
end
data_re_signed = data_re_signed;
Im=textread('G:\AvnetWork\Customer\SenardMicro\FFT\fft_ip_out_im.txt','%s')
data_im = hex2dec(Im);
for i=1:1:length(data_im)
if(data_im(i) > 2^16/2-1)
data_im_signed(i) = data_im(i) - 2^16;
else
data_im_signed(i) = data_im(i);
end
end
data_im_signed = -data_im_signed; % 这里取负数并没有想明白,只是波形图出来的结果看起来是相反的,请大佬指出。
subplot(2,1,1);
plot(o_re,'r');
hold on;
plot(data_re_signed,'b');
title('real');
subplot(2,1,2);
plot(o_im,'r');
hold on;
plot(data_im_signed,'b');
title('imag');
输出结果:
红色是cmodel的结果,蓝色是FFT IP输出的结果,这里把实部和虚部分开对比。