异步FIFO时序分析与设计

本文详细介绍了FIFO(先进先出缓冲区)的设计,包括时序分析、接口声明和跨时钟域同步的重要性。在时序分析中,明确了写入和读取操作的步骤。接口声明部分展示了FIFO的输入和输出信号。在跨时钟域同步中,讨论了如何通过亚稳态寄存器确保满和空标志的正确表示,防止数据丢失或错误。代码部分展示了用Verilog实现的FIFO模块,包括读写地址和指针的控制,以及写满和读空标志的判断。测试代码验证了模块的功能。
摘要由CSDN通过智能技术生成

一、时序分析

1.在读写之前需要将使能信号端拉高;
2.1写时序:
写满信号为0,w_clk上升,将数据写入mem,地址指向下一个位置。
2.2读时序:
读空信号为0,先将当前地址数据读出,后r_clk上升,地址加一,等待下次读出数据。

二、接口声明

input 			rst;
input 			w_clk;
input 	[7:0]	dat_in;
input 			w_en;
output reg 		wfull;//写满标志
input 			r_clk;
output	[7:0]	dat_out;
input 			r_en;
output reg 		rempty;//读空标志

二、跨时钟域同步

1.目的
在我们需要读数据或写数据时,我们需要判断FIFO中存储器里面有没有数据,或者数据已经写满。从而需要引出写满标志和读空标志信号,而这些信号的判断都是根据内部的读写指针来判断的。进行跨时钟域同步的目的就是考虑满和空标志能正确的表示,以保证系统能够正确的将数据写入与读出。
在此我们需要了解寄存器的亚稳态的知识(自行查阅),由于实际中寄存器电平跳转需要一定的延时,假设在写入第一个数据到FIFO中,我们需要保证数据完全写入并正确表示之后,才能将读空标志拉低,让读数据端将数据读出,那这个时候我们就需要进行一定的延时;同理在数据写满之后,我们在读数据的时候也要保证数据能够完全正确的读出,因此也需要一定的延时,
延时的方法就是再加两级寄存器,延时两个时钟周期。

2.思路
这部分可以参考链接: link这个博客
主要看转换格雷码跟亚稳态寄存器延时,不然代码看不懂的。

三、代码

my_fifo.v

//写数据时,先给dat_in,w_en拉高,w_clk上升沿数据采集写入,之后改变数据,等待下次写使能。
module my_fifo(rst,w_clk,dat_in,w_en,wfull,r_clk,dat_out,r_en,rempty);
input 			rst;
input 			w_clk;
input 	[7:0]	dat_in;
input 			w_en;
output reg 		wfull;
input 			r_clk;
output	[7:0]	dat_out;
input 			r_en;
output reg 		rempty;

//变量声明
reg [5:0] wbin,rbin;//地址寄存器
wire [5:0] rbin_next,wbin_next,wbin_gray,rbin_gray;
reg	[7:0] mem[31:0];
wire [4:0]	w_addr,r_addr;//地址线
reg [5:0] wp,wp1,wp2,rp,rp1,rp2;

wire wfull_fla,rempty_fla;

assign dat_out = mem[r_addr];  //读数据
//写数据
always@(posedge w_clk)
begin
	if(w_en & ~wfull_fla)
		mem[w_addr] <= dat_in;
end



//写地址与指针控制
assign w_addr = wbin[4:0];
assign wbin_next = wbin + (w_en & !wfull_fla);
always@(posedge w_clk or posedge rst)
begin
	if(rst)
	begin
		wbin <= 6'b0;
		wp <= 6'b0;
	end
	else
	begin
		wbin <= wbin_next;
		wp <= wbin_gray;
	end
end

assign wbin_gray = wbin_next^(wbin_next >> 1);
//读指针同步到写时钟域
always@(posedge w_clk or posedge rst)
	if(rst)
		{rp2,rp1} <= 0;
	else
		{rp2,rp1} <= {rp1,rp};
//写满标志
assign wfull_fla = ((rp2[5:4] == ~wp[5:4]) && rp2[3:0] == wp[3:0]);
always@(posedge w_clk or posedge rst)
	if(rst)
		wfull <= 1'b0;
	else
		wfull <= wfull_fla;


//读地址与指针控制
assign r_addr = rbin[4:0];
assign rbin_next = rbin + (r_en & !rempty_fla);
always@(posedge r_clk or posedge rst)
begin
	if(rst)
	begin
		rbin <= 6'b0;
		rp <= 6'b0;
	end
	else
	begin
		rbin <= rbin_next;
		rp <= rbin_gray;
	end
end

assign rbin_gray = rbin_next^(rbin_next >> 1);
//写指针同步
always@(posedge r_clk or posedge rst)
	if(rst)
		{wp2,wp1} <= 0;
	else
		{wp2,wp1} <= {wp1,wp};
//读空标志
assign rempty_fla = (wp2 == rp);
always@(posedge r_clk or posedge rst)
	if(rst)
		rempty <= 1'b0;
	else
		rempty<= rempty_fla;
		endmodule

my_fifo.vt(测试代码)



`timescale 1 ns/ 1 ns
module my_fifo_vlg_tst();
reg [7:0] dat_in;
reg r_clk;
reg r_en;
reg rst;
reg w_clk;
reg w_en;
// wires                                               
wire [7:0]  dat_out;
wire rempty;
wire wfull;
                   
my_fifo i1 ( 
	.dat_in(dat_in),
	.dat_out(dat_out),
	.r_clk(r_clk),
	.r_en(r_en),
	.rempty(rempty),
	.rst(rst),
	.w_clk(w_clk),
	.w_en(w_en),
	.wfull(wfull)
);
initial                                                
begin                                                  
	dat_in = 8'b1100_0101;
	rst = 1;
	w_clk = 0;
	r_clk = 0;
	w_en = 0 ;
	r_en = 0;
	#20 rst = 0;
	//write
	#20 w_en = 1;
	r_en = 1;
                   
end 
always #10 w_clk = ~w_clk;                                                   
always #7 r_clk = ~r_clk;                                                  
endmodule
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值