FIFO求和实验

前言

FIFO(先进先出)队列在图像处理中的应用非常广泛,特别是在需要处理实时数据流和保证数据顺序的场景中。以下是一些具体应用实例:在实时视频流处理中,FIFO队列用于缓存图像帧。这样可以确保图像数据按照捕获顺序被处理,避免因处理延迟导致的图像丢失或混乱。例如,视频监控系统会将捕获到的视频帧存储在FIFO队列中,然后按顺序进行处理和分析。在图像缓冲区管理中,FIFO队列帮助维护图像数据的顺序。这对于处理高分辨率图像或多个图像流的应用非常重要。图像处理系统会将图像数据推送到FIFO队列中,并从中读取数据进行进一步的处理,如滤镜应用或特征提取。在流媒体应用中,例如直播流或视频会议,FIFO队列用于缓存和传输数据包。这样可以保证数据按照传输顺序到达接收端,并且能够有效处理网络抖动或丢包问题。在某些图像处理任务中,尤其是需要批量处理的场景,FIFO队列可以用来管理待处理的图像数据。比如,图像增强或图像拼接任务中,FIFO队列可以保持数据的顺序,并在处理过程中保证一致性。在需要从多个传感器获取数据的系统中,FIFO队列能够处理传感器数据的流入。图像传感器的数据流可以使用FIFO队列缓存,确保数据的顺序和时效性,以便进行实时分析或处理。FIFO队列在图像处理中的主要作用是维护数据的顺序性和实时性,特别是在处理需要高吞吐量和低延迟的数据流时。

正文

一、FIFO求和实验

1.项目需求

电脑模拟产生数据求和矩阵,(5,4)使用RS232将数据发送给FPGA,FPGA通过FIFO进行求和运算,(3行求和),将数据求和结果通过RS232传回电脑。

2.技术介绍

现有一5行4列数据矩阵

FIFO求和,对该矩阵数据,N = 5,M = 4,使X = 3进行列求和运算,得到S(3,4)新矩阵,则S(0,0)=D(0,0)+D(1,0)+D(2,0),S(0,1)= D(0,1)+D(1,1)+D(2,1),S(0,2)=D(0,2)+D(1,2)+D(2,2),S(0,3)=SD(0,3)+D(1,3)+D(2,3),S(1,0)=D(1,0)+D(2,0)+D(3,0)...S(2,0)=D(2,0)+D(3,0)+D(4,0)。(n*m)矩阵转换后变为((n-(x-1)*m))矩阵。

3.顶层架构

4.端口描述

|-------|------------|
| clk | 时钟信号 |
| rst_n | 复位信号 |
| rx | 传输到FPGA的数据 |
| tx | 传输到PC的数据 |

二、代码验证

数据接收

复制代码
module uart_rx(
	input 			clk		,
	input				rst_n 	,
	input				rx			,
	
	output reg[7:0]po_data	,	//接收到的数据
	output reg  	po_flag		//数据输出有效

);

parameter 	uart_btl ='d9600			;//串口波特率
parameter 	clk_shuj ='d50_000_000	;//时钟频率

parameter 	cnt_max  =clk_shuj/uart_btl;

reg 			reg1,reg2,reg3	;//打排延迟周期,消除亚稳态
reg 			flag				;//uart工作信号(uart工作时在工作状态切换后产生一个时钟周期高电平)
reg 			en					;//uart工作使能标志信号(uart工作时在工作状态切换后的下一个时钟周期开始一直拉高,直到检测到停止信号)
reg [15:0]	cnt				;//每比特数据持续时钟周期计数器
reg [3 :0]	bit_cnt			;//数据个数计数器
reg 			bit_flag			;//每bit数据接收有效信号
reg [7 :0]	rx_data			;//存储输入数据
reg			rx_flag			;//输入数据并位结束信号

always@(posedge clk,negedge rst_n)//数据打排1
begin
	if(rst_n == 0)
		reg1 <= 1'b1;
	else
		reg1 <= rx;
end	

always@(posedge clk,negedge rst_n)//数据打排2
begin
	if(rst_n == 0)
		reg2 <= 1'b1;
	else
		reg2 <= reg1;
end	

always@(posedge clk,negedge rst_n)//数据打排3
begin
	if(rst_n == 0)
		reg3 <= 1'b1;
	else
		reg3 <= reg2;
end	

