题解 | #异步FIFO#
异步FIFO
https://www.nowcoder.com/practice/40246577a1a04c08b3b7f529f9a268cf
//采用例化双口RAM的方式设计AS_FIFO //单bit数据的跨时钟传输可以通过打拍,电平化,脉冲截等方式进行同步 //bits数据的跨时钟传输,需要先进行gray_code,跨时钟传输 //核心在于bin2gray,采用gray码做判断 `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 /***********************************asyn_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 ); /* --------------------------------- define --------------------------------- */ localparam ADDR_WIDTH = $clog2(DEPTH) ; //注意此为不可综合语句 reg [ADDR_WIDTH :0] wr_ptr ; reg [ADDR_WIDTH :0] rd_ptr ; reg [ADDR_WIDTH :0] wrptr ; reg [ADDR_WIDTH :0] rdptr ; reg [ADDR_WIDTH :0] wr_ptr_gray_cross ; reg [ADDR_WIDTH :0] rd_ptr_gray_cross ; reg [ADDR_WIDTH :0] wr_ptr_gray_cross_r1 ; reg [ADDR_WIDTH :0] rd_ptr_gray_cross_r1 ; wire [ADDR_WIDTH :0] wr_ptr_gray ; wire [ADDR_WIDTH :0] rd_ptr_gray ; /* ---------------------------------- main ---------------------------------- */ // assign wenc = winc & !wfull ; assign renc = rinc & !rempty ; assign wfull = (wrptr == {~rd_ptr_gray_cross_r1[ADDR_WIDTH :ADDR_WIDTH-1], rd_ptr_gray_cross_r1[ADDR_WIDTH-2 :0]} ) ; assign rempty = (rdptr == wr_ptr_gray_cross_r1) ; //wr_ptr always @(posedge wclk or negedge wrstn) begin if(!wrstn) wr_ptr <= 'd0 ; else if(wenc) wr_ptr <= wr_ptr + 1'b1 ; end //rd_ptr always @(posedge rclk or rrstn) begin if(!rrstn) rd_ptr <= 'd0 ; else if(renc) rd_ptr <= rd_ptr + 1'b1 ; end //bin2gray assign wr_ptr_gray = (wr_ptr >> 1) ^ wr_ptr ; assign rd_ptr_gray = (rd_ptr >> 1) ^ rd_ptr ; //wr_ptr_gray_sync always @(posedge wclk or negedge wrstn) begin if(!wrstn) wrptr <= 'd0 ; else wrptr <= wr_ptr_gray ; end //rd_ptr_gray_sync always @(posedge rclk or negedge rrstn) begin if(!rrstn) rdptr <= 'd0 ; else rdptr <= rd_ptr_gray ; end //wr_ptr_gray_cross always @(posedge rclk or negedge rrstn) begin if(!rrstn) begin wr_ptr_gray_cross <= 'd0 ; wr_ptr_gray_cross_r1 <= 'd0 ; end else begin wr_ptr_gray_cross <= wrptr ; wr_ptr_gray_cross_r1 <= wr_ptr_gray_cross ; end end //rd_ptr_gray_cross always @(posedge wclk or negedge wrstn) begin if(!wrstn) begin rd_ptr_gray_cross <= 'd0 ; rd_ptr_gray_cross_r1 <= 'd0 ; end else begin rd_ptr_gray_cross <= rdptr ; rd_ptr_gray_cross_r1 <= rd_ptr_gray_cross ; end end /* -------------------------------- instance -------------------------------- */ dual_port_RAM #( .DEPTH (DEPTH), .WIDTH (WIDTH) ) dual_port_RAM_u ( .wclk (wclk ), .wenc (wenc ), .waddr (wr_ptr[ADDR_WIDTH-1 :0] ), .wdata (wdata ), .rclk (rclk ), .renc (renc ), .raddr (rd_ptr[ADDR_WIDTH-1 :0] ), .rdata (rdata ) ); endmodule