题解 | #异步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 reg [WIDTH-1:0] rdata ); parameter WIDTH_ptr= 5; parameter WIDTH_addr= 4; //读写模块 integer i ; reg [WIDTH-1:0]buff[DEPTH-1:0]; reg [WIDTH_ptr-1:0]w_ptr; wire [WIDTH_addr-1:0] w_addr; assign w_addr=w_ptr[WIDTH_addr-1:0]; always@(posedge wclk or negedge wrstn) begin if(!wrstn) begin w_ptr<=0; end else if(winc&(!wfull)) begin w_ptr<=w_ptr+1; buff[w_addr]<=wdata; end end reg [WIDTH_ptr-1:0]r_ptr; wire [WIDTH_addr-1:0] r_addr; assign r_addr=r_ptr[WIDTH_addr-1:0]; always@(posedge rclk or negedge rrstn) begin if(!rrstn) begin r_ptr<=0; end else if(rinc&(!rempty)) begin r_ptr<=r_ptr+1; rdata<=buff[r_addr]; end end //指针同步 wire [WIDTH_ptr-1:0]w_gray_ptr; wire [WIDTH_ptr-1:0]r_gray_ptr; reg [WIDTH_ptr-1:0]w_gray_ptr_d0; reg [WIDTH_ptr-1:0]w_gray_ptr_d1; reg [WIDTH_ptr-1:0]w_gray_ptr_d2; reg [WIDTH_ptr-1:0]r_gray_ptr_d0; reg [WIDTH_ptr-1:0]r_gray_ptr_d1; reg [WIDTH_ptr-1:0]r_gray_ptr_d2; assign w_gray_ptr=w_ptr^(w_ptr>>1); assign r_gray_ptr=r_ptr^(r_ptr>>1); always@(posedge wclk or negedge wrstn) //此在原时钟域打排非必要环节 begin if(!wrstn) w_gray_ptr_d0<=0; else w_gray_ptr_d0<=w_gray_ptr; end always@(posedge rclk or negedge rrstn) begin if(!rrstn) {w_gray_ptr_d2,w_gray_ptr_d1}<=0; else {w_gray_ptr_d2,w_gray_ptr_d1}<={w_gray_ptr_d1,w_gray_ptr_d0}; end always@(posedge rclk or negedge rrstn) //此在原时钟域打排非必要环节 begin if(!rrstn) r_gray_ptr_d0<=0; else r_gray_ptr_d0<=r_gray_ptr; end always@(posedge wclk or negedge wrstn) begin if(!wrstn) {r_gray_ptr_d2,r_gray_ptr_d1}<=0; else {r_gray_ptr_d2,r_gray_ptr_d1}<={r_gray_ptr_d1,r_gray_ptr_d0}; end //空满标志位产生 assign rempty=(w_gray_ptr_d2==r_gray_ptr_d0); assign wfull=(r_gray_ptr_d2[WIDTH_ptr-1]!=w_gray_ptr_d0[WIDTH_ptr-1])&(r_gray_ptr_d2[WIDTH_ptr-2]!=w_gray_ptr_d0[WIDTH_ptr-2])&(r_gray_ptr_d2[WIDTH_ptr-3:0]==w_gray_ptr_d0[WIDTH_ptr-3:0]); endmodule