同步FIFO

 参考:

【新提醒】FIFO学习(转) - chuanshaoke的日志 - EETOP 创芯网论坛 (原名:电子顶级开发网) -

芯动力——硬件加速设计方法_中国大学MOOC(慕课) (icourse163.org)

FIFO的基本概念

FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器。

FIFO实际上是做匹配速率的一个match。

假设数据通道1的速率比数据通道2速率大(即,速率A>速率B)

两个速率不同的数据通道相连,两个数据通道的速率不match。

数据的吞吐率就不够,即在数据通道2,跑不了数据通道1这么多数据,

这时,需要中间一个缓存起来。

数据通道1不是全实时的一个工作,所以建立一个中间的缓冲机制FIFO,让数据进行一个match。 

FIFO的结构

 读写指针宽度

  • 与地址宽度相当
  • 地址增加而溢出后,自动变成0
  • 循环指针

 FIFO的一些重要参数

  • FIFO的深度(FIFO depth):FIFO可以存储多少个N位的数据(如果宽度为N)
  • FIFO的宽度(FIFO width):FIFO一次读写操作的数据位
  • FIFO空标志:IFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
  • FIFO满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)
  • 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。
  • 写时钟:写操作所遵循的时钟,在每个时钟沿来临时写数据。
  • 读指针(Read-pointer):指向下一个读出地址。读完后自动加1。
  • 写指针( Write-pointer):指向下一个要写入的地址的,写完自动加1。

注意:读写指针其实就是读写的地址,只不过这个地址不能任意选择,而是连续的。

FIFO分类

根均FIFO工作的时钟域,可以将FIFO分为:

  • 同步FIFO:数据写入FIFO的时钟和数据读出FIFO的时钟是同步的(synchronous)
  • 异步FIFO:数据写入FIFO的时钟和数据读出FIFO的时钟是异步的(asynchronous)

同步FIFO

同步FIFO:数据写入FIFO的时钟和数据读出FIFO的时钟是同步的(synchronous)

同步FIFO结构

  同步FIFO的一些重要参数

  • 时钟复位,clk,rst_n_i,读写应用同一个时钟;
  • FIFO宽度,用参数FIFO_data_size表示,也就是FIFO存储的数据宽度;
  • FIFO深度,用参数FIFO_addr_size表示,也就是地址的大小,也就是说能存储多少个数据;
  • 读使能,rd_en_i
  • 写使能,wr_en_i
  • 写地址指针wr_pointer,由自动加一生成,将数据写入该地址;
  • 读地址指针rd_pointer,由自动加一生成,将该地址上的数据读出;
  • 计数器fifo_counter,用计数器来进行空满标志的判断;
  • 满标志,full,当FIFO中的数据满了以后将不再能进行数据的写入;
  • 空标志empty,当FIFO为空的时候将不能进行数据的读出;

同步FIFO的空满判断:

使用计数器fifo_counter记录FIFO RAM中的数据个数:

  1. fifo_counter=0,给出empty信号
  2. fifo_counter=FIFO_addr_size,给出full信号

计数器fifo_counter计数:

  1. 写而未满时增加1
  2. 读而未空时减1
  3. 同时发生读写操作时,fifo_counter计数不变

同步FIFO的Verilog描述

存储数据的FIFO用双端口RAM表示:

reg [FIFO_data_size - 1:0] register_array [0:FIFO_addr_size-1];
//memory depth,有多少个单元  FIFO_addr_size个存储单元
//memory width,一个存储单元有多少位  FIFO_data_size位

判断空满标志:

//计数器计数count
always@(posedge clk or negedge rst_n_i)
  	if(!rst_n_i)
  		count<=0;
  	else if(wr_en_i && rd_en_i && !full_o && !empty_o)//同时读写不变
				count<=count;
		else if(wr_en_i && !rd_en_i && !full_o)//写而未满+1
				count<=count+1;
		else if(!wr_en_i && rd_en_i  && !empty_o)//读而未空-1
				count<=count-1;
				
 //generate flags
	assign full_o = (count == FIFO_addr_size);
	assign empty_o = (count == 0);

写数据:

//write pointer
  always@(posedge clk or negedge rst_n_i)
  if(!rst_n_i)
  	   wr_point<=0;
  else if(wr_en_i &&  !full_o)
				wr_point <= wr_point+1;
	else
		    wr_point <= wr_point;

//write data
interger i;
always@(posedge clk or negedge rst_n_i)
begin
  	if(!rst_n_i)
  	  begin
  		  for(i=0;i<addr;i=i+1)begin
  		  	register_array[i] <= 0;
  		  end	
  		end		
  	else if(wr_en_i && !full_o)//写使能,且存储单元没满
			register_array[wr_point] <= wr_data_i;
end

读数据:

//read pointer
	always@(posedge clk or negedge rst_n_i)
		if(!rst_n_i)
  		rd_point<=0;
    else if(rd_en_i &&  !empty_o)
				rd_point <= rd_point+1;
		else
		    rd_point <= rd_point;
//read data
	always@(posedge clk or negedge rst_n_i)
  	if(!rst_n_i)
  	  begin
  		  	rd_data_o<= 0;
  		end		
  	else if(rd_en_i && !empty_o)//读使能,且存储单元没空
			rd_data_o<=register_array[rd_point] ;

 完整的同步FIFO代码