always@(posedge clk,negedge rst_n)//uart工作信号赋值
begin
	if(rst_n == 0)
		flag <= 1'b0;
	else
		if((reg2 == 1'b0)&&(reg3 == 1'b1)&&(en == 1'b0))
			flag <= 1'b1;
		else
			flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//uart工作使能标志信号赋值
begin
	if(rst_n == 0)
		en <= 1'b0;
	else
		if(flag == 1'b1)
			en <= 1'b1;
		else
			if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))
				en <= 1'b0;
			else
				en <= en;
end			

always@(posedge clk,negedge rst_n)//每比特数据持续时钟周期计数器驱动逻辑
begin
	if(rst_n == 0)	
		cnt <= 16'd0;
	else 	
		if((cnt == cnt_max - 1)||(en == 1'b0))
			cnt <= 16'd0;
		else
			cnt = cnt + 1'b1;
end

always@(posedge clk,negedge rst_n)//每比特数据持续时钟周期计数器驱动逻辑
begin
	if(rst_n == 0)	
		bit_flag <= 1'b0;
	else
		if(cnt == cnt_max/2 - 1)
			bit_flag <= 1'b1;
		else
			bit_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//数据个数计数器驱动逻辑
begin
	if(rst_n == 0)	
		bit_cnt <= 4'd0;
	else	
		if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))
			bit_cnt <= 4'd0;
		else 
			if(bit_flag == 1'b1)
				bit_cnt <= bit_cnt + 1'b1;
			else
				bit_cnt <= bit_cnt;
end

always@(posedge clk,negedge rst_n)//接收数据并位
begin
    if(rst_n == 0)
        rx_data <= 8'd0;
    else
        if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
            rx_data <= {reg3,rx_data[7:1]};
end

always@(posedge clk,negedge rst_n)//输入数据并位结束信号
begin
    if(rst_n == 0)
        rx_flag <= 1'b0;
    else 
        if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))
            rx_flag <= 1'b1;
        else
            rx_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//输出数据传递
