题解 | 同步FIFO
同步FIFO
https://www.nowcoder.com/practice/e5e86054a0ce4355b9dfc08238f25f5f
`timescale 1ns/1ns
/**********************************RAM************************************/
module dual_port_RAM #(parameter DEPTH = 16,
					   parameter WIDTH = 8)(
	 input wclk
	,input wenc
	,input [$clog2(DEPTH)-1:0] waddr  
	,input [WIDTH-1:0] wdata      	
	,input rclk
	,input renc
	,input [$clog2(DEPTH)-1:0] raddr  
	,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  
/**********************************SFIFO************************************/
module sfifo#(
	parameter	WIDTH = 8,
	parameter 	DEPTH = 16
)(
	input 					clk		, 
	input 					rst_n	,
	input 					winc	,
	input 			 		rinc	,
	input 		[WIDTH-1:0]	wdata	,
	output 	reg	wfull	,
	output 	reg	rempty	,
	output wire [WIDTH-1:0]	rdata
);
    
	//深度的位宽
    localparam DP_WD = $clog2(DEPTH);
    //ram的写使能,读使能
    wire wenc;
    assign wenc = winc & (!wfull);
    wire renc;
    assign renc = rinc & (!rempty);
    //写地址的变化
    reg  [DP_WD : 0] waddr;
    wire [DP_WD : 0] waddr_d;
    assign waddr_d[DP_WD]     = (waddr[DP_WD-1:0] == DEPTH - 1) ? ~waddr[DP_WD] : waddr[DP_WD];
    assign waddr_d[DP_WD-1:0] = (waddr[DP_WD-1:0] == DEPTH - 1) ? 0 : waddr[DP_WD-1:0] + 1;
    always @(posedge clk or negedge rst_n) begin
        if (~rst_n) waddr <= 0;
        else if (wenc) waddr <= waddr_d;
    end
    //读地址的变化
    reg  [DP_WD : 0] raddr;
    wire [DP_WD : 0] raddr_d;
    assign raddr_d[DP_WD]     = (raddr[DP_WD-1:0] == DEPTH - 1) ? ~raddr[DP_WD] : raddr[DP_WD];
    assign raddr_d[DP_WD-1:0] = (raddr[DP_WD-1:0] == DEPTH - 1) ? 0 : raddr[DP_WD-1:0] + 1;
    always @(posedge clk or negedge rst_n) begin
        if (~rst_n) raddr <= 0;
        else if (renc) raddr <= raddr_d;
    end
    //写满,读空标志
	wire wfull_1;
	wire rempty_1;
    assign wfull_1  = (waddr[DP_WD] != raddr[DP_WD]) && (waddr[DP_WD-1:0] == raddr[DP_WD-1:0]);
    assign rempty_1 = (waddr[DP_WD] == raddr[DP_WD]) && (waddr[DP_WD-1:0] == raddr[DP_WD-1:0]);
	
    //牛客上多出来的
	always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            wfull <= 0;
			rempty<= 0;
        end else begin
            wfull <= wfull_1;
			rempty<= rempty_1;
        end
    end
	dual_port_RAM #(.DEPTH(DEPTH),
                .WIDTH(WIDTH)
)dual_port_RAM(
    .wclk (clk),  
    .wenc (wenc),  
    .waddr(waddr[DP_WD-1:0]),  //深度对2取对数,得到地址的位宽。
    .wdata(wdata),           //数据写入
    .rclk (clk), 
    .renc (renc), 
    .raddr(raddr[DP_WD-1:0]),   //深度对2取对数,得到地址的位宽。
    .rdata(rdata)          //数据输出
);
endmodule
牛客上面的 wfull rempty落后了一拍,实际的SFIFO在写满后立即wfull 拉高,并且初始时 wfull rempty两个都为0。
要通过牛客的系统,加个延迟就行

