这里写目录标题
- 1 功能
- 2 开发环境
- 3 框架
- 4 转置公式
- 5 Simulation
- 第一部分
- 第二部分
- 第三部分
- 6 Matlab代码
- 产生FIFO数据
- 产生转置矩阵
- 7 HDL
- 仿真文件
- 顶层文件
- FIFO顶层文件
- FIFO读
- FIFO写
- RAM顶层文件
- 8 IP配置
- FIFO
- RAM
- ROM
- 9 Reference
1 功能
通过tb读取本地数据保存到FIFO,通过coe文件将转置后的地址数据保存在ROM中,读取FIFO的文件作为输入,读取ROM作为地址。通过地址变换,对矩阵进行转置,最终将转置后的矩阵保存在RAM中。
2 开发环境
Vivado
3 框架
包含IP:FIFO、RAM和ROM
4 转置公式
来源见 Reference
5 Simulation
第一部分
通过tb将数据写到FIFO中,此部分数据为两路(1:32)*32。
这里的数据也就是转置前的数据,每行从1增长到32,总共32行。
第二部分
从FIFO中读取数据。
从ROM中读取地址,此地址为转置后的地址。
将FIFO中的数据按ROM中的地址写入到RAM中。
第三部分
读取RAM,可以从波形上看到转置的效果。
本来每行是1到32逐渐增加,现在每行为1到32中的一个数。
转置成功!
6 Matlab代码
产生FIFO数据
%% export to bin file% specifying a signed, fixed-point data type, rounding towards negative infinity, and saturate on overflow.
struct.mode = 'fixed';
struct.roundmode = 'floor';
struct.overflowmode = 'saturate';
struct.format = [8 0]; % 8位二进制数,0位小数,默认1位符号位
q=quantizer(struct);miu1_real = zeros(32,32);
for i = 1:32miu1_real(:,i) = i;
end
miu1_imag = miu1_real;% 量化值与实际值的误差
q_miu1_real = quantize(q,miu1_real);
q_miu1_imag = quantize(q,miu1_imag);
disp("最大量化误差");
disp(max(max([abs(miu1_real-q_miu1_real),abs(miu1_imag-q_miu1_imag)])));% 按行转为列向量
real_o = num2bin(q, reshape(miu1_real', [], 1));
imag_o = num2bin(q, reshape(miu1_imag', [], 1));
% 按列转为列向量
% real_o = num2bin(q,miu1_real(:));
% imag_o = num2bin(q,miu1_imag(:)); %% 将数据写入TXT
fid1=fopen('F:\MyTest\FPGA\IPFFT2\IPFFT2.srcs\sources_1\script/real_order.txt','wt');
fid2=fopen('F:\MyTest\FPGA\IPFFT2\IPFFT2.srcs\sources_1\script/imag_order.txt','wt');for i=1:32*32fwrite(fid1,real_o(i,:));fprintf(fid1,'\n');fwrite(fid2,imag_o(i,:));fprintf(fid2,'\n');
end
fclose(fid1);
fclose(fid2);
数据
imag_order内容一致
产生转置矩阵
close all; clear; clc
%% 生成方阵
a = 1:32*32;
a_exp = reshape(a, 32, 32);
a_exp = a_exp';
disp(a_exp);
%% 产生转置系数
m = 32;
n = 32;
% addr = (i-1)*n+j;
addr = 1:32*32;
% disp(addr);
i = floor((addr-1)/n) + 1;
j = mod((addr-1),n) + 1;
addr_t = (j-1)*m+i;
addr_t = addr_t-1; % 从0开始
%% 利用转置系数对方阵进行转置
b = zeros(1, 32*32);
for i = 1:32*32b(i) = a(addr_t(i)+1);
end
b_shrink = reshape(b, 32, 32);
b_shrink = b_shrink';
disp(b_shrink);%% 生成coe
N = 32*32;
fid = fopen('F:\MyTest\FPGA\IPFFT2\IPFFT2.srcs\sources_1\script/tran_matrix_para_1024.coe','wt');
%- standard format
fprintf( fid, 'memory_initialization_radix = 10;\n');
fprintf( fid, 'memory_initialization_vector =\n');
%- write data in coe file
for i = 1:1:Nif(i == N)fprintf(fid,'%d;',addr_t(i)); elsefprintf(fid,'%d,\n',addr_t(i)); end
end
fclose(fid);
数据
7 HDL
仿真文件
module tb_ip_fft2;reg clk;
reg rst_n;reg [7:0] data_real [1023:0];
reg [7:0] data_imag [1023:0];reg [7:0] dati_in;
reg [7:0] datq_in;wire [15:0] fifo_din;
reg [9:0] count=0;integer i;initial beginclk=1;rst_n=0;dati_in=0;datq_in=0;// (1:32)*32$readmemb("F:/MyTest/FPGA/IPFFT2/IPFFT2.srcs/sources_1/script/real_order.txt",data_real);$readmemb("F:/MyTest/FPGA/IPFFT2/IPFFT2.srcs/sources_1/script/imag_order.txt",data_imag);// for(i=0; i<127; i=i+1)// $display("%h %h", data_real[i], data_imag[i]);#100rst_n=1;
endalways #5 clk=~clk;assign fifo_din = {datq_in, dati_in};top u_top (.clk ( clk ),.rst_n ( rst_n ),.fifo_din ( fifo_din ),.fifo_wr_en_pre ( fifo_wr_en_pre )
);always @(posedge clk) beginif (!rst_n) begincount <= 1'b0;dati_in <= 1'b0;datq_in <= 1'b0;endelse if ( fifo_wr_en_pre ) begindati_in <= data_real[count];datq_in <= data_imag[count];count <= count+1'b1;endelse begincount <= count ;dati_in <= dati_in ;datq_in <= datq_in ;end
endendmodule
顶层文件
module top(input clk ,input rst_n ,input [15:0] fifo_din ,output fifo_wr_en_pre);wire fifo_wr_en ;// wire fifo_wr_en_pre ;wire fifo_rd_en ;wire [1:0] fifo_rd_en_pre ;wire [15:0] fifo_dout ;wire [27 : 0] ram_douta ;ip_fifo u_ip_fifo (.clk ( clk ),.rst_n ( rst_n ),.fifo_din ( fifo_din ),.fifo_dout ( fifo_dout ),.fifo_wr_en ( fifo_wr_en ),.fifo_wr_en_pre ( fifo_wr_en_pre ),.fifo_rd_en ( fifo_rd_en ),.fifo_rd_en_pre ( fifo_rd_en_pre ));//=======================================ip_ram u_ip_ram (.clk ( clk ),.rst_n ( rst_n ),.fifo_rd_en_pre ( fifo_rd_en_pre ),.fifo_dout ( fifo_dout ),.ram_douta ( ram_douta ));endmodule
FIFO顶层文件
module ip_fifo(input clk ,input rst_n ,input [15:0] fifo_din ,output [15 : 0] fifo_dout ,output fifo_wr_en ,output fifo_wr_en_pre ,output fifo_rd_en , output [1:0] fifo_rd_en_pre );// wire [15 : 0] fifo_dout ;wire full ;wire empty ;wire [9 : 0] data_count ;// wire fifo_wr_en ;wire almost_full ;wire almost_empty ;fifo_generator_0 u_fifo (.clk (clk), // input wire clk.din (fifo_din), // input wire [15 : 0] din.wr_en (fifo_wr_en), // input wire wr_en.rd_en (fifo_rd_en), // input wire rd_en.dout (fifo_dout), // output wire [15 : 0] dout.full (full), // output wire full.almost_full (almost_full), // output wire almost_full.empty (empty), // output wire empty.almost_empty (almost_empty), // output wire almost_empty.data_count (data_count) // output wire [9 : 0] data_count
);fifo_wr u_fifo_wr (.clk ( clk ),.rst_n ( rst_n ),.almost_empty ( almost_empty ),.almost_full ( almost_full ),.fifo_din ( fifo_din ),.fifo_wr_en_pre ( fifo_wr_en_pre ),.fifo_wr_en ( fifo_wr_en )
);fifo_rd u_fifo_rd (.clk ( clk ),.rst_n ( rst_n ),.fifo_out ( fifo_dout ),.almost_full ( almost_full ),.almost_empty ( almost_empty ),.fifo_rd_en ( fifo_rd_en ),.fifo_rd_en_pre ( fifo_rd_en_pre )
);endmodule
FIFO读
module fifo_rd(input clk,input rst_n,input [15:0] fifo_out,input almost_full,input almost_empty,output reg fifo_rd_en,output reg [1:0] fifo_rd_en_pre);// reg fifo_rd_en;reg [1:0] state;reg almost_full_d0;reg almost_full_syn;reg [3:0] dly_cnt;always @(posedge clk ) beginif (!rst_n) beginalmost_full_d0 <= 1'b0;almost_full_syn <= 1'b0;endelse beginalmost_full_d0 <= almost_full;almost_full_syn <= almost_full_d0;endendalways @(posedge clk ) beginif (!rst_n) beginfifo_rd_en_pre[0] <= 1'b0;state <= 2'd0; dly_cnt <= 4'd0;endelsecase (state)2'd0: if(almost_full_syn)state <= 2'd1;elsestate <= state;2'd1:if (dly_cnt == 4'd9) begindly_cnt <= 4'd0;state <= 2'd2;endelsedly_cnt <= dly_cnt +1'b1;2'd2:if (almost_empty) beginfifo_rd_en_pre[0] <= 1'b0;state <= 2'd3; endelsefifo_rd_en_pre[0] <= 1'b1;2'd3:state <= state;default: state <= 2'd0;endcaseendalways @(posedge clk ) beginfifo_rd_en_pre[1] <= fifo_rd_en_pre[0];fifo_rd_en <= fifo_rd_en_pre[1];endendmodule
FIFO写
module fifo_wr(input clk,input rst_n,input almost_empty,input almost_full,input [15:0] fifo_din ,output reg fifo_wr_en, output reg fifo_wr_en_pre // 涓轰簡娑堥櫎鎵撲竴鎷嶅fifo杈撳叆鐨勫奖鍝�);reg [1:0] state;reg almost_empty_d0;reg almost_empty_syn;reg [3:0] dly_cnt;reg [15:0] fifo_wr_data;// always @(posedge clk ) beginif (!rst_n) beginalmost_empty_d0 <= 1'b0;almost_empty_syn <= 1'b0;endelse beginalmost_empty_d0 <= almost_empty;almost_empty_syn <= almost_empty_d0;endendalways @(posedge clk ) beginif (!rst_n) beginfifo_wr_en_pre <= 1'b0;fifo_wr_data <=16'd0;state <= 2'd0;dly_cnt <= 4'd0;endelse begincase (state)// 绛夊緟FIFO绌轰俊鍙�2'd0: if (almost_empty_syn) state <= 2'd1;elsestate <= state;// 寤舵椂2'd1:if (dly_cnt == 4'd9) begindly_cnt <= 4'd0;state <= 2'd2;fifo_wr_en_pre <= 1'b0; // 姝ゅ涓�1鐨勮瘽锛屽垯榛樿鏁版嵁浼氳鍐欏叆endelsedly_cnt <= dly_cnt +4'd1;// 鍐欐暟鎹�2'd2:if (almost_full) beginfifo_wr_en_pre <=1'b0;fifo_wr_data <= 16'h0;state <= 2'd3;end else beginfifo_wr_en_pre <=1'b1;fifo_wr_data <= fifo_wr_data +1'd1;end// 姝诲惊鐜�2'd3:state <= state;default: state <= 2'd0;endcaseendendalways @(posedge clk ) beginfifo_wr_en <= fifo_wr_en_pre;end
endmodule
RAM顶层文件
module ip_ram(input clk ,input rst_n ,input [15:0] fifo_dout , input [1:0] fifo_rd_en_pre ,output [27 : 0] ram_douta);// ==========rom==============reg [9:0] rom_addra;reg [9:0] rom_addra_pre;wire [10 : 0] rom_douta;reg rom_ena;//===========ram ==============reg ram_ena ;reg [0 : 0] ram_wea ;reg [9 : 0] ram_addra ;reg [27 : 0] ram_dina ;//=============================reg [1:0] state;parameter START = 2'd0, WRITE = 2'd1, READ = 2'd2, WAIT = 2'd3;reg [9:0] ram_read_counter;always @(posedge clk ) beginif(!rst_n) beginram_read_counter <= 10'b0;endelse beginif(state == READ)ram_read_counter <= ram_read_counter + 1'b1;endendalways @(posedge clk ) beginif(!rst_n)beginstate <= START;endelse begincase(state)START:if (fifo_rd_en_pre[0] == 1'b1) beginstate <= WRITE;endelse beginstate <=state;end// 鍐檙amWRITE:if (fifo_rd_en_pre[0] == 1'b1) beginstate <= state;endelse beginstate <= READ;end// read ramREAD:if(ram_read_counter == 10'd1023)state <= WAIT;elsestate <= state;// if (fifo_rd_en_pre[0] == 1'b0) begin// state <= state;// end// else begin// state <= WAIT;// endWAIT:state <= state;default:state <= START;endcaseendendalways @(posedge clk ) beginif(!rst_n) beginram_wea <= 1'b0;endelse begincase (state)START: ram_wea <= 1'b0;WRITE: ram_wea <= 1'b1;READ : ram_wea <= 1'b0;WAIT : ram_wea <= 1'b0;default: ram_wea <= 1'b0;endcaseendendalways @(posedge clk ) beginif(!rst_n) beginram_ena <= 1'b0;endelse begincase (state)START: ram_ena <= 1'b0;WRITE: ram_ena <= 1'b1;READ : ram_ena <= 1'b1;WAIT : ram_ena <= 1'b0;default: ram_ena <= 1'b0;endcaseendendalways @(posedge clk ) beginif(!rst_n)beginram_addra <= 10'b0;endelse begincase (state)START: ram_addra <= 10'b0;WRITE: ram_addra <= rom_douta;READ : ram_addra <= ram_addra + 1'b1;WAIT : ram_addra <= 10'b0;default: ram_addra <= 10'b0;endcaseendendalways @(posedge clk ) beginif(!rst_n)beginram_dina <= 28'b0;endelse begincase (state)START: ram_dina <= 28'b0;WRITE: ram_dina <= fifo_dout;READ : ram_dina <= 28'b0;WAIT : ram_dina <= 28'b0;default: ram_dina <= 28'b0;endcaseendendram_wr u_ram_wr (.clk ( clk ),.rst_n ( rst_n ),.fifo_dout ( fifo_dout ),.fifo_rd_en_pre ( fifo_rd_en_pre ),.rom_douta ( rom_douta ),.ram_ena ( ram_ena ),.ram_wea ( ram_wea ),.ram_addra ( ram_addra ),.ram_dina ( ram_dina ));blk_mem_gen_0 u_ram (.clka (clk), // input wire clka.ena (ram_ena), // input wire ena.wea (ram_wea), // input wire [0 : 0] wea.addra (ram_addra), // input wire [9 : 0] addra.dina (ram_dina), // input wire [27 : 0] dina.douta (ram_douta) // output wire [27 : 0] douta);// ============rom==============================always @(posedge clk ) beginif(!rst_n)beginrom_ena <= 1'b0;endelse begincase (state)START: rom_ena <= 1'b0;WRITE: rom_ena <= 1'b1;READ : rom_ena <= 1'b0;WAIT : rom_ena <= 1'b0;default: rom_ena <= 1'b0;endcaseendendalways @(posedge clk ) beginif(!rst_n)beginrom_addra <= 10'b0;rom_addra_pre <= 10'b0;endelse begincase (state)START: rom_addra_pre <= 10'b0;WRITE: rom_addra_pre <= rom_addra_pre + 1'b1;READ : rom_addra_pre <= 10'b0;WAIT : rom_addra_pre <= 10'b0;default: rom_addra_pre <= 10'b0;endcaserom_addra <= rom_addra_pre; // 鐢变簬ena鏃讹紝addr浠�1寮�濮嬶紝鎵�浠ユ墦涓媿瀛愪粠0寮�濮�endendblk_mem_gen_1 u_rom (.clka (clk) , // input wire clka.ena (rom_ena) , // input wire ena.addra (rom_addra) , // input wire [9 : 0] addra.douta (rom_douta) // output wire [10 : 0] douta);// =====================================endmodule
8 IP配置
FIFO
RAM
ROM
9 Reference
- 李汉清. 基于FPGA的快速原地转置算法. 电子测量技术. 2015;38(11):46-50.
都看到这了,点个赞吧!