FIFO设计

发布时间 2024-01-13 21:40:53作者: Icer_Newer
  • first in first out,先进先出
  • fifo是基于RAM进行设计的

双端口RAM设计(16*8)

  • 如果大的RAM可以调用IP
  • RAM的关键参数:深度和宽度
module dual_ram
#(
    parameter ADDR_WIDTH = 4,
    parameter RAM_WIDTH = 8,
    parameter DLY=1
)
(
    input   wire                        read_clk    ,
    input   wire                        write_clk   ,
    input   wire    [ADDR_WIDTH-1:0]    read_addr   ,
    input   wire    [ADDR_WIDTH-1:0]    write_addr  ,
    input   wire                        read_allow  ,
    input   wire                        write_allow ,
    input   wire    [RAM_WIDTH-1:0]     write_data  ,
    output  reg   [RAM_WIDTH-1:0]     read_data   
);

    reg [RAM_WIDTH-1:0] memory [ADDR_WIDTH-1:0];

    always @(posedge read_clk) begin
        if(read_allow)
            read_data <= #DLY memory[read_addr];
    end

    always @(posedge write_clk) begin
        if(write_allow)
            memory[write_addr] <= #DLY write_data;
    end

endmodule

单端口ram

module single_port_ram
#(
    parameter ADDR_WIDTH = 8,
    parameter RAM_WIDTH = 8,
    parameter RAM_DEPTH = 255,
    parameter DLY = 1
)
(
    input   wire                    clk,
    input   wire                    rst_n,
    input   wire [ADDR_WIDTH-1:0]   addr,
    input   wire                    wr_en, // 1-write 0-read
    input   wire [RAM_WIDTH-1:0]    wdata,

    output  wire [RAM_WIDTH-1:0]    rata
);

reg [RAM_DEPTH-1:0] mem [RAM_WIDTH-1:0];

integer i;
always @(posedge clk or negedge rst_n) begin
    if(rst_n)
        for(i=0;i<=255;i=i+1) begin
            mem[i] = 16'h0000;
        end
    else if(wr_en)
        mem[addr] <= wdata;
end


assign radta = (!wr_en) ? mem[addr] : 16'h0000 ;

// always @(posedge clk or negedge rst_n) begin
//     if(!rst_n)
//         radta <= 'h0;
//     else if(!wr_en)
//         r_data <= mem[addr];
// end

endmodule

同步FIFO设计

module sync_fifo
#(
    parameter ADDR_WIDTH = 9,
    parameter RAM_WIDTH = 8
)
(
    input   wire                    fifo_clk,
    input   wire                    fifo_rst_n,
    input   wire                    read_en,
    input   wire                    write_en,
    input   wire [RAM_WIDTH-1:0]    w_data,
    output  wire [RAM_WIDTH-1:0]    r_data,
    output  reg                     empty,
    output  reg                     full,
    output  reg [ADDR_WIDTH-1:0]    fcounter
);

    reg [ADDR_WIDTH-1:0]    write_addr;
    reg [ADDR_WIDTH-1:0]    read_addr;

    wire write_allow = write_en && (!empty);
    wire read_allow = read_en && (!full);


    // empty 
    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(fifo_rst_n)
            empty <= 1'b1;
        else
            empty <= (!write_allow) && (fcounter[ADDR_WIDTH-1:1] == 8'h0) && (fcounter[0] == 0||read_allow);    
    end

    // full
    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(fifo_rst_n)
            full <= 1'b0;
        else
            full <= (!read_allow) && (fcounter[ADDR_WIDTH-1:1] == 8'hff) && (fcounter[0] == 1||write_allow);    
    end

    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(fifo_rst_n)
            fcounter <= {ADDR_WIDTH{1'b0}};
        else if( (!read_allow) && (write_allow)||(read_allow) && (!write_allow)) begin
                if(write_allow)
                    fcounter <= fcounter + 1'b1;
                else
                    fcounter <= fcounter - 1'b1;        
        end
    end
    
    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(fifo_rst_n)
            write_addr <= {ADDR_WIDTH{1'b0}};
        else if(write_allow)
            write_addr <= write_addr + 1'b1;
        end

    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(fifo_rst_n)
            read_addr <= {ADDR_WIDTH{1'b0}};
        else if(write_allow)
            read_addr <= read_addr + 1'b1;
        end


    dual_ram u_dual_ram
    (
        .read_clk    (fifo_clk),
        .write_clk   (fifo_clk),
        .read_addr   (read_addr),
        .write_addr  (write_addr),
        .read_allow  (read_allow),
        .write_allow (write_allow),
        .write_data  (w_data),
        .read_data   (r_data)
    );
endmodule
module sync_fifo
#(
    parameter ADDR_WIDTH = 4,
    parameter RAM_WIDTH = 8,
    parameter RAM_DEPTH = 16,
)
(
    input   wire                    fifo_clk,
    input   wire                    fifo_rst_n,
    input   wire                    read_en,
    input   wire                    write_en,
    input   wire [RAM_WIDTH-1:0]    w_data,
    output  wire [RAM_WIDTH-1:0]    r_data,
    output  reg                     empty,
    output  reg                     full
);

    // 指针
    reg [ADDR_WIDTH:0]    write_addr;
    reg [ADDR_WIDTH:0]    read_addr;
    wire    [ADDR_WIDTH-1:0] w_addr;
    wire    [ADDR_WIDTH-1:0] r_addr;

    wire write_allow = write_en && (!empty);
    wire read_allow = read_en && (!full);

    reg [RAM_WIDTH-1:0] mem [RAM_DEPTH-1:0];

    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(!fifo_rst_n)
            read_addr <= {ADDR_WIDTH{1'b0}};
        else if(read_allow) begin 
            r_data <= mem[read_addr];
            read_addr <= read_addr + 1;
        end
    end

    always @(posedge fifo_clk or negedge fifo_rst_n) begin
        if(!fifo_rst_n)
            write_addr <= {ADDR_WIDTH{1'b0}};
        else if(write_allow) begin 
            mem[write_addr] <= w_data;
            write_addr <= write_addr + 1;
        end
    end

    assign empty = read_addr == write_addr ? 1 : 0;
    assign full = (read_addr[ADDR_WIDTH]!=write_addr[ADDR_WIDTH]) &&
                (read_addr[ADDR_WIDTH-1:0] == write_addr[ADDR_WIDTH-1:0]);

    assign r_addr = read_addr[ADDR_WIDTH-1:0]
    assign w_addr = write_addr[ADDR_WIDTH-1:0]
endmodule