begin
    if(rst_n == 0)
        po_data <= 8'd0;
    else 
        if(rx_flag == 1'b1)
            po_data <= rx_data;
        else
            po_data <= po_data;
end

always@(posedge clk,negedge rst_n)//输出使能
begin
    if(rst_n == 0)
        po_flag <= 1'b0;
    else 
        po_flag <= rx_flag;
end

endmodule

数据处理

复制代码
module fifo_add(
	input 			clk  		,
	input 			rst_n		,
	input	[7:0]		data		,//rs232传输到FPGA的数据
	input				flag		,
	
	output reg[7:0]data_out	,//求和结果
	output reg		out_flag	 //输出使能
);

parameter l_max = 'd3,//列数
			 h_max = 'd4;//行数

reg	[3:0]l_cnt		;//列计数器	
reg	[3:0]h_cnt		;//行计数器
	
reg	fifo1_en	;//fifo_1写使能	 
reg	[7:0]fifo1_data;//fifo_1写数据

reg	fifo2_en	;//fifo_2写使能	 
reg	[7:0]fifo2_data;//fifo_2写数据
			
reg	rd_en;//读使能信号	
wire	[7:0]data1;	//fifo1读出数据
wire	[7:0]data2;	//fifo2读出数据
reg	add_en;//求和标志信号	
reg	data_flag;//fifo1的写使能信号		

always@(posedge clk,negedge rst_n)//列计数器驱动
begin
	if(rst_n == 0)
		l_cnt <= 4'd0;
	else
		if((l_cnt == l_max)&&(flag == 1'b1))
			l_cnt <= 4'd0;
		else
			if(flag == 1'b1)
				l_cnt <= l_cnt + 4'd1;
			else
				l_cnt <= l_cnt;
end

always@(posedge clk,negedge rst_n)//行计数器驱动
begin
	if(rst_n == 0)
		h_cnt <= 4'd0;
	else
		if((h_cnt == h_max)&&(l_cnt == l_max)&&(flag == 1'b1))
			h_cnt <= 4'd0;
		else
			if((l_cnt == l_max)&&(flag == 1'b1))
				h_cnt <= h_cnt + 4'd1;
			else
				h_cnt <= h_cnt;
end

always@(posedge clk,negedge rst_n)//fifo_1写使能
begin
	if(rst_n == 0)
		fifo1_en <= 1'b0;
	else
		if((h_cnt == 0)&&(flag == 1'b1))
			fifo1_en <= 1'b1;
		else
			fifo1_en <= data_flag;
end

always@(posedge clk,negedge rst_n)//fifo_1写数据
begin
	if(rst_n == 0)
		fifo1_data <= 8'd0;
	else
		if((h_cnt == 0)&&(flag == 1'b1))
			fifo1_data <= data;
		else
			if(data_flag == 1'b1)
				fifo1_data <= data2;
			else
				fifo1_data <= fifo1_data;
end

always@(posedge clk,negedge rst_n)//fifo_2写使能
begin
	if(rst_n == 0)
		fifo2_en <= 1'b0;
	else
		if((h_cnt >= 4'd1)&&(h_cnt <= h_max - 4'd1)&&(flag == 1'b1))
			fifo2_en <= 1'b1;
		else
			fifo2_en <= 1'b0;
end

always@(posedge clk,negedge rst_n)//fifo_2写数据
begin
	if(rst_n == 0)
		fifo2_data <= 8'd0;
	else
		if((h_cnt >= 4'd1)&&(h_cnt <= h_max - 4'd1)&&(flag == 1'b1))
			fifo2_data <= data;
		else
			fifo2_data <= fifo2_data;
end

always@(posedge clk,negedge rst_n)//fifo读写使能(共用)
begin
	if(rst_n == 0)
		rd_en <= 1'b0;
	else
		if((h_cnt >= 4'd2)&&(flag <= h_max)&&(flag == 1'b1))
			rd_en <= 1'b1;
		else
			rd_en <= 1'b0;
end

always@(posedge clk,negedge rst_n)//fifo1的写使能信号	
begin
	if(rst_n == 0)
		data_flag <= 1'b0;
	else
		if((fifo2_en == 1'b1)&&(rd_en == 1'b1))
			data_flag <= 1'b1;
		else
			data_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//求和使能信号	
begin
	if(rst_n == 0)
		add_en <= 1'b0;
	else
		if(rd_en == 1'b1)
			add_en <= 1'b1;
		else
			add_en <= 1'b0;
end

always@(posedge clk,negedge rst_n)//结果输出
begin
	if(rst_n == 0)
		data_out <= 8'd0;
	else
		if(add_en == 1'b1)
			data_out <= data + data1 + data2;
		else
			data_out <= data_out;
end

always@(posedge clk,negedge rst_n)//结果输出使能
begin
	if(rst_n == 0)
		out_flag <= 1'b0;
	else
		out_flag <= add_en;
end

fifo1	fifo1_inst (
	.clock 	( clk  		 ),
	.data 	( fifo1_data ),
	.rdreq 	( rd_en 		 ),
	.wrreq 	( fifo1_en   ),
	
	.q 		( data1 )
	);

fifo1	fifo2_inst (
	.clock 	( clk   		 ),
	.data 	( fifo2_data ),
	.rdreq 	( rd_en      ),
	.wrreq 	( fifo2_en   ),
	
	.q 		( data2 )
	);


endmodule

数据发送

复制代码
module uart_tx(

    input       clk     ,
    input       rst_n   ,
    input [7:0] pi_data ,
    input       pi_flag ,
    
    output reg  tx
);

parameter 	uart_btl ='d9600			;//串口波特率
parameter 	clk_shuj ='d50_000_000	;//时钟频率

parameter 	cnt_max  =clk_shuj/uart_btl;

reg         en      ;
reg [15:0]  cnt     ;//每bit数据传输完成计数器
reg         flag    ;//
reg [3 :0]  bit_cnt ;//bit计数器

always@(posedge clk,negedge rst_n)
begin 
    if(rst_n == 0)
        en <= 1'b0;
    else
        if(pi_flag == 1'b1)
            en <= 1'b1;
        else
            if((bit_cnt == 4'd9)&&(flag == 1'b1))
                en <= 1'b0;
            else 
                en <= en;          
end

always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        cnt <= 16'd0;
    else
        if((en == 1'b0)||(cnt == cnt_max - 1'd2))
            cnt <= 16'd0;
        else
            if(en == 1'b1)
                cnt <= cnt + 1'b1;
            else
                cnt <= cnt;
end

always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        flag <= 1'b0;
    else 
        if(cnt == 16'd1)
           flag <= 1'b1; 
        else
           flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        bit_cnt <= 4'd0;
    else
        if((bit_cnt == 4'd9)&&(flag == 1'b1))
            bit_cnt <= 4'd0;
        else
            if((en == 1'b1)&&(flag == 1'b1))
                bit_cnt <= bit_cnt + 1'b1;
            else
                bit_cnt <= bit_cnt;
end                
            
always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        tx <= 1'b1;
    else
        if(flag == 1'b1)
            case(bit_cnt)
                0:  tx <= 1'b0;
                1:  tx <= pi_data[0];
                2:  tx <= pi_data[1];
                3:  tx <= pi_data[2];
                4:  tx <= pi_data[3];
                5:  tx <= pi_data[4];
                6:  tx <= pi_data[5];
                7:  tx <= pi_data[6];
                8:  tx <= pi_data[7];
                9:  tx <= 1'b1;
                default :tx <= 1'b1;
            endcase    
end

endmodule

顶层文件

复制代码
module fifo_add_top(
	input 			clk  		,
	input 			rst_n		,
	input				rx 		,//rs232传输到FPGA的数据
	
	output			tx    	 //rs232传输到PC的数据
);

wire [7:0]po_data;
wire [7:0]pi_data;
wire pi_flag;
wire po_flag;

fifo_add fifo_add(
	.clk  		(clk  	),
	.rst_n		(rst_n	),
	.data		(po_data	),//rs232传输到FPGA的数据
	.flag		(po_flag	),
	         
	.data_out	(pi_data),//求和结果
	.out_flag	(pi_flag)	 //输出使能
);

uart_tx uart_tx(

    .clk     (clk     ),
    .rst_n   (rst_n   ),
    .pi_data (pi_data ),
    .pi_flag (pi_flag ),
	         
    .tx		(tx		)	
);

uart_rx uart_rx(
	.clk		(clk	),
	.rst_n 	(rst_n ),
	.rx			(rx		),
        
	.po_data	(po_data),	//接收到的数据
	.po_flag	(po_flag)	//数据输出有效

);

endmodule

仿真代码

复制代码
`timescale 1ns/1ps
module fifo_add_top_tb;

	reg 			clk	;
	reg 			rst_n	;
	reg 			rx		;
	reg [7:0]	data_a[19:0];
	
	wire 			tx		;

fifo_add_top fifo_add_top(
	.clk  (clk  ),
	.rst_n(rst_n),
	.rx 	(rx 	),//rs232浼犺緭鍒癋PGA鐨勬暟鎹
	.tx   (tx   ) //rs232浼犺緭鍒癙C鐨勬暟鎹);
);

initial 
	$readmemh("E:/FPGA_exer/fifo_add_0904/doc/data.txt",data_a);//灏嗘暟鎹彁鍙栧埌浠跨湡鏂囦欢鐨勫瓨鍌ㄥ櫒涓
	
initial clk = 1'b1;
always #10 clk = ~clk;


initial begin
	rst_n = 1'b0;
	rx = 1'b1;
	#40
	rst_n = 1'b1;
	#200
	re_byte();
	#100000
	$stop;
end
//璧嬪€煎嚱鏁	
	task	rx_bit(input [7:0]data);
		
	integer i;
 
	for(i = 0;i < 10; i = i + 1)//寰幆9娆			
			begin
				case(i)
					0:  rx <= 1'b0;
					1:  rx <= data[0];
					2:  rx <= data[1];
					3:  rx <= data[2];
					4:  rx <= data[3];
					5:  rx <= data[4];
					6:  rx <= data[5];
					7:  rx <= data[6];
					8:  rx <= data[7];
					9:  rx <= 1'b1;
				endcase
			#(5208*20);//姣忔寤舵椂
			end
	endtask
	
	//defparam fifo_add_top.uart_rx.clk_shuj = 50_000;
	
	task re_byte();
		integer j;
			for(j = 0;j < 20;j = j + 1)
				rx_bit(data_a[j]);//浼犻€鈥斺€锛涓暟鎹	
	endtask


	
	
	
endmodule 

三、仿真验证

运行仿真,将data,data1,data2数据调到一起,观察data_out

观察几组数据4,1,5,=10,5,2,1=8,求和正确,数据传输到RS232数据发送模块,可以看到,数据正常通过tx输出。

输出正常,实验成功。

参考资料

fifo求和原理

相关推荐
FakeOccupational5 小时前
fpga系列 HDL : Microchip FPGA开发软件 Libero 中导出和导入引脚约束配置
fpga开发
贝塔实验室8 小时前
LDPC 码的构造方法
算法·fpga开发·硬件工程·动态规划·信息与通信·信号处理·基带工程
Moonnnn.12 小时前
【FPGA】时序逻辑计数器——仿真验证
fpga开发
三贝勒文子13 小时前
Synopsys 逻辑综合之 ICG
fpga开发·eda·synopsys·时序综合
byte轻骑兵13 小时前
【驱动设计的硬件基础】CPLD和FPGA
fpga开发·cpld
dadaobusi13 小时前
看到一段SVA代码,让AI解释了一下
单片机·嵌入式硬件·fpga开发
G2突破手25913 小时前
FMC、FMC+ 详解
fpga开发
fpga和matlab13 小时前
FPGA时序约束分析4——Reg2Reg路径的建立时间与保持时间分析
fpga开发·reg2reg·建立时间·保持时间
高沉13 小时前
2025华为海思数字IC面经
华为·fpga开发
伊宇韵13 小时前
FPGA - GTX收发器-K码 以及 IBERT IP核使用
fpga开发