异步FIFO(verilog简单实现)

对其他网友的代码进行了改进纠正,使代码更加完整,并用vivado2020.1进行了仿真测试

源代码(不到100行):

`timescale 1ns/1ps
module test #(parameter  data_width =4,depth =8,addr_width=3)(
    wclk,rst_w,w_en,din,w_ptr,
    rclk,rst_r,r_en,dout,r_ptr,
    fifo_empty,fifo_full
);
input wclk,rst_w,w_en;
input rclk,rst_r,r_en;
input [data_width-1:0]din;
output fifo_empty,fifo_full;
output reg[data_width-1:0]dout;
output reg [addr_width:0]w_ptr,r_ptr;//读写指针

wire [addr_width:0] w_ptr2gray, r_ptr2gray;
reg [addr_width:0] w_ptr2gray1,w_ptr2gray2;
reg [addr_width:0] r_ptr2gray1,r_ptr2gray2;

wire [addr_width-1:0] w_addr,r_addr;//读写地址

reg [data_width-1:0]ram[depth-1:0];//ram存储器
//地址与指针的关系
assign w_addr=w_ptr[addr_width-1:0];
assign r_addr=r_ptr[addr_width-1:0];

//二进制码->格雷码
assign w_ptr2gray=w_ptr^(w_ptr>>1);
assign r_ptr2gray=r_ptr^(r_ptr>>1);

//格雷码同步,w_ptr同步到rclk时钟域
always @(posedge rclk or negedge rst_r) begin
    if(!rst_r)begin
        w_ptr2gray1<=0;
        w_ptr2gray2<=0;
    end
    else begin
        w_ptr2gray1<=w_ptr2gray;
        w_ptr2gray2<=w_ptr2gray1;
    end   
end

//格雷码同步,r_ptr同步到wclk时钟域
always @(posedge wclk or negedge rst_w) begin
    if(!rst_w)begin
        r_ptr2gray1<=0;
        r_ptr2gray2<=0;
    end
    else begin
        r_ptr2gray1<=r_ptr2gray;
        r_ptr2gray2<=r_ptr2gray1;
    end   
end

//写FIFO
always @(posedge wclk or negedge rst_w) begin
    if(!rst_w)begin
        w_ptr<=0;
    end
    else if(w_en && !fifo_full) begin
        ram[w_addr]<=din;
        w_ptr<=w_ptr+1;
    end
    else begin
        w_ptr<=w_ptr;
        ram[w_addr]<=ram[w_addr];
    end
end

//读FIFO
always @(posedge rclk or negedge rst_r) begin
    if(!rst_r)begin
        r_ptr<=0;
        dout<=0;
    end
    else if(r_en && !fifo_empty) begin
        dout<=ram[r_addr];
        r_ptr<=r_ptr+1;
    end
    else begin
        r_ptr<=r_ptr;
    end
end

//产生fifo_empty、fifo_full
assign fifo_empty=(w_ptr2gray2 == r_ptr2gray);
assign fifo_full=({~w_ptr2gray[addr_width:addr_width-1],w_ptr2gray[addr_width-2:0]} == r_ptr2gray2 );

endmodule

仿真测试:

`timescale 1ns / 1ps

module test_sim;
parameter  data_width =4,depth =8,addr_width=3;
reg wclk,rst_w,w_en;
reg rclk,rst_r,r_en;
reg [data_width-1:0]din;
wire fifo_empty,fifo_full;
wire[data_width-1:0]dout;
wire [addr_width:0]w_ptr,r_ptr;//读写指针

always #10 wclk=~wclk;
always #4 rclk=~rclk;
always @(posedge wclk) begin
    din<={$random%16};   
end
initial begin
    wclk=0;rclk=0;
    rst_w=1;rst_r=1;
    din=0;
    {w_en,r_en}=2'b00;
    #4 rst_w=0;rst_r=0; 
    #10 rst_w=1;rst_r=1;

    #200 {w_en,r_en}=2'b10;
    #200 {w_en,r_en}=2'b01;
    #100 {w_en,r_en}=2'b11;
  //  #200 $stop;
end

test m1(
   .wclk(wclk),
   .rst_w(rst_w),
   .w_en(w_en),
   .din(din),
   .w_ptr(w_ptr),
   .rclk(rclk),
   .rst_r(rst_r),
   .r_en(r_en),
   .dout(dout),
   .r_ptr(r_ptr),
   .fifo_empty(fifo_empty),
   .fifo_full(fifo_full)
);
endmodule

vivado2020仿真结果

异步FIFO(verilog简单实现)_第1张图片
异步FIFO(verilog简单实现)_第2张图片

理论讲解请参考:

异步FIFO—Verilog实现
同步FIFO与异步FIFO
【FPGA——基础篇】同步FIFO与异步FIFO——Verilog实现

你可能感兴趣的:(数字IC/FPGA,fifo,fpga开发,verilog,面试,芯片)