这里写目录标题
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:32
miu1_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*32
fwrite(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*32
b(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:N
if(i == N)
fprintf(fid,'%d;',addr_t(i));
else
fprintf(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 begin
clk=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]);
#100
rst_n=1;
end
always #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) begin
if (!rst_n) begin
count <= 1'b0;
dati_in <= 1'b0;
datq_in <= 1'b0;
end
else if ( fifo_wr_en_pre ) begin
dati_in <= data_real[count];
datq_in <= data_imag[count];
count <= count+1'b1;
end
else begin
count <= count ;
dati_in <= dati_in ;
datq_in <= datq_in ;
end
end
endmodule
顶层文件
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 ) begin
if (!rst_n) begin
almost_full_d0 <= 1'b0;
almost_full_syn <= 1'b0;
end
else begin
almost_full_d0 <= almost_full;
almost_full_syn <= almost_full_d0;
end
end
always @(posedge clk ) begin
if (!rst_n) begin
fifo_rd_en_pre[0] <= 1'b0;
state <= 2'd0;
dly_cnt <= 4'd0;
end
else
case (state)
2'd0:
if(almost_full_syn)
state <= 2'd1;
else
state <= state;
2'd1:
if (dly_cnt == 4'd9) begin
dly_cnt <= 4'd0;
state <= 2'd2;
end
else
dly_cnt <= dly_cnt +1'b1;
2'd2:
if (almost_empty) begin
fifo_rd_en_pre[0] <= 1'b0;
state <= 2'd3;
end
else
fifo_rd_en_pre[0] <= 1'b1;
2'd3:
state <= state;
default:
state <= 2'd0;
endcase
end
always @(posedge clk ) begin
fifo_rd_en_pre[1] <= fifo_rd_en_pre[0];
fifo_rd_en <= fifo_rd_en_pre[1];
end
endmodule
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 ) begin
if (!rst_n) begin
almost_empty_d0 <= 1'b0;
almost_empty_syn <= 1'b0;
end
else begin
almost_empty_d0 <= almost_empty;
almost_empty_syn <= almost_empty_d0;
end
end
always @(posedge clk ) begin
if (!rst_n) begin
fifo_wr_en_pre <= 1'b0;
fifo_wr_data <=16'd0;
state <= 2'd0;
dly_cnt <= 4'd0;
end
else begin
case (state)
// 绛夊緟FIFO绌轰俊鍙�
2'd0:
if (almost_empty_syn)
state <= 2'd1;
else
state <= state;
// 寤舵椂
2'd1:
if (dly_cnt == 4'd9) begin
dly_cnt <= 4'd0;
state <= 2'd2;
fifo_wr_en_pre <= 1'b0; // 姝ゅ涓�1鐨勮瘽锛屽垯榛樿鏁版嵁浼氳鍐欏叆
end
else
dly_cnt <= dly_cnt +4'd1;
// 鍐欐暟鎹�
2'd2:
if (almost_full) begin
fifo_wr_en_pre <=1'b0;
fifo_wr_data <= 16'h0;
state <= 2'd3;
end
else begin
fifo_wr_en_pre <=1'b1;
fifo_wr_data <= fifo_wr_data +1'd1;
end
// 姝诲惊鐜�
2'd3:
state <= state;
default:
state <= 2'd0;
endcase
end
end
always @(posedge clk ) begin
fifo_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 ) begin
if(!rst_n) begin
ram_read_counter <= 10'b0;
end
else begin
if(state == READ)
ram_read_counter <= ram_read_counter + 1'b1;
end
end
always @(posedge clk ) begin
if(!rst_n)begin
state <= START;
end
else begin
case(state)
START:
if (fifo_rd_en_pre[0] == 1'b1) begin
state <= WRITE;
end
else begin
state <=state;
end
// 鍐檙am
WRITE:
if (fifo_rd_en_pre[0] == 1'b1) begin
state <= state;
end
else begin
state <= READ;
end
// read ram
READ:
if(ram_read_counter == 10'd1023)
state <= WAIT;
else
state <= state;
// if (fifo_rd_en_pre[0] == 1'b0) begin
// state <= state;
// end
// else begin
// state <= WAIT;
// end
WAIT:
state <= state;
default:
state <= START;
endcase
end
end
always @(posedge clk ) begin
if(!rst_n) begin
ram_wea <= 1'b0;
end
else begin
case (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;
endcase
end
end
always @(posedge clk ) begin
if(!rst_n) begin
ram_ena <= 1'b0;
end
else begin
case (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;
endcase
end
end
always @(posedge clk ) begin
if(!rst_n)begin
ram_addra <= 10'b0;
end
else begin
case (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;
endcase
end
end
always @(posedge clk ) begin
if(!rst_n)begin
ram_dina <= 28'b0;
end
else begin
case (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;
endcase
end
end
ram_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 ) begin
if(!rst_n)begin
rom_ena <= 1'b0;
end
else begin
case (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;
endcase
end
end
always @(posedge clk ) begin
if(!rst_n)begin
rom_addra <= 10'b0;
rom_addra_pre <= 10'b0;
end
else begin
case (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;
endcase
rom_addra <= rom_addra_pre; // 鐢变簬ena鏃讹紝addr浠�1寮�濮嬶紝鎵�浠ユ墦涓媿瀛愪粠0寮�濮�
end
end
blk_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.
都看到这了,点个赞吧!