基于Robei EDA实现FIFO(非IP核)及FIFO求和

一、FIFO简介

        FIFO( First in First out) 使用在需要产生数据接口的部分,用来存储、缓冲在两个异步
时钟之间的数据传输
。在异步电路中,由于时钟之间周期和相位完全独立,因此数据丢失概
率不为零。使用 FIFO 可以在两个不同时钟域系统之间快速而方便地传输实时数据。

在此给自己挖个坑:是否以后会遇到FIFO解决不同时钟域用来同步信号


注:上图为异步FIFO

        如果是一个单端口的存储器,还应包含一个仲裁器,保证同一时刻只能进行一项操作(读或写),我们选择双口 RAM(无需真正的双口 RAM,因为我们只是希望有一个简单的相互独立的读写端口)是因为这些实例非常接近实际情况。读、写端口拥有两个计数器( wr_ptr、 rd_ptr)产生的互相独立的读、写地址。计数器的值在读写使能信号来临时传递给“ 读指针” ( rd)和“ 写指针” ( wr)。写指针指向下一个将要写入的位置,读指针指向下一个将要读取的位置。每次写操作使写指针加 1,读操作使读指针加1。左右两侧的模块为读写指针与满空信号产生模块。这两个模块的任务是给 FIFO 提供“ 空”( empty)和“ 满” ( full)信号。这些信号告诉外部电路 FIFO 已经达到了临界条件:如果出现“ 满” 信号,那么 FIFO 为写操作的临界状态,如果出现“ 空” 信号,则 FIFO 为读操作的临界状态。写操作的临界状态表示 FIFO 已经没有空间来存储更多的数据,读操作的临界表示 FIFO 没有更多的数据可以读出。读写指针与满空信号产生模块还可告诉 FIFO 中“ 满”或“ 空” 位置的数值。这是由指针的算术运算来完成了。实际的“ 满” 或“ 空” 位置计算并不是为 FIFO 自身提供的。它是作为一个报告机构给外部电路用的。但是, “ 满” 和“ 空”信号在 FIFO 中却扮演着非常重要的角色,它为了能实现读与写操作各自的独立运行而阻塞性的管理数据的存取。
这种阻塞性管理的重要性不是将数据复写(或重读),而是指针位置。可以控制整个 FIFO,并且使读、写操作改变着指针数值。
FIFO 的工作原理如下所述:复位时,读、写指针均为 0。这是 FIFO 的空状态,空标志(empty)为高电平,此时满标志( full)为低电平。当 FIFO 出现空标志( empty)时,不允许读操作,只能允许写操作。写操作写入到位置 0,并使写指针加 1。此时,空标志( empty)变为低电平。假设没有发生读操作且随后的一段时间中 FIFO 只有写操作,一定时间后,写指针的值等于 7。这就意味着在存储器中,要写入数据的最后一个位置就是下一个位置。在这种情况下,写操作将写指针变为 0,并将输出满标志( full)。

二、同步FIFO框图设计

端口类型作用
clkinput提供时钟信号
resetinput提供复位信号
data_ininput数据输入
wr_eninput写使能信号
rd_eninput读使能信号
fifo_cntoutput还未读出的数据
data_outouput缓存数据输出
fulloutput“满“信号
emptyoutput”空“信号

三、波形图绘制

四、程序编写

多仿真多改正

fifo.v

