异步FIFO的设计

1,经过同步FIFO的设计,了解FIFO ,现在来写异步FIFO,应该有点思考了,由于要解决跨时钟域的问题,前面设计同步FIFO的计数器方法就不太实用了,所以就选择高位扩展法,但是还有个问题如果采取二进制也会造成亚稳态,所以选择格雷码

2,注意点

1他于普通存储器的区别是没有外部读写地址线,使用相对简单。

2缺点是只能顺序写入数据,顺序读出数据,其数据地址有内部读写指针自动加一完成,不能读取指定位置的数据

3有同步和异步FIFO,同步是指读写时钟是同一个时钟,异步是指读写时钟不同

4同步FIFO一般做数据的缓冲,主要作用是buffer

5异步FIFO主要作用就是跨时钟域处理,除此之外可以实现两个不同数据宽度的数据链接

3 ,读写跨时钟域的问题,这里都是采取打两拍来解决,但是如何判断空满了?

总结一下别人的结论,这里就不再讨论了,

写满判断:将读指针同步到写指针,在于写指针判断

读空判断: 将写指针同步到读指针,在于读指针判断

3,二进制转格雷码,之前的文章讲过

Verilog实现二进制与格雷码的转换_weixin_45230720的博客-CSDN博客

4Verilog实现

设计是位宽为8 深度为16的FIFO,

module async_fifo
    #(
        parameter DATA_WIDTH = 'd8 ,
        parameter DATA_DEPTH = 'd16 
    )
(
//写数据
input               wr_clk,
input               wr_rst_n ,
input               wr_en ,
input   [DATA_WIDTH -1 : 0] data_in ,

//读数据

input               rd_clk ,
input               rd_rst_n ,
input               rd_en ,
input [DATA_WIDTH -1 :0] data_out ,

//状态标志
output              empty ,
output              full 


);
//=======================================================================

reg [DATA_WIDTH-1:0] fifo_buffer [DATA_DEPTH -1 :0] ;

reg [4:0]       wr_ptr ;
reg [4:0]       rd_ptr ;
reg [4:0]       wr_ptr_g_d1;
reg [4:0]       wr_ptr_g_d2;
reg [4:0]       rd_ptr_g_d1;
reg [4:0]       rd_ptr_g_d2;


//

wire [4:0:] wr_ptr_g ;
wire [4:0:] rd_ptr_g ;
wire [3:0:] wr_ptr_ture ;
wire [3:0:] rd_ptr_ture ;

//=========================================================================
//二进制转成格雷码
assign wr_ptr_g = wr_ptr^(wr_ptr>>1);
assign rd_ptr_g = rd_ptr^(rd_ptr>>1);


//writ 
always@(posedge wr_clk or negedge wr_rst_n)begin
    if(!wr_rst_n)
    wr_ptr <= 1'b0 ;
    else if(wr_en && !full)begin
    wr_ptr <= wr_ptr + 1'b1 ;
    fifo_buffer[wr_ptr] <= data_in ;
end 
end 

always@(posedge wr_clk or negedge wr_rst_n )begin
    if(!wr_rst_n)begin
    rd_ptr_g_d1 <= 0;
    rd_ptr_g_d2 <= 0 ;
    end 
    else 
    begin
        rd_ptr_g_d1<= rd_ptr_g ;
        rd_ptr_g_d2 <= rd_ptr_g_d1 ;

    end 
end 

//read
always@(posedge rd_clk or negedge rd_rst_n)begin
    if(!rd_rst_n)
    rd_ptr <= 0;
    else if(rd_en && !empty)begin
        data_out <= fifo_buffer[rd_ptr];
        rd_ptr <= rd_ptr +1'b1 ;
    end 
end 

//打俩拍。判断读空
always @(posedge rd_clk or negedge rd_rst_n )begin
    if(!rd_rst_n)begin
    wr_ptr_g_d1 <= 0;
    wr_ptr_g_d2 <= 0;
    end 
    else begin
    wr_ptr_g_d1 <= wr_ptr_g ;
    wr_ptr_g_d2 < wr_ptr_g_d1 ;

