异步FIFO的Verilog HDL设计实现

2020-07-02  本文已影响0人  一条摸水鱼

1.FIFO简介

2.代码实现

module sv_test #(
    parameter AWIDTH = 4,
    parameter DWIDTH = 8,
    parameter DEPTH  = 1 << AWIDTH
)(
    input logic rst_n,
    input logic wr_clk,
    input logic rd_clk,
    input logic wr_en,
    input logic rd_en,
    input logic [DWIDTH-1:0] din,
    output logic fifo_full,
    output logic fifo_empty,
    output logic dout_valid,
    output logic [DWIDTH-1:0] dout
);

    logic is_in, is_out;
    logic [AWIDTH:0] wptr_bin, wptr_gray, next_wptr_bin, next_wptr_gray, sync_wptr_bin, sync_wptr_gray, sync_wptr_gray_dff;
    logic [AWIDTH:0] rptr_bin, rptr_gray, next_rptr_bin, next_rptr_gray, sync_rptr_bin, sync_rptr_gray, sync_rptr_gray_dff;
    logic [AWIDTH-1:0] raddr, waddr;
    logic [DWIDTH-1:0] ram [DEPTH];

    assign is_in = wr_en & (~fifo_full);//judge if data should be written in async_fifo
    assign is_out = rd_en & (~fifo_empty);//judge if data should be read from async_fifo

    always @(posedge wr_clk or negedge rst_n) begin
        if(!rst_n) begin
            wptr_bin <= 'b0;
        end
        else if(is_in) begin
            wptr_bin <= wptr_bin + 1'b1;
        end
    end

    always @(posedge rd_clk or negedge rst_n) begin
        if(!rst_n) begin
            rptr_bin <= 'b0;
        end
        else if(is_out) begin
            rptr_bin <= rptr_bin + 1'b1;
        end
    end

    assign wptr_gray = wptr_bin ^ (wptr_bin>>1);
    assign rptr_gray = rptr_bin ^ (rptr_bin>>1);
    assign next_wptr_bin = wptr_bin + 1'b1;
    assign next_rptr_bin = rptr_bin + 1'b1;
    assign next_wptr_gray = next_wptr_bin ^ (next_wptr_bin>>1);
    assign next_rptr_gray = next_rptr_bin ^ (next_rptr_bin>>1);

    //wptr_gray should be stable in rd_clk
    always @(posedge rd_clk or negedge rst_n) begin
        if(!rst_n) begin
            sync_wptr_gray_dff <= 'b0;
            sync_wptr_gray <= 'b0;
        end
        else begin
            sync_wptr_gray_dff <= wptr_gray;
            sync_wptr_gray <= sync_wptr_gray_dff;
        end
    end

    //rptr_gray should be stable in wr_clk
    always @(posedge wr_clk or negedge rst_n) begin
        if(!rst_n) begin
            sync_rptr_gray_dff <= 'b0;
            sync_rptr_gray <= 'b0;
        end
        else begin
            sync_rptr_gray_dff <= rptr_gray;
            sync_rptr_gray <= sync_rptr_gray_dff;
        end
    end

    //judge if fifo_full signal should be pull up
    assign fifo_full = ((sync_rptr_gray[AWIDTH] != wptr_gray[AWIDTH])
                && ((sync_rptr_gray[AWIDTH]^sync_rptr_gray[AWIDTH-1]) == (wptr_gray[AWIDTH]^wptr_gray[AWIDTH-1]))
                && (sync_rptr_gray[AWIDTH-2:0] == (wptr_gray[AWIDTH-2:0])));

    //judge if fifo_empty signal should be pull up
    assign fifo_empty = (sync_wptr_gray == rptr_gray); 

    always @(posedge wr_clk or negedge rst_n) begin
        if(!rst_n) begin
            waddr <= 'b0;
        end
        else if(is_in) begin
            waddr <= next_wptr_bin[AWIDTH-1:0];
        end
    end

    always @(posedge rd_clk or negedge rst_n) begin
        if(!rst_n) begin
            raddr <= 'b0;
        end
        else if(is_out) begin
            raddr <= next_rptr_bin[AWIDTH-1:0];
        end
    end

    always @(posedge wr_clk or negedge rst_n) begin
        if(is_in) begin
            ram[waddr] <= din;
        end
    end

    always @(posedge rd_clk or negedge rst_n) begin
        if(!rst_n) begin
            dout_valid <= 'b0;
        end
        else if(is_out) begin
            dout_valid <= 'b1;
            dout <= ram[raddr];
        end
        else begin
            dout_valid <= 'b0;
        end
    end
endmodule
module tb_sv_test #(
    parameter AWIDTH = 4,
    parameter DWIDTH = 8,
    parameter DEPTH  = 1 << AWIDTH
)();
    logic rst_n;
    logic wr_clk;
    logic rd_clk;
    logic wr_en;
    logic rd_en;
    logic [DWIDTH-1:0] din;
    logic fifo_full;
    logic fifo_empty;
    logic dout_valid;
    logic [DWIDTH-1:0] dout;

    sv_test my_top( .rst_n(rst_n),
                    .wr_clk(wr_clk),
                    .rd_clk(rd_clk),
                    .wr_en(wr_en),
                    .rd_en(rd_en),
                    .din(din),
                    .fifo_full(fifo_full),
                    .fifo_empty(fifo_empty),
                    .dout_valid(dout_valid),
                    .dout(dout)
                    );

    initial begin
        wr_clk = 0;
        rd_clk = 0;
        fork
            forever begin
                #5 wr_clk = ~wr_clk;
            end
            forever begin
                #20 rd_clk = ~rd_clk;
            end
        join_none
    end

    initial begin
        wr_en = 0;
        rd_en = 0;
        rst_n = 0;
        #25;
        rst_n = 1;
        #10;
        fork
            forever begin
                din = $urandom_range(0,255);
                #2;
                #0;
                wr_en = 1;
                #10;
                #0;
                wr_en = 0;
            end
        join_none
        #500;
        fork
            forever begin
                #0;
                rd_en = 1;
                #40;
                rd_en = 0;
                #2;
            end
        join_none
    end

    initial begin
        #3000;
        $finish;
    end

    // dump fsdb
    `ifdef DUMP
    initial begin//do_not_remove 
        $fsdbAutoSwitchDumpfile(1000, "./fsdb/test_fsdb.fsdb", 10);//do_not_remove 
        $fsdbDumpvars(0, my_top);//do_not_remove 
        $fsdbDumpMDA(1000, my_top);//do_not_remove 
        // $fsdbDumpflush();//do_not_remove 
        //$fsdbDumpvars("+all");//do_not_remove 
    end//do_not_remove 
    `endif

endmodule
上一篇 下一篇

猜你喜欢

热点阅读