题解 | #异步FIFO#
异步FIFO
https://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf
`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); // write pointer reg [ADDR_WIDTH:0] wr_ptr; always @(posedge wclk or negedge wrstn) begin if (~wrstn) begin wr_ptr <= 0; end else begin if (wenc & ~wfull) begin wr_ptr <= wr_ptr + 1; end else begin wr_ptr <= wr_ptr; end end end // read pointer reg [ADDR_WIDTH:0] rd_ptr; always @(posedge rclk or negedge rrstn) begin if (~rrstn) begin rd_ptr <= 0; end else begin if (renc & ~rempty) begin rd_ptr <= rd_ptr + 1; end else begin rd_ptr <= rd_ptr; end end end // gray code wire [ADDR_WIDTH:0] wr_ptr_gray; wire [ADDR_WIDTH:0] rd_ptr_gray; assign wr_ptr_gray = wr_ptr ^ (wr_ptr >> 1); assign rd_ptr_gray = rd_ptr ^ (rd_ptr >> 1); reg [ADDR_WIDTH:0] wr_ptr_gray_reg; always @(posedge wclk or negedge wrstn) begin if (~wrstn) begin wr_ptr_gray_reg <= 0; end else begin wr_ptr_gray_reg <= wr_ptr_gray; end end reg [ADDR_WIDTH:0] rd_ptr_gray_reg; always @(posedge rclk or negedge rrstn) begin if (~rrstn) begin rd_ptr_gray_reg <= 0; end else begin rd_ptr_gray_reg <= rd_ptr_gray; end end // synchronize write pointer to read clock domain reg [ADDR_WIDTH:0] wr_ptr_reg; reg [ADDR_WIDTH:0] wr_ptr_reg2; always @(posedge rclk or negedge rrstn) begin if (~rrstn) begin wr_ptr_reg <= 0; wr_ptr_reg2 <= 0; end else begin wr_ptr_reg <= wr_ptr_gray_reg; wr_ptr_reg2 <= wr_ptr_reg; end end // synchronize read pointer to write clock domain reg [ADDR_WIDTH:0] rd_ptr_reg; reg [ADDR_WIDTH:0] rd_ptr_reg2; always @(posedge wclk or negedge wrstn) begin if (~wrstn) begin rd_ptr_reg <= 0; rd_ptr_reg2 <= 0; end else begin rd_ptr_reg <= rd_ptr_gray_reg; rd_ptr_reg2 <= rd_ptr_reg; end end assign rempty = (wr_ptr_reg2 == rd_ptr_gray_reg); assign wfull = (wr_ptr_gray_reg == {~rd_ptr_reg2[ADDR_WIDTH:ADDR_WIDTH-1], rd_ptr_reg2[ADDR_WIDTH-2:0]}); wire wenc; wire [$clog2(DEPTH)-1:0] waddr; wire renc; wire [$clog2(DEPTH)-1:0] raddr; dual_port_RAM #( .DEPTH(DEPTH), .WIDTH(WIDTH) ) u_RAM ( .wclk(wclk), .wenc(wenc), .waddr(waddr), .wdata(wdata), .rclk(rclk), .renc(renc), .raddr(raddr), .rdata(rdata) ); assign wenc = winc && ~wfull; assign waddr = wr_ptr; assign renc = rinc && ~rempty; assign raddr = rd_ptr; endmodule