module asyn_fifo
#(
parameter data_width = 16,
parameter data_depth = 8,
parameter ram_depth = 256
)
(
input rst_n,
input wr_clk,
input wr_en,
input [data_width-1:0] data_in,
output full,
input rd_clk,
input rd_en,
output reg [data_width-1:0] data_out,
output empty
);
reg [data_depth-1:0] wr_adr;
reg [data_depth-1:0] rd_adr;
reg [data_depth:0] wr_adr_ptr;
reg [data_depth:0] rd_adr_ptr;
wire [data_depth:0] wr_adr_gray;
reg [data_depth:0] wr_adr_gray1;
reg [data_depth:0] wr_adr_gray2;
wire [data_depth:0] rd_adr_gray;
reg [data_depth:0] rd_adr_gray1;
reg [data_depth:0] rd_adr_gray2;
//dual port ram - write and read
assign wr_adr = wr_adr_ptr[data_depth-1:0];
assign rd_adr = rd_adr_ptr[data_depth-1:0];
integer i;
reg [data_width-1:0] ram_fifo [ram_depth-1:0];
always@(posedge wr_clk or negedge rst_n)begin
if(!rst_n)begin
for(i=0;i<ram_depth;i=i+1)
ram_fifo[i] <= 'd0;
end
else if(wr_en && (~full))
ram_fifo[wr_adr] <= data_in;
else
ram_fifo[wr_adr] <= ram_fifo[wr_adr];
end
always@(posedge rd_clk or negedge rst_n)begin
if(!rst_n)
data_out <= 'd0;
else if(rd_en && (~empty))
data_out <= ram_fifo[rd_adr];
else
data_out <= 'd0;
end
//wr_adr_ptr ++ and rd_adr_ptr ++
always@(posedge wr_clk or negedge rst_n)begin
if(!rst_n)
wr_adr_ptr <= 'd0;
else if(wr_en && (~full))
wr_adr_ptr <= wr_adr_ptr + 1'b1;
else
wr_adr_ptr <= wr_adr_ptr;
end
always@(posedge rd_clk or negedge rst_n)begin
if(!rst_n)
rd_adr_ptr <= 'd0;
else if(rd_en && (~empty))
rd_adr_ptr <= rd_adr_ptr + 1'b1;
else
rd_adr_ptr <= rd_adr_ptr;
end
//binary to gray
assign wr_adr_gray = (wr_adr_ptr >> 1) ^ wr_adr_ptr;
assign rd_adr_gray = (rd_adr_ptr >> 1) ^ rd_adr_ptr;
//gray cdc compare
always@(posedge wr_clk or negedge rst_n)begin
if(!rst_n)begin
rd_adr_gray1 <= 'd0;
rd_adr_gray2 <= 'd0;
end
else begin
rd_adr_gray1 <= rd_adr_gray;
rd_adr_gray2 <= rd_adr_gray1;
end
end
always@(posedge rd_clk or negedge rst_n)begin
if(!rst_n)begin
wr_adr_gray1 <= 'd0;
wr_adr_gray2 <= 'd0;
end
else begin
wr_adr_gray1 <= wr_adr_gray;
wr_adr_gray2 <= wr_adr_gray1;
end
end
assign empty = (rd_adr_gray == wr_adr_gray2)?1'b1:1'b0;
assign full = (wr_adr_gray[data_depth:data_depth-1] != rd_adr_gray2[data_depth:data_depth-1]) && (wr_adr_gray[data_depth-2:0] == rd_adr_gray2[data_depth-2:0]);
endmodule
//tb
`timescale 1ns / 1ps
module asyn_fifo_tb;
reg rst_n;
reg wr_clk;
reg wr_en;
reg [15:0] data_in;
wire full;
reg rd_clk;
reg rd_en;
wire [15:0] data_out;
wire empty;
asyn_fifo asyn_fifo_inst
(
.rst_n (rst_n),
.wr_clk (wr_clk),
.wr_en (wr_en),
.data_in (data_in),
.full (full),
.rd_clk (rd_clk),
.rd_en (rd_en),
.data_out (data_out),
.empty (empty)
);
initial wr_clk = 0;
always#10 wr_clk = ~wr_clk;
initial rd_clk = 0;
always#30 rd_clk = ~rd_clk;
always@(posedge wr_clk or negedge rst_n)begin
if(!rst_n)
data_in <= 'd0;
else if(wr_en)
data_in <= data_in + 1'b1;
else
data_in <= data_in;
end
initial begin
rst_n = 0;
wr_en = 0;
rd_en = 0;
#200;
rst_n = 1;
wr_en = 1;
#20000;
wr_en = 0;
rd_en = 1;
#20000;
rd_en = 0;
$stop;
end
endmodule
仿真波形图