异步FIFO(内有Verilog设计及仿真激励代码)

前言:

FIFO本质为RAM,分为同步FIFO(SCFIFO)和异步FIFO(DCFIFO),前者读写用同一个时钟信号,后者则使用双时钟读写。不过同步FIFO实际运用中较为少(可用做数据缓存),一般多用异步FIFO,因为在FPGA设计中,往往都是多时钟系统,很少为单时钟(除非你单纯做一个流水灯之类的简单实验)。这里,笔者给大家做一个简单的异步FIFO实验,供大家参考。(在看这个实验之前建议大家先学习同步FIFO,文字最后面我会附上同步FIFO的实验链接

1. 实验内容
了解掌握DCFIFO的工作原理以及其结构,设计DCFIFO模块以及其test_bench,最后VIVADO进行功能实现和仿真验证。

2. 实验原理
在两个时钟域之间进行数据传递最常用的的使用方法就是异步FIFO。异步FIFO一般包括两个端口,其中端口A是写入端,端口B是读入端。AFIFO中最常用的控制信号是“空”(empty)和“满”(full),另外,“将空”(almost empty)、“将满”(almost full)也是两个经常使用的控制信号。

 **下图为DCFIFO外部链接关系**

DCFIFO外部链接关系
确定DCFIFO的空状态或满状态需要一定的数学处理以及读指针和写指针的比较。关键问题是两个指针在不同的时钟域产生,所以指针必须经过同步化才能在另一时钟域中进行比较和用于计算。对于异步FIFO来说,产生准确的“空”和“满”指示信号是比较困难的,但为了保证操作的安全,避免“满”后仍继续写入和“空”后仍继续读出是可以做到的。
这里为了方便大家理解代码,指针以及满空信号的产生,及为什么要使用格雷码指针,我找了相关资料供大家参考:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上图片资料来源于百度条词:异步FIFO

简单描述二进制与格雷码转换:
二进制数 —————————— 1 0 1 1 0
(进制数右移1位,空位补 0) — 01 0 1 1
异或运算 —————————— 1 1 1 0 1
这样就可以实现二进制到格雷码的转换了,总结就是移位并且异或,verilog代码实现就一句话:assign rgraynext = (rbinnext>>1) ^ rbinnext;

3. 实验代码
①设计代码

module DCFIFO(
	wdata,
	wclk,
	rinc,
	rdata,
	wfull,
	rempty,
	rclk,
	rrst_n,
	wrst_n,
	winc);

	input [7:0] wdata;
	input wclk;
	input rinc;
	output [7:0] rdata;
	output wfull;
	output rempty;
	input rclk;
	input rrst_n;
	input wrst_n;
	input winc;
	
     //输入,输出引脚类型定义
	wire [7:0] wdata;   
	wire wclk;
	wire rinc;
	wire [7:0] rdata;
	reg wfull;
	reg rempty;
	wire rclk;
	wire rrst_n;
	wire wrst_n;
	wire winc;

     
	  reg [4:0] wptr, rptr, wq2_rptr, rq2_wptr, wq1_rptr,rq1_wptr;
	  reg [4:0] rbin, wbin;
	  reg [7:0] mem[0:(1<<4)-1];
	  wire[3:0] waddr, raddr;
	  wire [4:0]  rgraynext, rbinnext,wgraynext,wbinnext;
	  wire  rempty_val,wfull_val;
	   
	 assign rdata=mem[raddr];
	 
	   always@(posedge wclk)
	     if (winc && !wfull)
	       mem[waddr] <= wdata;
	   always @(posedge wclk or negedge wrst_n)
	          if (!wrst_n) 
	           {
    
    wq2_rptr,wq1_rptr} <= 0;
	          else 
	           {
    
    wq2_rptr,wq1_rptr} <= {
    
    wq1_rptr,rptr};
	always @(posedge rclk or negedge rrst_n)
	        if (!rrst_n) 
	          {
    
    rq2_wptr,rq1_wptr} <= 0;
	        else 
	           {
    
    rq2_wptr,rq1_wptr} <= {
    
    rq1_wptr,wptr};
	 always @(posedge rclk or negedge rrst_n) 
	       if (!rrst_n) 
	          {
    
    rbin, rptr} <= 0;
	       else 
	           {
    
    rbin, rptr} <= {
    
    rbinnext, rgraynext};  
	  assign raddr = rbin[3:0];
	  assign rbinnext = rbin + (rinc & ~rempty);
	  assign rgraynext = (rbinnext>>1) ^ rbinnext;   //二进制与格雷码转换
	  assign rempty_val = (rgraynext == ~rq2_wptr);
	   
	  always @(posedge rclk or negedge rrst_n)
	      if (!rrst_n)
	         rempty <= 1'b1;
	      else 
	         rempty <= rempty_val;
	 always @(posedge wclk or negedge wrst_n)
	   if (!wrst_n)
	      {wbin, wptr} <= 0;
	   else 
	       {wbin, wptr} <= {wbinnext, wgraynext};
	   assign waddr = wbin[3:0];
	   assign wbinnext = wbin + (winc & ~wfull);
	   assign wgraynext = (wbinnext>>1) ^ wbinnext;
	   assign wfull_val = (wgraynext=={~wq2_rptr[4:4-1],
	                       wq2_rptr[4-2:0]});
	 always @(posedge wclk or negedge wrst_n)
	     if (!wrst_n) 
	         wfull <= 1'b0;
	     else 
	         wfull <= wfull_val;
	
	
endmodule  

 

设计原理图如下:设计原理图
②仿真激代码

`timescale 1ns/1ns
module DCFIFO_test();

	reg [7:0] wdata;
	reg winc;
	reg wclk;
	reg wrst_n;
	reg rinc;
	reg rclk;
	reg rrst_n;
	wire [7:0] rdata;
	wire wfull;
	wire rempty;


	integer i;
	always begin 
	#10 wclk=1;
	#10 wclk=0;
	end
	always begin
	#15 rclk=1;
	#15 rclk=0;
	end
	initial begin
	wclk=0;rclk=0;wdata=0;winc=0;rinc=0;wrst_n=0;rrst_n=0;i=0;
	#2 winc=1;
	#2 rinc=0;
	for(i=0;i<=20;i=i+1)
	   begin
	   repeat(1)@(posedge wclk);
	    wrst_n=1;
	   wdata=wdata+1;
	   end
	   repeat(1)@(posedge wclk);
	   wrst_n=0;
	#100 rinc=1;
	#2 winc=0;
	for(i=0;i<=20;i=i+1)
	   begin
	   repeat(1)@(posedge rclk);
	   #2;
	   rrst_n=1;
	   end
	repeat(1)@(posedge rclk);
	   #2;
	   rrst_n=0;
	#100 rinc=0;
	#2 $finish;
	   end
	
	
//将设计模块例化到仿真模块中

	DCFIFO DCFIFO1(
		.wdata(wdata),
		.wclk(wclk),
		.rinc(rinc),
		.rdata(rdata),
		.wfull(wfull),
		.rempty(rempty),
		.rclk(rclk),
		.rrst_n(rrst_n),
		.wrst_n(wrst_n),
		.winc(winc));

endmodule   

仿真波形图如下:
仿真波形图
**后续:**因为时间原因代码的注释还没写,后面如果有时间会补上,并对文章进行完整讲解。

这里推荐一位朋友写的同步FIFO,内容很详细,建议大家看学习异步FIFO之前先看这篇文章:verilog实现FIFO设计(一)之同步8位深度

猜你喜欢

转载自blog.csdn.net/weixin_46423500/article/details/106168438