Verilog实现FIFO设计(一)之同步8位深度

最近学习verilog设计FIFO,记录一下。

一. 设计原理

FIFO( First in First out) 使用在需要产生数据接口的部分,用来存储、缓冲在两个异步时钟之间的数据传输。在异步电路中,由于时钟之间周期和相位完全独立,因此数据丢失概率不为零。使用 FIFO 可以在两个不同时钟域系统之间快速而方便地传输实时数据。这次的设计我们就来学习一下设计一个 8 位 8 深度的 同步FIFO。
FIFO 的原理框图如下图所示:
在这里插入图片描述
我们看到图中有一个具有独立的读端口和独立的写端口的 RAM 存储器。这样选择是为了分析方便。如果是一个单端口的存储器,还应包含一个仲裁器,保证同一时刻只能进行一项操作(读或写),我们选择双口 RAM(无需真正的双口 RAM,因为我们只是希望有一个简单的相互独立的读写端口)是因为这些实例非常接近实际情况。

读、写端口拥有两个计数器( wr_ptr、 rd_ptr)产生的互相独立的读、写地址。计数器的值在读写使能信号来临时传递给“ 读指针” ( rd)和“ 写指针” ( wr)。写指针指向下一个将要写入的位置,读指针指向下一个将要读取的位置。每次写操作使写指针加 1,读操作使读指针加1。左右两侧的模块为读写指针与满空信号产生模块。这两个模块的任务是给 FIFO 提供“ 空”( empty)和“ 满” ( full)信号。这些信号告诉外部电路 FIFO 已经达到了临界条件:如果出现“ 满” 信号,那么 FIFO 为写操作的临界状态,如果出现“ 空” 信号,则 FIFO 为读操作的临界状态。写操作的临界状态表示 FIFO 已经没有空间来存储更多的数据,读操作的临界表示 FIFO 没有更多的数据可以读出。读写指针与满空信号产生模块还可告诉 FIFO 中“ 满”或“ 空” 位置的数值。这是由指针的算术运算来完成了。实际的“ 满” 或“ 空” 位置计算并不是为 FIFO 自身提供的。它是作为一个报告机构给外部电路用的。

功能上看, FIFO 的工作原理如下所述:复位时,读、写指针均为 0。这是 FIFO 的空状态,空标志( empty)为高电平,此时满标志( full)为低电平。当 FIFO 出现空标志( empty)时,不允许读操作,只能允许写操作。写操作写入到位置 0,并使写指针加 1。此时,空标志( empty)变为低电平。假设没有发生读操作且随后的一段时间中 FIFO 只有写操作,一定时间后,写指针的值等于 7。这就意味着在存储器中,要写入数据的最后一个位置就是下一个位置。在这种情况下,写操作将写指针变为 0,并将输出满标志( full)。

为了更好地判断空状态和满状态,这里设置一个四位的计数器( sfifo_cnt),代表存储器( mem)中写入但还未读取的数据个数。当 FIFO 未进行任何读写操作时,计数器保持不变;当进行写操作时,计数器加 1;当进行读操作时,计数器减 1;当同时进行写操作和读操作时,计数器值保持不变。这样就可以根据计数器中的值来判断状态的空与满,即:当计时器 sfifo_cnt=0 时,表示存储器处于空状态,输出空标志( empty);当计数器 sfifo_cnt=8时,表示存储器处于满状态,输出满标志( full)。

二. 设计要求

读写指针都指向一个内存的初始位置,每进行一次读写操作,相应的指针就递增一次,指向下一个内存位置。当指针移动到了内存的最后一个位置时,它又重新跳回初始位置。在FIFO 非满或非空的情况下,这个过程将随着读写控制信号的变化一直进行下去。如果 FIFO处于空的状态,下一个读动作将会导致向下溢(underflow),一个无效的数据被读入;同样,对于一个满了的 FIFO,进行写动作将会导致向上溢出(overflow),一个有用的数据被新写入的数据覆盖。这两种情况都属于误动作,因此需要设置满和空两个信号,对满信号置位表示FIFO 处于满状态,对满信号复位表示 FIFO 非满,还有空间可以写入数据;对空信号置位表示 FIFO 处于空状态,对空信号复位表示 FIFO 非空,还有有效的数据可以读出。设计波形如图所示。
在这里插入图片描述

三. 设计流程

3.1 模型

3.1.1 模块设计

在这里插入图片描述

3.1.2 引脚说明

在这里插入图片描述

3.1.3 算法设计

已添加注释:

