实现
`timescale 1ns/1ps
module asyn_fifo#(
parameter data_width = 16,
parameter ram_depth = 256,
parameter ram_addr_width = 8
)
(
input rst,
input wr_clk,
input wr_en,
input [data_width-1:0] din,
input rd_clk,
input rd_en,
output reg valid,
output reg [data_width-1:0] dout,
output empty,
output full
);
reg[ram_addr_width: 0] wr_addr_ptr;
reg[ram_addr_width: 0] rd_addr_ptr;
wire[ram_addr_width - 1: 0] wr_addr;
wire[ram_addr_width - 1: 0] rd_addr;
wire[ram_addr_width: 0] wr_addr_ptr_gray;
wire[ram_addr_width: 0] rd_addr_ptr_gray;
reg[ram_addr_width: 0] wr_addr_ptr_gray_d1;
reg[ram_addr_width: 0] wr_addr_ptr_gray_d2;
reg[ram_addr_width: 0] rd_addr_ptr_gray_d1;
reg[ram_addr_width: 0] rd_addr_ptr_gray_d2;
reg[data_width - 1: 0] fifo_ram[ram_depth - 1: 0];
genvar i;
generate
for (i = 0; i < ram_depth; i = i + 1) begin:write_fifo
always@ (posedge wr_clk or negedge rst) begin
if (!rst)
fifo_ram[i] <= 'h0;
else if (wr_en && (~full) && wr_addr == i)
fifo_ram[i] <= din;
else
fifo_ram[i] <= fifo_ram[i];
end
end
endgenerate
always@(posedge rd_clk or negedge rst)
begin
if(!rst)
begin
dout <= 'h0;
valid <= 1'b0;
end
else if(rd_en && (~empty))
begin
dout <= fifo_ram[rd_addr];
valid <= 1'b1;
end
else
begin
dout <= 'h0;
valid <= 1'b0;
end
end
always@ (posedge wr_clk or negedge rst) begin
if(!rst)
wr_addr_ptr <= 'h0;
else if(wr_en && (~full))
wr_addr_ptr <= wr_addr_ptr + 1'b1;
else wr_addr_ptr <= wr_addr_ptr;
end
always@ (posedge rd_clk or negedge rst) begin
if(!rst)
rd_addr_ptr <= 'h0;
else if(rd_en && (~empty))
rd_addr_ptr <= rd_addr_ptr + 1'b1;
else
rd_addr_ptr <= rd_addr_ptr;
end
assign wr_addr = wr_addr_ptr[ram_addr_width - 1: 0];
assign rd_addr = rd_addr_ptr[ram_addr_width - 1: 0];
always@ (posedge rd_clk) begin
wr_addr_ptr_gray_d1 <= wr_addr_ptr_gray;
wr_addr_ptr_gray_d2 <= wr_addr_ptr_gray_d1;
end
always@ (posedge wr_clk) begin
rd_addr_ptr_gray_d1 <= rd_addr_ptr_gray;
rd_addr_ptr_gray_d2 <= rd_addr_ptr_gray_d1;
end
assign wr_addr_ptr_gray = (wr_addr_ptr >> 1) ^ wr_addr_ptr;
assign rd_addr_ptr_gray = (rd_addr_ptr >> 1) ^ rd_addr_ptr;
assign full = (wr_addr_ptr_gray == {~(rd_addr_ptr_gray_d2[ram_addr_width-:2]),rd_addr_ptr_gray_d2[ram_addr_width-2:0]}) ;
assign empty = ( rd_addr_ptr_gray == wr_addr_ptr_gray_d2 );
endmodule
测试
`timescale 1ns/1ps
module fif0_test();
parameter data_width = 16;
parameter ram_depth = 256;
parameter ram_addr_width = 8;
reg rst;
reg wr_clk;
reg wr_en;
reg [data_width-1:0] din;
reg rd_clk;
reg rd_en;
wire valid;
wire [data_width-1:0] dout;
wire empty;
wire full;
asyn_fifo #
(
.data_width (16),
.ram_depth (256),
.ram_addr_width (8)
)
( .rst(rst),
.wr_clk (wr_clk),
.wr_en(wr_en),
.din(din),
.rd_clk(rd_clk),
.rd_en(rd_en),
.valid(valid),
.dout(dout),
.empty(empty),
.full(full)
);
initial begin
rst = 1'b1;
#10 rst = 1'b0;
#20 rst = 1'b1;
wr_en = 1'b1;
rd_en = 1'b1;
#5000 rst = 1'b0;
#50 rst = 1'b1;
#9000 $finish;
end
initial begin
wr_clk = 1'b1;
forever #5 wr_clk = ~wr_clk;
end
initial begin
rd_clk = 1'b1;
forever #20 rd_clk = ~rd_clk;
end
initial begin
#10 din = 1'b0;
forever #10 din = din + 1'b1;
end
initial begin
$fsdbDumpfile("asyn_fifo.fsdb");
$fsdbDumpvars;
end
endmodule
仿真