手撕verilog代码——异步FIFO

手撕代码——异步FIFO

module asynfifo (
    input rd_clk,
    input wr_clk,
    input rst_n,
    input rd_en,
    input wr_en,
    input [7:0] datain,
    output reg empty,
    output reg full,
    output reg [7:0] dataout
);
    reg [9:0] rd_addr;
    reg [9:0] wr_addr;
    wire [9:0] rd_ptr;
    wire [9:0] wr_ptr;

    wire rd_allow;
    wire wr_allow;

    assign rd_allow= rd_en && !empty && !rst_n;
    assign wr_allow= wr_en && !full && !rst_n;
//DUALRAM
    reg [7:0] RAM_DATA[511:0];

    always @(posedge wr_clk ) begin
            if (wr_allow) begin
                RAM_DATA[wr_addr[8:0]] <=datain;
            end
    end

    always @(posedge rd_clk) begin
        if (rd_allow) begin
                dataout<=RAM_DATA[rd_addr[8:0]];
            end
    end
    //addr change
    always @(posedge wr_clk ) begin
        if(rst_n) begin
            wr_addr<=10'd0;
        end
        else if(wr_allow)begin
            wr_addr<=wr_addr+1'b1;
        end
        else begin
            wr_addr<=wr_addr;
        end
    end

    always @(posedge rd_clk ) begin
        if(rst_n) begin
            rd_addr<=10'd0;
        end
        else if(rd_allow) begin
            rd_addr<=rd_addr+1'b1;
        end
        else begin
            rd_addr<=rd_addr;
        end
    end
    //指针跨时钟域传递
    reg [9:0] rd_ptr_to_wr1;
    reg [9:0] rd_ptr_to_wr2;

    reg [9:0] wr_ptr_to_rd1;
    reg [9:0] wr_ptr_to_rd2;

    always @(posedge rd_clk) begin
        if(rst_n) begin
            wr_ptr_to_rd1<=10'd0;
            wr_ptr_to_rd2<=10'd0;
        end
        else begin
            wr_ptr_to_rd1<=wr_ptr;
            wr_ptr_to_rd2<=wr_ptr_to_rd1;
        end
    end

    always @(posedge wr_clk) begin
            if(rst_n) begin
                rd_ptr_to_wr1<=10'd0;
                rd_ptr_to_wr2<=10'd0;
            end
            else begin
                rd_ptr_to_wr1<=rd_ptr;
                rd_ptr_to_wr2<=rd_ptr_to_wr1;
            end
        end

    //格雷码转换


          assign  rd_ptr= rd_addr^(rd_addr>>1);


//always@(posedge wr_clk)begin
//        if(rst_n) begin
//            wr_ptr<=10'b0;
//        end
//        else begin
           assign wr_ptr= wr_addr^(wr_addr>>1);
//        end
//    end


    //空
    always @(posedge rd_clk) begin
        if(rst_n) begin
            empty <=1'b1;
        end
        else if(rd_ptr==wr_ptr_to_rd2) begin
            empty <=1'b1;
        end
        else begin
            empty <=1'b0;
        end
    end

    //满
    always @(posedge wr_clk) begin
        if(rst_n) begin
            full <=1'b1;
        end
        else if((wr_ptr[9]!=rd_ptr_to_wr2[9])&&(wr_ptr[7:0]==rd_ptr_to_wr2[7:0])&&(wr_ptr[8]!=rd_ptr_to_wr2[8])) begin
            full <=1'b1;
        end
        else begin
            full<=1'b0;
        end
    end
endmodule
posted @ 2022-03-15 10:02  passchen  阅读(285)  评论(0编辑  收藏  举报