FIFO设计

  • 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_counter
#(
    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  reg [RAM_WIDTH-1:0]    r_data,
    output  wire                     empty,
    output  wire                     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
module sync_fifo_tb();

parameter ADDR_WIDTH = 4;
parameter RAM_WIDTH = 8;
parameter RAM_DEPTH = 16;

reg fifo_clk;
reg fifo_rst_n;
reg read_en;
reg write_en;
reg [RAM_WIDTH-1:0] w_data;
wire [RAM_WIDTH-1:0] rdata;
wire empty;
wire full;

// 例化模块 - 省略
sync_fifo u_sysc_fifo(
    .fifo_clk    (fifo_clk  )   ,
    .fifo_rst_n  (fifo_rst_n)   ,
    .read_en     (read_en   )   ,
    .write_en    (write_en  )   ,
    .w_data      (w_data    )   ,
    .r_data      (r_data    )   ,
    .empty       (empty     )   ,
    .full        (full      ) 
);



initial begin
    fifo_rst_n = 1;
    fifo_clk = 0;
    #1 fifo_rst_n = 0;
    #5 fifo_rst_n = 1;
end

always #20 fifo_clk = ~fifo_clk;

initial begin
    write_en = 0;
    #1 write_en = 1;
end

initial begin 
    read_en = 0;
    #650 read_en = 1;
    write_en = 0;
end



initial begin
    w_data = 8'h0;
    #40 w_data = 8'h1;
    #40 w_data = 8'h2;
    #40 w_data = 8'h3;
    #40 w_data = 8'h4;
    #40 w_data = 8'h5;
    #40 w_data = 8'h6;
    #40 w_data = 8'h7;
    #40 w_data = 8'h9;
    #40 w_data = 8'ha;
    #40 w_data = 8'hb;
    #40 w_data = 8'hc;
    #40 w_data = 8'hd;
    #40 w_data = 8'he;
    #40 w_data = 8'hf;
    #200 $finish;
end

initial begin
    $vcdpluson();
end

endmodule
posted @ 2024-01-13 21:38  Icer_Newer  阅读(13)  评论(0编辑  收藏  举报