异步FIFO

异步FIFO

`timescale 1ns/1ns

/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
					   parameter WIDTH = 8)(
	 input wclk
	,input wenc
	,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
	,input [WIDTH-1:0] wdata      	//数据写入
	,input rclk
	,input renc
	,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
	,output reg [WIDTH-1:0] rdata 		//数据输出
);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

always @(posedge wclk) begin
	if(wenc)
		RAM_MEM[waddr] <= wdata;
end 

always @(posedge rclk) begin
	if(renc)
		rdata <= RAM_MEM[raddr];
end 

endmodule  

/***************************************AFIFO*****************************************/
module asyn_fifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					wclk	, 
	input 					rclk	,   
	input 					wrstn	,
	input					rrstn	,
	input 					winc	,
	input 			 		rinc	,
	input 		[WIDTH-1:0]	wdata	,

	output wire				wfull	,
	output wire				rempty	,
	output wire [WIDTH-1:0]	rdata
);

//地址宽度
localparam ADDR_WIDTH = $clog2(DEPTH);

//***************例化双口RAM******************//
dual_port_RAM #(
	.WIDTH(WIDTH),
	.DEPTH(DEPTH)
)
u_dual_port_RAM(
	.wclk	(wclk)							,
	.wenc	(winc&&!wfull)					,
	.waddr	(wr_addr_bin[ADDR_WIDTH-1:0])	,
	.wdata  (wdata)    						,
	.rclk	(rclk)							,
	.renc	(rinc&&!rempty)					,
	.raddr	(rd_addr_bin[ADDR_WIDTH-1:0])	,
	.rdata 	(rdata)
);

//写地址,长度为ADDR_WIDTH+1
reg [ADDR_WIDTH:0] wr_addr_bin;
//写地址的格雷码以及用于在本地打拍的寄存器
wire [ADDR_WIDTH:0] wr_addr_gray;
reg [ADDR_WIDTH:0] wr_addr_gray_d;
//写地址同步到读时钟的格雷码寄存器
reg [ADDR_WIDTH:0] wr2rd_addr_gray_d1;
reg [ADDR_WIDTH:0] wr2rd_addr_gray_d2;

//读地址,长度为ADDR_WIDTH+1
reg [ADDR_WIDTH:0] rd_addr_bin;
//读地址的格雷码以及用于在本地打拍的寄存器
wire [ADDR_WIDTH:0] rd_addr_gray;
reg [ADDR_WIDTH:0] rd_addr_gray_d;
//读地址同步到写时钟的格雷码寄存器
reg [ADDR_WIDTH:0] rd2wr_addr_gray_d1;
reg [ADDR_WIDTH:0] rd2wr_addr_gray_d2;

//***************读写地址的产生******************//
always @(posedge wclk or negedge wrstn) begin
	if(!wrstn)
	    wr_addr_bin <= 'b0;
	else if(winc&&!wfull)
		wr_addr_bin <= wr_addr_bin + 1'b1;
	else
	    wr_addr_bin <= wr_addr_bin;
end

always @(posedge rclk or negedge rrstn) begin
	if(!rrstn)
	    rd_addr_bin <= 'b0;
	else if(rinc&&!rempty)
		rd_addr_bin <= rd_addr_bin + 1'b1;
	else
	    rd_addr_bin <= rd_addr_bin;
end

//***************读写地址转化成格雷码******************//
assign wr_addr_gray = wr_addr_bin^(wr_addr_bin>>1'b1);
assign rd_addr_gray = rd_addr_bin^(rd_addr_bin>>1'b1);

//***************读写地址格雷码本地打拍******************//
always @(posedge wclk or negedge wrstn) begin
	if(!wrstn)
	    wr_addr_gray_d <= 'b0;
	else
	    wr_addr_gray_d <= wr_addr_gray;
end

always @(posedge rclk or negedge rrstn) begin
	if(!rrstn)
	    rd_addr_gray_d <= 'b0;
	else
	    rd_addr_gray_d <= rd_addr_gray;
end

//***************读地址格雷码同步到写时钟域******************//
always @(posedge wclk or negedge wrstn) begin
	if(!wrstn) begin
	    rd2wr_addr_gray_d1 <= 'b0;
		rd2wr_addr_gray_d2 <= 'b0;
	end
	else begin
	    rd2wr_addr_gray_d1 <= rd_addr_gray_d;
		rd2wr_addr_gray_d2 <= rd2wr_addr_gray_d1;
	end
end
//***************写地址格雷码同步到读时钟域******************//
always @(posedge rclk or negedge rrstn) begin
	if(!rrstn) begin
	    wr2rd_addr_gray_d1 <= 'b0;
		wr2rd_addr_gray_d2 <= 'b0;
	end
	else begin
	    wr2rd_addr_gray_d1 <= wr_addr_gray_d;
		wr2rd_addr_gray_d2 <= wr2rd_addr_gray_d1;
	end
end

//***************空满标志的判断******************//
//此处判断写满信号,如果根据gray码进行判断就应该翻转高两位,如果根据二进制码进行判断就只翻转高一位就行了
assign wfull = (wr_addr_gray_d == {~rd2wr_addr_gray_d2[ADDR_WIDTH:ADDR_WIDTH-1], rd2wr_addr_gray_d2[ADDR_WIDTH-2:0]});
assign rempty = (rd_addr_gray_d == wr2rd_addr_gray_d2);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值