// *****************************************************************************
// Project Name : *
// Target Device : *
// Tool version : *
// Module Name : dcfifo
// Description : Dual Clock First In First Out
// Function : asynchronous FIFO
// Attention : The FIFO must be reseted firstly before used
// Version History : *
// *****************************************************************************
// Engineer : zyhe
// Date : 2016-01-01
// Modification : 1) initial version
// *****************************************************************************
// Engineer : zyhe
// Date : 2016-05-01
// Modification : 1) standard coding style
// i_ for input, o_ for output, w_ for wire, r_ for register
// *****************************************************************************
// All rights reserved.
// *****************************************************************************
`timescale 1ns / 1ps
module dcfifo # (
parameter DW = 8 , // Data Width
parameter AW = 4 // Address Width
) (
input i_wr_rst , // write reset, active high
input i_wr_clk , // write clock
input i_wr_ena , // write enable
input [DW-1:0]i_wr_dat , // write data
output reg o_wr_ful , // write full
input i_rd_rst , // read reset, active high
input i_rd_clk , // read clock
input i_rd_ena , // read enable
output [DW-1:0]o_rd_dat , // read data
output reg o_rd_ept // read empty
);
reg [DW-1:0]r_2d_mem[0:(1<<AW)-1]; // register for 2D array memory
wire[AW:0] w_rd_adr ; // wire for read address
reg [AW:0] r_rd_adr ; // register for read address
wire[AW:0] w_rd_gry ; // wire for read graycode
reg [AW:0] r_rd_gry ; // register for read graycode
reg [AW:0] r_rd_gry_d0 ; // register for read graycode, cross clock domain 1 cycle
reg [AW:0] r_rd_gry_d1 ; // register for read graycode, cross clock domain 2 cycle
wire[AW:0] w_wr_adr ; // wire for write address
reg [AW:0] r_wr_adr ; // register for write address
wire[AW:0] w_wr_gry ; // wire for write graycode
reg [AW:0] r_wr_gry ; // register for write graycode
reg [AW:0] r_wr_gry_d0 ; // register for write graycode, cross clock domain 1 cycle
reg [AW:0] r_wr_gry_d1 ; // register for write graycode, cross clock domain 2 cycle
assign w_wr_adr = r_wr_adr + (i_wr_ena & ~o_wr_ful);
assign w_wr_gry = w_wr_adr ^ (w_wr_adr >> 1);
assign w_rd_adr = r_rd_adr + (i_rd_ena & ~o_rd_ept);
assign w_rd_gry = w_rd_adr ^ (w_rd_adr >> 1);
assign o_rd_dat = r_2d_mem[r_rd_adr[AW-1:0]];
always @ (posedge i_wr_clk)
begin
if (i_wr_ena & ~o_wr_ful)
r_2d_mem[r_wr_adr[AW-1:0]] <= i_wr_dat;
end
always @ (posedge i_wr_clk)
begin
if (i_wr_rst)
begin
r_wr_gry <= 0;
r_wr_adr <= 0;
r_rd_gry_d0 <= 0;
r_rd_gry_d1 <= 0;
o_wr_ful <= 0;
end
else
begin
r_wr_gry <= w_wr_gry;
r_wr_adr <= w_wr_adr;
r_rd_gry_d0 <= r_rd_gry;
r_rd_gry_d1 <= r_rd_gry_d0;
o_wr_ful <= (w_wr_gry == {~r_rd_gry_d1[AW:AW-1], r_rd_gry_d1[AW-2:0]});
end
end
always @ (posedge i_rd_clk)
begin
if (i_rd_rst)
begin
r_rd_gry <= 0;
r_rd_adr <= 0;
r_wr_gry_d0 <= 0;
r_wr_gry_d1 <= 0;
o_rd_ept <= 1;
end
else
begin
r_rd_gry <= w_rd_gry;
r_rd_adr <= w_rd_adr;
r_wr_gry_d0 <= r_wr_gry;
r_wr_gry_d1 <= r_wr_gry_d0;
o_rd_ept <= (w_rd_gry == r_wr_gry_d1);
end
end
endmodule