FPGA 矩阵转置

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

  1. 李汉清. 基于FPGA的快速原地转置算法. 电子测量技术. 2015;38(11):46-50.

都看到这了,点个赞吧!

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值