题解 | #异步FIFO#

异步FIFO

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

异步FIFO的原理在这里不做赘述,有需要移步知乎,说几个提交过程中遇到的问题:

  1. 指针变换为格雷码之后,此格雷码属于异步时钟域中的组合逻辑,所以第一步必须在本时钟域进行同步(此步骤是错的,会导致FIFO的空满判断错误,原则上写时钟域写指针实时。读时钟域读指针实时),然后再进行常规CDC处理,从而判断空满时也是源时钟域中的信号和目的时钟域中的同步信号进行比较。
  2. 注意题目给的双口RAM模块写和读操作是没有判断空满标志的,因此给此模块输入的时候一定是将空满判断之后的信号输入。
`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
);
    //=======================================parameter
    parameter ADDR_WIDTH = $clog2(DEPTH);
    
    //=======================================defination
    reg [ADDR_WIDTH : 0] wpnt;
    reg [ADDR_WIDTH : 0] rpnt;
    
    wire [ADDR_WIDTH - 1: 0] wpnt_addr;
    wire [ADDR_WIDTH - 1: 0] rpnt_addr;
    
    wire [ADDR_WIDTH : 0] wpnt_gray;
    wire [ADDR_WIDTH : 0] rpnt_gray;
    
    reg [ADDR_WIDTH : 0] wpnt_gray_r;
    reg [ADDR_WIDTH : 0] rpnt_gray_r;
    
    reg [ADDR_WIDTH : 0] wpnt_gray_r_r;
    reg [ADDR_WIDTH : 0] rpnt_gray_r_r;
    
    wire wenc;
    wire renc;
    //=======================================output 
    //pnt
    always@(posedge wclk or negedge wrstn)begin
        if(!wrstn) wpnt <= 'd0;
        else if(!wfull && winc) wpnt <= wpnt + 1'b1;
    end
    
    always@(posedge rclk or negedge rrstn)begin
        if(!rrstn) rpnt <= 'd0;
        else if(!rempty && rinc) rpnt <= rpnt + 1'b1;
    end
    
    //gray & sync
    assign wpnt_gray = wpnt ^ (wpnt >> 1);
    assign rpnt_gray = rpnt ^ (rpnt >> 1);
    
    
    always@(posedge rclk or negedge rrstn)begin
        if(!rrstn) {wpnt_gray_r_r, wpnt_gray_r} <= 'd0;
        else {wpnt_gray_r_r, wpnt_gray_r} <= {wpnt_gray_r, wpnt_gray};
    end
    
    always@(posedge wclk or negedge wrstn)begin
        if(!wrstn) {rpnt_gray_r_r, rpnt_gray_r} <= 'd0;
        else {rpnt_gray_r_r, rpnt_gray_r} <= {rpnt_gray_r, rpnt_gray};
    end
    
    //full & empty
    assign wfull = wpnt_gray == {~rpnt_gray_r_r[ADDR_WIDTH : ADDR_WIDTH - 1], rpnt_gray_r_r[ADDR_WIDTH - 2 : 0]};
    assign rempty = rpnt_gray == wpnt_gray_r_r;
    
    //ram ctrl
    assign wpnt_addr = wpnt[ADDR_WIDTH - 1 : 0];
    assign rpnt_addr = rpnt[ADDR_WIDTH - 1 : 0];
    
    assign wenc = winc && !wfull;
    assign renc = rinc && !rempty;
    
    dual_port_RAM 
        #(
              .DEPTH (DEPTH),
              .WIDTH (WIDTH)
        )
        u_dual_port_RAM
        (
            .wclk (wclk),
            .wenc (wenc),
            .waddr (wpnt_addr), //深度对2取对数,得到地址的位宽。
            .wdata (wdata)    ,  //数据写入
            .rclk (rclk),
            .renc (renc),
            .raddr(rpnt_addr) , //深度对2取对数,得到地址的位宽。
            .rdata(rdata)//数据输出
        ); 
    
    
endmodule
全部评论
在写时钟域将写格雷码打一拍同步,然后再得到wfull的标志位,这样不会慢一拍吗,这个时候wpnt已经自加了,但是wfull判断中的wpnt_gray_是对应上一个wpnt的格雷码这样的话wpnt不就超过rpnt了吗
点赞 回复 分享
发布于 2022-03-14 01:28
老哥我有两个问题: 1、二进制转格雷码是用组合逻辑得到的二进制呢还是用打一拍之后的二进制数呢? 2、判断空满是直接用组合逻辑产生的格雷码指针呢还是同步一拍之后的格雷码指针呢? 3、空满信号经组合逻辑产生后,需要对空满信号打一拍同步吗? 前两个问题我的答案是:组合逻辑、组合逻辑;第三个问题不确定
点赞 回复 分享
发布于 2022-03-24 17:25
感觉代码中所有的!wfull和!rempty判断都是不必要的,因为空满判断是输出(相对外界是输入),外界只有在收到非满时才会传入写使能信号,收到非空时才会传入读使能信号,因此在有写使能/读使能时没必要再判断空满
点赞 回复 分享
发布于 2022-04-08 15:53
就是这样,害我modelsim跑了半天仿真都没找到问题,都怀疑人生了,就不应该打一拍。太强了老哥。这网站错的答案是真多。
点赞 回复 分享
发布于 2023-08-04 02:52 浙江

相关推荐

10-09 09:39
门头沟学院 C++
HHHHaos:这也太虚了,工资就一半是真的
点赞 评论 收藏
分享
三年之期已到我的offer快到碗里来:9硕都比不上9本
点赞 评论 收藏
分享
评论
5
3
分享
牛客网
牛客企业服务