题解 | #异步FIFO#
异步FIFO
https://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf
//async_fifo 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 ADDR = $clog2(DEPTH); reg [ADDR:0] waddr; reg [ADDR:0] raddr; always@(posedge wclk or negedge wrstn)begin if(!wrstn)begin waddr <= 0; end else if(winc&~wfull)begin waddr <= waddr + 1; end end always@(posedge rclk or negedge rrstn)begin if(!rrstn)begin raddr <= 0; end else if(rinc&~rempty)begin raddr <= raddr + 1; end end //双端口RAM例化 dual_port_RAM#( .DEPTH (16), .WIDTH (8) )u_dual_port_RAM( .wclk (wclk), .wenc (winc&~wfull), .waddr (waddr), .wdata (wdata), .rclk (rclk), .renc (rinc&~rempty), .raddr (raddr), .rdata (rdata) ); //读写地址指针格雷码转换 wire [ADDR:0] gray_wptr; wire [ADDR:0] gray_rptr; assign gray_wptr = waddr ^ (waddr>>>1); assign gray_rptr = raddr ^ (raddr>>>1); reg [ADDR:0] wptr; reg [ADDR:0] rptr; always@(posedge wclk or negedge wrstn)begin if(!wrstn)begin wptr <= 0; end else begin wptr <= gray_wptr; end end always@(posedge rclk or negedge rrstn)begin if(!rrstn)begin rptr <= 0; end else begin rptr <= gray_rptr; end end //同步打拍 reg [ADDR:0] wptr2rclk_r1,wptr2rclk_r2; reg [ADDR:0] rptr2wclk_r1,rptr2wclk_r2; always@(posedge rclk or negedge rrstn)begin if(!rrstn)begin wptr2rclk_r1 <= 0; wptr2rclk_r2 <= 0; end else begin wptr2rclk_r1 <= wptr; wptr2rclk_r2 <= wptr2rclk_r1; end end always@(posedge wclk or negedge wrstn)begin if(!wrstn)begin rptr2wclk_r1 <= 0; rptr2wclk_r2 <= 0; end else begin rptr2wclk_r1 <= rptr; rptr2wclk_r2 <= rptr2wclk_r1; end end //空满判断 assign wfull = wptr == {~rptr2wclk_r2[ADDR:ADDR-1],rptr2wclk_r2[ADDR-2:0]}; assign rempty = rptr == wptr2rclk_r2; endmodule 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 [DEPTH-1:0]; always@(posedge wclk)begin if(wenc)begin RAM_MEM[waddr] <= wdata; end end always@(posedge rclk)begin if(renc)begin rdata <= RAM_MEM[raddr]; end end endmodule