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求和原理

  • 21
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
下面是一个使用 Verilog 编写的简单的 FIFO 求和代码示例: ```verilog module FIFO_Sum ( input wire clk, input wire rst, input wire en, input wire [7:0] data_in, output wire [7:0] sum ); parameter DEPTH = 8; // FIFO的深度 reg [7:0] fifo [DEPTH-1:0]; reg [2:0] wr_ptr; reg [2:0] rd_ptr; reg [7:0] sum_reg; reg [2:0] count; always @(posedge clk or posedge rst) begin if (rst) begin wr_ptr <= 0; rd_ptr <= 0; sum_reg <= 0; count <= 0; end else if (en) begin if (count < DEPTH) begin fifo[wr_ptr] <= data_in; wr_ptr <= wr_ptr + 1; count <= count + 1; end if (count > 0) begin sum_reg <= sum_reg + fifo[rd_ptr]; rd_ptr <= rd_ptr + 1; count <= count - 1; end end end assign sum = sum_reg; endmodule ``` 上述代码实现了一个深度为 8 的 FIFO 求和模块。输入信号包括时钟 `clk`、复位信号 `rst`、使能信号 `en` 和数据输入信号 `data_in`。输出信号为求和结果 `sum`。 模块中定义了一个长度为 `DEPTH` 的 reg 数组 `fifo`,用于存储输入数据。`wr_ptr` 和 `rd_ptr` 分别表示写指针和读指针,用于控制数据的写入和读取。`sum_reg` 用于存储求和结果。`count` 记录当前 FIFO 中的数据数量。 在时钟上升沿或复位信号上升沿时,根据使能信号的状态,进行数据的写入和读取操作。当使能信号有效时,如果 FIFO 未满,将输入数据写入 FIFO,并更新写指针和数据数量;如果 FIFO 非空,从 FIFO 中读取数据并进行求和操作,同时更新读指针和数据数量。 最后,将求和结果赋值给输出信号 `sum`。 请注意,这只是一个简单的示例代码,可能需要根据实际需求进行修改和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张明阳.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值