module fifo(
	clk,
	reset,
	data_in,
	wr_en,
	rd_en,
	full,
	empty,
	data_out,
	fifo_cnt);

	//---Ports declearation: generated by Robei---
	input clk;
	input reset;
	input [7:0] data_in;
	input wr_en;
	input rd_en;
	output full;
	output empty;
	output [7:0] data_out;
	output [3:0] fifo_cnt;

	wire clk;
	wire reset;
	wire [7:0] data_in;
	wire wr_en;
	wire rd_en;
	wire full;
	wire empty;
	reg [7:0] data_out;
	reg [3:0] fifo_cnt;

	//----Code starts here: integrated by Robei-----
	//fifo存储空间
	reg [7:0]fifo_ram[0:7];
	//rd_ptr和wr_ptr指针
	reg [3:0]rd_ptr,wr_ptr;
	
	/*空和满信号产生*/
	assign empty = (fifo_cnt == 0);//存储0个数据
	assign full = (fifo_cnt == 8); //存储8个数据
	/*写操作*/
	always@(posedge clk or negedge reset)
	if(reset == 0)
		begin
			fifo_ram[0]=8'hff;
			fifo_ram[1]=8'hff;
			fifo_ram[2]=8'hff;
			fifo_ram[3]=8'hff;
			fifo_ram[4]=8'hff;
			fifo_ram[5]=8'hff;
			fifo_ram[6]=8'hff;
			fifo_ram[7]=8'hff;
		end
	else if(wr_en == 1 && (!full))    //写信号并且没有满
		fifo_ram[wr_ptr] <= data_in;//数据写入
	else if(wr_en == 1&&rd_en == 1)			//同时读写,只是指针不移动(后面体现)
		fifo_ram[wr_ptr] <= data_in;
	
	/*读操作*/
	always@(posedge clk)
	if(reset == 0)
		data_out <= 0;
	else if((rd_en == 1) && (empty == 0))
		data_out <= fifo_ram[rd_ptr];
	else if(wr_en== 1&&rd_en == 1)   	//同时读写,只是指针不移动(后面体现)
		data_out <= fifo_ram[rd_ptr];	
	else
		data_out <= data_out;
	/*指针移动--wr_ptr*/
	always@(posedge clk)
	if(reset == 0)
		wr_ptr <= 0;
	else if((wr_en == 1) && (full == 0))
		wr_ptr <= wr_ptr + 1'b1;
	else if((wr_en == 1)&&(rd_en == 1))
		wr_ptr <= wr_ptr + 1'b1;
	else if(full)
		wr_ptr <= 0;
	else
		wr_ptr <= wr_ptr;
		//wr_ptr <= ((wr == 1 && full == 0)||((wr==1)&&(rd==1)))?wr_ptr+1:wr_ptr;
	
	/*指针移动--rd_ptr*/
	always@(posedge clk)
	if(reset == 0)
		rd_ptr <= 0;
	else if((rd_en == 1'b1)&&(wr_en == 1'b1))
		rd_ptr <= rd_ptr + 1'b1;
	else if((rd_en == 1'b1)&&(empty == 0))
		rd_ptr <= rd_ptr + 1'b1;
	else if(empty)
		rd_ptr <= 0;
	else
		rd_ptr <= rd_ptr;
		//rd_ptr <= ((rd_en == 1 && empty == 0)||((wr_en==1)&&(rd_en==1)))?rd_ptr+1:rd_ptr;
	
	/*fifo_cnt */
	always@(posedge clk)
	if(reset == 0)
		fifo_cnt <= 0;
	else
		case({wr_en,rd_en})
			2'b00:fifo_cnt <= fifo_cnt;
			2'b01:fifo_cnt <= (fifo_cnt == 0)?0:fifo_cnt - 1;
			2'b10:fifo_cnt <= (fifo_cnt == 8)?8:fifo_cnt + 1;
			2'b11:fifo_cnt <= fifo_cnt;
			default:fifo_cnt <= fifo_cnt;
		endcase
	
	
endmodule    //fifo

fifo_tb.v 

module fifo_tb();

	reg clk;
	reg reset;
	reg [7:0] data_in;
	reg wr;
	reg rd;
	wire full;
	wire empty;
	wire [7:0] data_out;
	wire [3:0] fifo_cnt;

	//----Code starts here: integrated by Robei-----
	always #2  clk =~clk;				//产生时钟
	initial begin
			clk = 1;
	end
	initial begin
	reset =0;
	wr=0;
	rd=0;
	#1 reset=1;
	#3 wr=1;
	#5 rd=1;
	#5 rd=0;
	#5 wr=0;
	#5 wr=1;
	#10 rd=1;
	#10 rd=0;
	
	#3 wr=1;
	#5 rd=1;
	#5 rd=0;
	#5 wr=0;
	#5 wr=0;
	#10 rd=1;
	#10 rd=0;
	  wr=1;
	#4 wr = 0;
	#14 $finish;
	end
	
	always @(posedge clk or negedge reset )
	begin
	if (reset == 0)
	begin
	data_in<=8'hbc;
	wr<=0;
	rd<=0;
	end
	else
	data_in<=$random;
	end
	initial begin
		$dumpfile ("F:/Robei/Robei_study_fifo/fifo_tb.vcd");
		$dumpvars;
	end
	//---Module instantiation---
	fifo fifo1(
		.clk(clk),
		.reset(reset),
		.data_in(data_in),
		.wr_en(wr),
		.rd_en(rd),
		.full(full),
		.empty(empty),
		.data_out(data_out),
		.fifo_cnt(fifo_cnt));

endmodule    //fifo_tb

仿真波形

写在最后,有任何不对的希望及时指正我的错误,感激不尽!

五、FIFO求和原理和方法

为什么要用FIFO求和?

要完成3行数据的SUM求和,需要调用2个FIFO。

六、FIFO求和系统框图

串口收发模块哦我们之前写过,现在光编写fifo求和顶层模块

还在编写ing

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值