module sfifo(
	clk,
	rst_n,
	data_in,
	wr,
	rd,
	full,
	empty,
	data_out,
	sfifo_cnt);

	input clk;
	input rst_n;
	input [7:0] data_in;
	input wr;
	input rd;
	output full;
	output empty;
	output [7:0] data_out;
	output [3:0] sfifo_cnt;

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

	`define DEL 1 // Clock-to-output delay
	
	reg [7:0] sfifo_ram[0:7];  // sfifo_ram initialized
	reg [2:0] rd_ptr;  // Read pointer
	reg [2:0] wr_ptr;  // Write pointer 
	
	assign empty = ( sfifo_cnt == 0 ) ? 1 : 0;  //Empty signal
	assign full  = ( sfifo_cnt == 8 ) ? 1 : 0;  //Full signal
	
	// sfifo_cnt changed
	// While rd is valid, cnt--
	// While wr is valid, cnt++
	always @( posedge clk or negedge rst_n) begin
	  if( ~rst_n ) begin
	    sfifo_cnt <= #`DEL 4'h0;
	  end
	  else if( rd && ~wr ) begin
	    sfifo_cnt <= #`DEL sfifo_cnt - 1;
	  end
	  else if( ~rd && wr ) begin
	    sfifo_cnt <= #`DEL sfifo_cnt + 1;
	  end
	  else begin 
	    sfifo_cnt <= sfifo_cnt;
	  end
	end      
	
	/*
	
	//
	// The change of sfifo_cnt can also be written like below.
	//
	always @( posedge clk or negedge rst_n) begin
	  if( ~rst_n ) begin
	    sfifo_cnt <= #`DEL 4'h0;
	  end
	  else begin
	    case({ wr,rd })
	      2'b00 : sfifo_cnt <= #`DEL sfifo_cnt;
	      2'b01 : sfifo_cnt <= #`DEL (sfifo_cnt==0) ? 0 : fifo_cnt-1;
	      2'b10 : sfifo_cnt <= #`DEL (sfifo_cnt==8) ? 8 : fifo_cnt+1;
	      2'b11 : sfifo_cnt<=sfifo_cnt;
	      default: sfifo_cnt <= sfifo_cnt;
	    endcase
	  end
	end    
	
	*/
	
	// Increment of rd_ptr 
	// Check if the read pointer has gone beyond the depth of fifo  
	always @( posedge clk or negedge rst_n) begin
	  if( ~rst_n ) begin
	    rd_ptr <= #`DEL 3'h0;
	  end
	  else if( rd ) begin
	    if( rd_ptr == 3'h7 ) begin
	      rd_ptr <= #`DEL 3'h0;
	    end
	    else begin
	      rd_ptr <= #`DEL rd_ptr +1;
	    end
	  end
	  else begin
	    rd_ptr <= rd_ptr;
	  end
	end    
	
	// Increment of wr_ptr 
	// Check if the write pointer has gone beyond the depth of fifo  
	always @( posedge clk or negedge rst_n) begin
	  if( ~rst_n ) begin
	    wr_ptr <= #`DEL 3'h0;
	  end
	  else if( wr ) begin
	    if( wr_ptr == 3'h7 ) begin
	      wr_ptr <= #`DEL 3'h0;
	    end
	    else begin
	      wr_ptr <= #`DEL wr_ptr +1;
	    end
	  end
	  else begin
	    wr_ptr <= wr_ptr;
	  end
	end 
	
	/*
	
	//
	// The incerment of pointer can also be written like below. 
	//
	always @( posedge clk or negedge rst_n) begin
	  if( ~rst_n ) begin
	    wr_ptr <= #`DEL 3'h0;
	    rd_ptr <= #`DEL 3'h0;
	  end
	  else begin
	    wr_ptr <= #`DEL wr ? wr_ptr + 1 : wr_ptr;
	    rd_ptr <= #`DEL rd ? rd_ptr + 1 : rd_ptr;
	  end
	end    
	
	*/
	
	//
	// Deal with the data 
	//
	always @( posedge clk or negedge rst_n) begin
	  if( ~rst_n ) begin
	    data_out <= #`DEL 8'h0;
	  end
	  else if( wr ) begin
	    sfifo_ram[wr_ptr] <= #`DEL data_in;
	  end
	  else if( rd ) begin 
	    data_out <= #`DEL sfifo_ram[rd_ptr];
	  end
	end      
	
	
endmodule    //sfifo

3.2 测试模块

3.2.1 模块设计

在这里插入图片描述

3.2.2 引脚说明

在这里插入图片描述

3.1.3 激励输入

这里测试代码写的比较简单,下一篇文章有详细的设计代码。

module sfifo_test();

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

	initial begin
	  rst_n=1;
	  clk=0;
	  wr=0;
	  rd=0;
	  data_in=0;
	  #1 rst_n=0;
	  #5 rst_n=1;
	  #3 wr=1;
	  #5 rd=1;
	  #5 rd=0;
	  #5 wr=0;
	  #5 wr=1;
	  #10 rd=1;
	  #10 rd=0;
	  #14 $finish;
	end
	always begin
	  #5 clk=~clk;
	end
	always @(posedge clk or negedge rst_n) begin
	  if (~rst_n) begin
	    data_in<=0;
	    wr<=0;
	    rd<=0;
	  end
	  else begin
	    data_in<=$random;
	  end
	end
	
	initial begin
		$dumpfile ("F:/Robei/practice/prac_07_sfifo/sfifo_test.vcd");
		$dumpvars;
	end
	//---Module instantiation---
	sfifo sfifo1(
		.clk(clk),
		.rst_n(rst_n),
		.data_in(data_in),
		.wr(wr),
		.rd(rd),
		.full(full),
		.empty(empty),
		.data_out(data_out),
		.sfifo_cnt(sfifo_cnt));

endmodule    //sfifo_test

3.2.4 仿真查看波形

在这里插入图片描述
以上就实现了8位同步fifo的设计~

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值