题解 | 进阶版22#异步FIFO#

异步FIFO

http://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf

基础:

在先做23题同步FIFO和24题格雷码的前提下,写异步FIFO很简单。同步FIFO中的很多内容可以直接拿来用。

结构:

在同步FIFO基础上,进行异步FIFO设计。保持类似的读写逻辑和读写地址控制,区别是增加了格雷码跨时钟,另外空满逻辑是使用格雷码判断空满。

代码:

`timescale 1ns/1ns
//********************************
//作者:FPGA探索者
//********************************
/***************************************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);
    
    reg [ADDR_WIDTH:0] waddr;
    reg [ADDR_WIDTH:0] raddr;
    always @ (posedge wclk&nbs***bsp;negedge wrstn) begin
        if(~wrstn) begin
            waddr <= 'b0;
        end 
        else begin
            if( winc && ~wfull ) begin
                waddr <= waddr + 1'b1;
            end 
            else begin
                waddr <= waddr;    
            end 
        end 
    end 
    
    always @ (posedge rclk&nbs***bsp;negedge rrstn) begin
        if(~rrstn) begin
            raddr <= 'b0;
        end 
        else begin
            if( rinc && ~rempty ) begin
                raddr <= raddr + 1'b1;
            end 
            else begin
                raddr <= raddr;    
            end 
        end 
    end 
    
    wire [ADDR_WIDTH:0] waddr_gray;
    wire [ADDR_WIDTH:0] raddr_gray;
    assign waddr_gray = waddr ^ (waddr>>1);
    assign raddr_gray = raddr ^ (raddr>>1);
    
    reg [ADDR_WIDTH:0] waddr_gray_reg;
    always @ (posedge wclk&nbs***bsp;negedge wrstn) begin
        if(~wrstn) begin
            waddr_gray_reg  <= 'd0;
        end
        else begin
            waddr_gray_reg <= waddr_gray;
        end 
    end 
    
    reg [ADDR_WIDTH:0] raddr_gray_reg;
    always @ (posedge rclk&nbs***bsp;negedge rrstn) begin
        if(~rrstn) begin
            raddr_gray_reg  <= 'd0;
        end
        else begin
            raddr_gray_reg <= raddr_gray;
        end 
    end
    
    
    reg [ADDR_WIDTH:0] addr_r2w_t;
    reg [ADDR_WIDTH:0] addr_r2w;
    always @ (posedge wclk&nbs***bsp;negedge wrstn) begin
        if(~wrstn) begin
            addr_r2w_t  <= 'd0;
            addr_r2w    <= 'd0;
        end
        else begin
            addr_r2w_t <= raddr_gray_reg;
            addr_r2w <= addr_r2w_t;
        end 
    end 
    
    reg [ADDR_WIDTH:0] addr_w2r_t;
    reg [ADDR_WIDTH:0] addr_w2r;
    always @ (posedge rclk&nbs***bsp;negedge rrstn) begin
        if(~rrstn) begin
            addr_w2r_t  <= 'd0;
            addr_w2r    <= 'd0;
        end
        else begin
            addr_w2r_t <= waddr_gray_reg;
            addr_w2r <= addr_w2r_t;
        end 
    end 
    
    
    assign wfull = (waddr_gray_reg == {~addr_r2w[ADDR_WIDTH:ADDR_WIDTH-1], addr_r2w[ADDR_WIDTH-2:0]});
    assign rempty = (raddr_gray_reg == addr_w2r);
    
    
dual_port_RAM  
    #(
        .DEPTH(DEPTH),
		.WIDTH(WIDTH)
    )
    dual_port_RAM_U0 
    (
        .wclk(wclk),
        .wenc(winc&&~wfull),
        .waddr(waddr[ADDR_WIDTH-1:0]),  //深度对2取对数,得到地址的位宽。
	    .wdata(wdata),      	//数据写入
        .rclk(rclk),
        .renc(rinc&&~rempty),
        .raddr(raddr[ADDR_WIDTH-1:0]),  //深度对2取对数,得到地址的位宽。
	    .rdata(rdata) 		//数据输出
);    
    
endmodule


全部评论
请问always @ (posedge wclk&nbs***bsp;negedge wrstn)中,wclk&nbs***bsp是什么呢?
1 回复 分享
发布于 2023-02-20 18:46 江苏
为什么同步FIFO中用winc和rinc来表示读使能和写使能,而在异步FIFO中用wenc和renc来表示读使能和写使能?
点赞 回复 分享
发布于 2023-08-05 23:37 四川
老哥,时序有点不对,貌似空满那个地方格雷码用组合逻辑比较好
点赞 回复 分享
发布于 09-04 11:29 福建

相关推荐

ProMonkey2024:5个oc?厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了(别的帖子偷来的,现学现卖😋)
点赞 评论 收藏
分享
Noel_:中石油是这样的 哥们侥幸混进免笔试名单 一看给我吓尿了
点赞 评论 收藏
分享
36 13 评论
分享
牛客网
牛客企业服务