一种异步FIFO实现

异步fifo整体模型:

优点:

分别在读、写时钟域判断空、满信号,即时使用状态信号控制fifo的操作,可有效避免读写溢出问题。

在判断空满状态时,本设计使用了格雷码进行比较,可有效避免数据变化时的竞争冒险问题。

在最坏情况下,会造成读、写操作延迟一个时钟周期(格雷码的优势),但不会出现数据读、写错误等现象。

各模块简要介绍:

FIFO Memory:双端口异步ram,fifo控制的存储器,数据缓冲区

FIFO wptr&full:写指针修改器&满信号生成器,控制写指针的操作,及fifo满信号的生成

FIFO rptr&empty :读指针修改器&空信号生成器,控制读指针操作,及fifo空信号的生成

sync_r2w,sync_w2r:两个2级寄存器构成的同步器,用于同步读写指针到各自的时钟域,进而判断空、满状态,

                      这样设计的意图在于避免毛刺

 

主要verilog hdl实现代码如下:

fifo1.v

/*
Filename: fifo1.v
Function: asynchronous fifo full implementation
Author 	: unkonwn
Note		: traveler

Input	:
	wdata	: data to write in
	wclk	: write side clock
	wrst_n:	write side reset signal low enable asynchronous 
	winc	: write enable
	
	rclk	: read side clock
	rrst_n: read side reset signal low enable asynchronous 
	rinc	: read enable
	
Output :
	rdata : output data corresponding to reading
	wfull : write full signal
	rempty: read empty signal
	
*/
module fifo1 #
	(
	//data bus width
	parameter DSIZE = 8,
	
	//address bus width corresponding to the fifo's volume
	parameter ASIZE = 4
	)
	(
	output [DSIZE-1:0] rdata,
	output wfull,
	output rempty,
	input [DSIZE-1:0] wdata,
	input winc, wclk, wrst_n,
	input rinc, rclk, rrst_n
	);
	
	wire [ASIZE-1:0] waddr, raddr;
	wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
	
	//synchronous read pointer to write side by using a 
	//two-flip-flop-synchronizer controled by clock at write side
	sync_r2w sync_r2w (.wq2_rptr(wq2_rptr), 
		.rptr(rptr),.wclk(wclk), .wrst_n(wrst_n));
			
	//synchronous write pointer to read side by using a 
	//two-flip-flop-synchronizer controled by clock at read side
	sync_w2r sync_w2r (.rq2_wptr(rq2_wptr),
		.wptr(wptr),.rclk(rclk), .rrst_n(rrst_n));
	
	//fifo controled dual-port RAM
	//accessed by both the read write clock domains
	fifomem #(DSIZE, ASIZE) fifomem(
		.rdata(rdata), .wdata(wdata),.waddr(waddr), .raddr(raddr),
		.wclken(winc), .wfull(wfull),.wclk(wclk));
		
	//read side empty signal generator using gray-code 
	//increases read pointer
	rptr_empty #(ASIZE) rptr_empty(.rempty(rempty),.raddr(raddr),
		.rptr(rptr), .rq2_wptr(rq2_wptr),.rinc(rinc), .rclk(rclk),
		.rrst_n(rrst_n));
		
	//write side full signal generator using gray-code
	//increases write pointer
	wptr_full #(ASIZE) wptr_full(.wfull(wfull), .waddr(waddr),
		.wptr(wptr), .wq2_rptr(wq2_rptr),.winc(winc), .wclk(wclk),
		.wrst_n(wrst_n));
		
endmodule


fifomem.v

双端口ram

module fifomem #
	(
	parameter DATASIZE = 8, // Memory data word width
	parameter ADDRSIZE = 4 // Number of mem address bits
	)
	(
	output [DATASIZE-1:0] rdata,
	input [DATASIZE-1:0] wdata,
	input [ADDRSIZE-1:0] waddr, raddr,
	input wclken, wfull, wclk
	);

`ifdef VENDORRAM
// instantiation of a vendor's dual-port RAM
	vendor_ram mem (.dout(rdata), .din(wdata),
		.waddr(waddr), .raddr(raddr),
		.wclken(wclken),
		.wclken_n(wfull), .clk(wclk));
		
`else
// RTL Verilog memory model
	localparam DEPTH = 1<<ADDRSIZE;
	reg [DATASIZE-1:0] mem [0:DEPTH-1];
	assign rdata = mem[raddr];
	
	always @(posedge wclk)
		if (wclken && !wfull) mem[waddr] <= wdata;