end 
end 


//===========================================================================
assign empty = (wr_ptr_g_d2 == rd_ptr_g) ? 1'b1 :1'b0 ;

assign full = (wr_ptr_g == {~rd_ptr_g_d2[4:3],rd_ptr_g_d2[2:0]}) ? 1'b1 :1'b0;



endmodule

如果有问题可以一起学习讨论,留言

4 测试与仿真

testbech与同步FIFO的类似,这里只给出Verilog实现


`timescale 1ns/1ns	//时间单位/精度
 
//=================================================================================
module tb_async_fifo();
 
parameter   DATA_WIDTH = 8  ;		//FIFO位宽
parameter   DATA_DEPTH = 16 ;		//FIFO深度
 
reg							wr_clk		;				//写时钟
reg							wr_rst_n	;       		//低电平有效的写复位信号
reg							wr_en		;       		//写使能信号,高电平有效	
reg	[DATA_WIDTH-1:0]		data_in		;       		//写入的数据
 
reg							rd_clk		;				//读时钟
reg							rd_rst_n	;       		//低电平有效的读复位信号
reg							rd_en		;				//读使能信号,高电平有效						                                        
wire[DATA_WIDTH-1:0]		data_out	;				//输出的数据					
wire						empty		;				//空标志,高电平表示当前FIFO已被写满
wire						full		;               //满标志,高电平表示当前FIFO已被读空
 
//===================================================================================
async_fifo
#(
	.DATA_WIDTH	(DATA_WIDTH),			//FIFO位宽
    .DATA_DEPTH	(DATA_DEPTH)			//FIFO深度
)
async_fifo_inst(
	.wr_clk		(wr_clk		),
	.wr_rst_n	(wr_rst_n	),
	.wr_en		(wr_en		),
	.data_in	(data_in	),	
	.rd_clk		(rd_clk		),               
	.rd_rst_n	(rd_rst_n	),	
	.rd_en		(rd_en		),	
	.data_out	(data_out	),
	
	.empty		(empty		),		
	.full		(full		)
);
 
//=======================================================================================
initial begin
	rd_clk = 1'b0;					//初始时钟为0
	wr_clk = 1'b0;					//初始时钟为0
	wr_rst_n <= 1'b0;				//初始复位
	rd_rst_n <= 1'b0;				//初始复位
	wr_en <= 1'b0;
	rd_en <= 1'b0;	
	data_in <= 'd0;
	#5
	wr_rst_n <= 1'b1;				
	rd_rst_n <= 1'b1;					
//重复16次写操作,让FIFO写满 	
	repeat(16) begin
		@(negedge wr_clk)begin		
			wr_en <= 1'b1;
			data_in <= $random;	//生成8位随机数
		end
	end
//拉低写使能	
	@(negedge wr_clk)	wr_en <= 1'b0;
	
//重复16次读操作,让FIFO读空 	
	repeat(16) begin
		@(negedge rd_clk)rd_en <= 1'd1;		
	end
//拉低读使能
	@(negedge rd_clk)rd_en <= 1'd0;		
//重复4次写操作,写入4个随机数据	
	repeat(4) begin
		@(negedge wr_clk)begin		
			wr_en <= 1'b1;
			data_in <= $random;	//生成8位随机数
		end
	end
//持续同时对FIFO读
	@(negedge rd_clk)rd_en <= 1'b1;
//持续同时对FIFO写,写入数据为随机数据	
	forever begin
		@(negedge wr_clk)begin		
			wr_en <= 1'b1;
			data_in <= $random;	//生成8位随机数
		end
	end	
 
end
 
//=======================================================================================
always #10 rd_clk = ~rd_clk;			//读时钟周期20ns
always #20 wr_clk = ~wr_clk;			//写时钟周期40ns
 
endmodule

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值