module sync_fifo
#(parameter FIFO_data_size = 32, parameter ADDR_WIDTH=3)
(
//reset signal  input   negedge active
  input rst_n_i,
//clock
  input clk,
//write interface
  input wire                       wr_en_i,   //write enable
  input wire  [FIFO_data_size-1:0] wr_data_i, //write data
//read interface
  input wire          				rd_en_i,   //read enable
   output reg [FIFO_data_size-1:0] rd_data_o, //read data
//flags
   output full_o,
   output empty_o
);
 parameter FIFO_addr_size = 1<<ADDR_WIDTH; //1<<3=8

//memory definition   use register model
	reg [FIFO_data_size - 1:0] register_array [0:FIFO_addr_size- 1];
//memory depth,有多少个单元  FIFO_addr_size个存储单元
//memory width,一个存储单元有多少位  FIFO_data_size位

//write pointer and read pointer
 reg[ADDR_WIDTH-1:0] wr_point;//例如存储单元0-7,一共8个存储单元 [2:0]
 reg[ADDR_WIDTH-1:0] rd_point;//例如存储单元0-7,一共8个存储单元
 
 reg [ADDR_WIDTH:0] count;
 //计数有0,1,2,3,4,5,6,7,8
 //9个状态,要用[3:0]表示
 
//############################################
//write pointer
  always@(posedge clk or negedge rst_n_i)
  if(!rst_n_i)
  	   wr_point<=0;
  else if(wr_en_i &&  !full_o)
				wr_point <= wr_point+1;
	else
		    wr_point <= wr_point;
//read pointer
	always@(posedge clk or negedge rst_n_i)
		if(!rst_n_i)
  		rd_point<=0;
    else if(rd_en_i &&  !empty_o)
				rd_point <= rd_point+1;
		else
		    rd_point <= rd_point;

//##########################################
//element counter
  always@(posedge clk or negedge rst_n_i)
  	if(!rst_n_i)
  		count<=0;
  	else if(wr_en_i && rd_en_i && !full_o && !empty_o)//同时读写不变
				count<=count;
		else if(wr_en_i && !rd_en_i && !full_o)//写而未满+1
				count<=count+1;
		else if(!wr_en_i && rd_en_i  && !empty_o)//读而未空-1
				count<=count-1;
				
 //generate flags
	assign full_o = (count == addr);
	assign empty_o = (count == 0);
	
//############################################################33
//access arry
//	reg [n-1:0] register_array [0:addr-1];
//memory depth,有多少个单元  addr个存储单元
//memory width,一个存储单元有多少位  n位
//###############################################################
//write data
interger i;

always@(posedge clk or negedge rst_n_i)
begin
  	if(!rst_n_i)
  	  begin
  		  for(i=0;i<addr;i=i+1)begin
  		  	register_array[i] <= 0;
  		  end	
  		end		
  	else if(wr_en_i && !full_o)//写使能,且存储单元没满
			register_array[wr_point] <= wr_data_i;
end
//read data
	always@(posedge clk or negedge rst_n_i)
  	if(!rst_n_i)
  	  begin
  		  	rd_data_o<= 0;
  		end		
  	else if(rd_en_i && !empty_o)//读使能,且存储单元没空
			rd_data_o<=register_array[rd_point] ;
endmodule

参考:

【新提醒】FIFO学习(转) - chuanshaoke的日志 - EETOP 创芯网论坛 (原名:电子顶级开发网) -

芯动力——硬件加速设计方法_中国大学MOOC(慕课) (icourse163.org)


同步FIFO编码练习

练习网站:

 牛客网-在线编程-Verilog练习

 里面还有其他人总结的各种题解,可以自己总结下思路。写完代码可以在线运行,检查自己的代码哪里有问题,

  • 9
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
FPGA 同步 FIFO 是一种用于在 FPGA 设备中实现数据缓冲和数据转移的组件。它由一个读取指针和一个写入指针组成,可以实现读写操作的同步和互斥。 使用 FPGA 同步 FIFO 的一个常见场景是在不同频率的数据传输之间进行数据缓冲和同步。当输入以不同频率产生数据时,为了保证数据的可靠传输和处理,可以使用同步 FIFO 来缓冲输入数据,并在输出端以相同或不同的频率读取数据。 FPGA 同步 FIFO 的实现可以采用 FPGA 内部的存储单元,如 Block RAM 或 Distributed RAM。写入操作将数据写入 FIFO 的写入指针所指向的位置,并将写入指针前移。读取操作将数据从 FIFO 的读取指针所指向的位置读取出来,并将读取指针前移。读写指针的移动是同步的,以保证数据的正确性和完整性。 FPGA 同步 FIFO 的大小通常取决于数据传输的需求和 FPGA 设备的资源限制。可以根据数据产生和处理的速度来确定 FIFO 的大小,并且需要根据需要调整读写指针的顺序和移动策略,以满足数据的传输需求。 尽管 FPGA 同步 FIFO 在数据传输中起到了重要的作用,但同时也会增加设计的复杂性和资源消耗。在使用 FPGA 同步 FIFO 时,需要注意处理数据的同步和互斥问题,以及避免出现数据丢失、溢出等异常情况。 总之,FPGA 同步 FIFO 是一种用于实现数据缓冲和转移的组件,在不同频率的数据传输中发挥了关键作用。它可以通过读写指针的同步移动来保证数据的可靠性和完整性,并且可根据需求和硬件资源进行灵活调整。但同时也需要注意处理同步和互斥问题,以确保数据的正确传输。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值