`endif

endmodule


读指针控制

rptr_empty.v

module rptr_empty #
	(
	parameter ADDRSIZE = 4
	)
	(
	output reg rempty,
	output [ADDRSIZE-1:0] raddr,
	output reg [ADDRSIZE :0] rptr,
	input [ADDRSIZE :0] rq2_wptr,
	input rinc, rclk, rrst_n
	);
	
	reg [ADDRSIZE:0] rbin;
	wire [ADDRSIZE:0] rgraynext, rbinnext;
	
	//synchronize output both binary and gray encoded read pointers
	always @(posedge rclk or negedge rrst_n)
		if (!rrst_n) 
			{rbin, rptr} <= 0;
		else 
			{rbin, rptr} <= {rbinnext, rgraynext};

	// Memory read-address pointer (okay to use binary to address memory)
	assign raddr = rbin[ADDRSIZE-1:0];
	
	//increases read address register if read enable while not read empty
	assign rbinnext = rbin + (rinc & ~rempty);
	
	//combinational logic converting binary to gray code
	assign rgraynext = (rbinnext>>1) ^ rbinnext;

	// FIFO empty when the next rptr == synchronized wptr or on reset	 	
	always @(posedge rclk or negedge rrst_n)
		if (!rrst_n) 
			rempty <= 1'b1;
		else 
		//empty occurs when rptr == wptr (both applicative in binary and gray code)
			rempty <= (rgraynext == rq2_wptr);
			
//			rempty <= rempty_val;
			
//	assign rempty_val = (rgraynext == rq2_wptr);

endmodule


写指针控制

wptr_full.v

module wptr_full #
	(
	parameter ADDRSIZE = 4
	)
	(
	output reg wfull,
	output [ADDRSIZE-1:0] waddr,
	output reg [ADDRSIZE :0] wptr,
	input [ADDRSIZE :0] wq2_rptr,
	input winc, wclk, wrst_n);
	reg [ADDRSIZE:0] wbin;
	wire [ADDRSIZE:0] wgraynext, wbinnext;

	//synchronize output both binary and gray encoded write pointers
	always @(posedge wclk or negedge wrst_n)
		if (!wrst_n) 
			{wbin, wptr} <= 0;
		else 
			{wbin, wptr} <= {wbinnext, wgraynext};

	// Memory write-address pointer (okay to use binary to address memory)
	assign waddr = wbin[ADDRSIZE-1:0];
	
	//increases write address register if write enable while not write full
	assign wbinnext = wbin + (winc & ~wfull);

	//combinational logic converting binary to gray code
	assign wgraynext = (wbinnext>>1) ^ wbinnext;

	//full occurs when rptr == {~wptr[MSB],wptr[MSB-1:LSB]}
	//I'm not so clearly about this detail,so ...
	assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1],
																	wq2_rptr[ADDRSIZE-2:0]});

	//synchronize full signal
	always @(posedge wclk or negedge wrst_n)
		if (!wrst_n) 
			wfull <= 1'b0;
		else 
			wfull <= wfull_val;
			
endmodule

 

2个读写指针同步器

   太简单了 ,略过吧……

 

testbench文件:

module fifo1_tb  ; 

parameter ASIZE  = 4 ;
parameter DSIZE  = 8 ; 
  reg    rrst_n   ; 
  reg    rclk   ; 
  reg    rinc   ; 
  wire  [DSIZE-1:0]  rdata   ; 
  reg    wrst_n   ; 
  reg    wclk   ; 
  reg    winc   ; 
  reg  [DSIZE-1:0]  wdata   ; 
  wire    rempty   ; 
  wire    wfull   ; 
    
  fifo1    #(DSIZE,ASIZE   )
   DUT  ( 
       .rrst_n (rrst_n ) ,
      .rclk (rclk ) ,
      .rinc (rinc ) ,
      .rdata (rdata ) ,
      .wrst_n (wrst_n ) ,
      .wclk (wclk ) ,
      .winc (winc ) ,
      .wdata (wdata ) ,
      .rempty (rempty ) ,
      .wfull (wfull ) ); 

initial
begin
  rrst_n = 0;
  wrst_n = 0;
  rclk = 0;
  wclk = 0;
  winc = 0;
  rinc = 0;
  #20 rrst_n = 1;
  wrst_n =1 ;
end

always #10 rclk = ~ rclk;
always #10 wclk = ~ wclk;

always @(posedge rclk)
  rinc <= {$random} % 2;

always @(posedge wclk)
  winc <= {$random} % 2;
  
always @(negedge wclk)
  wdata <= {$random} % 256;
  
endmodule

 

功能仿真波形:

ps:

本设计是Clifford E. Cummings, Sunburst Design, Inc.在一篇论文里面实现的,我只是添加了一些自己的理解的注解,并做了简单的测试。

具体论文及modelsim工程可以参见我的csdn资源

http://download.csdn.net/detail/s_a_n_/4987629

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sanzhong104204

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

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

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

打赏作者

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

抵扣说明:

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

余额充值