module afifo ( wr_clock, rd_clock, reset_n, wr_enable, wr_data, rd_enable, rd_data, full, empty ); parameter WIDTH = 8; parameter ADDR_WIDTH = 4; parameter WR_TO_RD_SYNC_STAGES = 3; parameter RD_TO_WR_SYNC_STAGES = 3; input wr_clock; input rd_clock; input reset_n; input wr_enable; input [WIDTH-1:0] wr_data; input rd_enable; output [WIDTH-1:0] rd_data; output full; output empty; reg [WIDTH-1:0] data[2 ** ADDR_WIDTH-1:0]; reg [ADDR_WIDTH-1:0] wr_addr; reg [ADDR_WIDTH-1:0] rd_addr; wire [ADDR_WIDTH-1:0] wr_addr_next = wr_addr + 1; wire [ADDR_WIDTH-1:0] rd_addr_next = rd_addr + 1; wire [ADDR_WIDTH-1:0] wr_addr_gray = (wr_addr >> 1) ^ wr_addr; wire [ADDR_WIDTH-1:0] wr_addr_next_gray = (wr_addr_next >> 1) ^ wr_addr_next; wire [ADDR_WIDTH-1:0] rd_addr_gray = (rd_addr >> 1) ^ rd_addr; wire [ADDR_WIDTH-1:0] rd_addr_next_gray = (rd_addr_next >> 1) ^ rd_addr_next; reg [ADDR_WIDTH-1:0] wr_addr_gray_sync[WR_TO_RD_SYNC_STAGES-1:0]; reg [ADDR_WIDTH-1:0] rd_addr_gray_sync[RD_TO_WR_SYNC_STAGES-1:0]; assign empty = rd_addr_gray == wr_addr_gray_sync[WR_TO_RD_SYNC_STAGES-1]; assign full = wr_addr_next_gray == rd_addr_gray_sync[RD_TO_WR_SYNC_STAGES-1]; assign rd_data = data[rd_addr]; integer i; always @(posedge wr_clock or negedge reset_n) begin if (!reset_n) begin wr_addr <= 0; for (i = 0; i < RD_TO_WR_SYNC_STAGES; i = i + 1) rd_addr_gray_sync[i] <= 0; end else begin if (wr_enable && !full) begin data[wr_addr] <= wr_data; wr_addr <= wr_addr_next; end rd_addr_gray_sync[0] <= rd_addr_gray; for (i = 1; i < RD_TO_WR_SYNC_STAGES; i = i + 1) rd_addr_gray_sync[i] <= rd_addr_gray_sync[i - 1]; end end always @(posedge rd_clock or negedge reset_n) begin if (!reset_n) begin rd_addr <= 0; for (i = 0; i < WR_TO_RD_SYNC_STAGES; i = i + 1) wr_addr_gray_sync[i] <= 0; end else begin if (rd_enable && !empty) begin rd_addr <= rd_addr_next; end wr_addr_gray_sync[0] <= wr_addr_gray; for (i = 1; i < WR_TO_RD_SYNC_STAGES; i = i + 1) wr_addr_gray_sync[i] <= wr_addr_gray_sync[i - 1]; end end endmodule