同步和异步FIFO

同步和异步FIFO
FiFo外部是没有地址的,外部端口只负责读写,内部RAM有地址
同步和异步FIFO
FIFO可以在一边读,一边写,两边读写速度可不一样,
RAM中的控件可以重复利用,某个数据位读走后,可再存入新的数据。
两边速度不同的情况下,RAM的空间和两边读写速度满足一定的公式就可随意读写

FIFO中的RAM设计

module dp_ram #(parameter	DLY       = 1,
                          	RAM_WIDTH = 8,
                          	RAM_DEPTH = 16,
                          	ADDR_WIDTH= 4)
               (input       write_clock,
                input       read_clock,
                input       write_allow,
                input       read_allow,
                input       [ADDR_WIDTH-1:0] write_addr,
                input       [ADDR_WIDTH-1:0] read_addr,
                input       [RAM_WIDTH-1 :0] write_data,
                output  reg [RAM_WIDTH-1 :0] read_data);
    
    reg [RAM_WIDTH-1:0] memory[RAM_DEPTH-1:0];

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

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

同步FIFO的设计

同步和异步FIFO
FIFO原则:先进先出

同步FIFO的设计

1. 通过计数判断fifo空满

`timescale 1ns/10ps

module SYNCFIFO#(parameter  DATA_WIDTH = 8,
                            ADDR_WIDTH = 9)
                (input  wire                 fifo_rst,       //复位信号
                 input  wire                 clock,          //读写的同步时钟
                 input  wire                 read_enable,    
                 input  wire                 write_enable,
                 input  reg [DATA_WIDTH-1:0] write_data,
                 output reg [DATA_WIDTH-1:0] read_data,
                 output reg                  full,          //满信号
                 output reg                  empty,         //空信号    
                 output reg [ADDR_WIDTH-1:0] fcounter
                 );

    wire    read_allow   = (read_enable  && !empty);    //读允许+不空
    wire    write_allow  = (write_enable && !full);     //写允许+不满

    dp_ram fifo_ram(
        .write_clock(clock),
        .read_clock (clock),
        .write_allow(write_allow),
        .read_allow (read_allow),
        .read_addr  (read_addr),
        .write_addr (write_addr),
        .write_data (write_data),
        .read_data  (read_data)
    );
    
    /*
     * 1. 判断fifo的空满
     */
    always @(posedge clock or posedge fifo_rst)
        if(fifo_rst)
            empty <= 'b1;
        else
            empty <= (!write_enable && (fcounter[8:1] == 8'h0) && 
                     ((fcounter[0] == 0)||read_enable));

    always @(posedge clock or posedge fifo_rst)
        if(fifo_rst)
            full <= 'b1;
        else 
            full <=  (!read_enable && (fcounter[8:1] == 8'hFF) && 
                     ((fcounter[0] == 1)||write_enable));
    
    /* 
     * 2. 产生读写地址 
     */
    always @(posedge clock or posedge fifo_rst)
        if(fifo_rst)
            read_addr <= 'h0;
        else if(read_allow)
            read_addr <= read_addr + 'b1;

    always @(posedge clock or posedge fifo_rst)
        if(fifo_rst)
            write_addr <= 'h0;
        else if(write_allow)
            write_addr <= write_addr + 'b1;

    /*
     * 3. 读写计数(写:计数器加1;读:计数器减1)
     */
    always @(posedge clock or posedge fifo_rst)
        if(fifo_rst)
            fcounter <= 'h0;
        else if((!read_allow && write_allow)||(read_allow && !write_allow))
        begin
            if(write_allow) fcounter <= fcounter + 'b1;
            else fcounter <= fcounter - 'b1;
        end
endmodule

2. 通过地址扩展位判断fifo空满

module sync_fifo(
    input       clk,
                rst,
                write_enable,
                read_enable,
    input       [7:0] data_in,
    output  reg [7:0] data_out,
    output      empty,
                full
);
    /* 数据宽度为8bit,深度为16的RAM */
    reg [7:0] mem[15:0];    
    
    /* 地址 */
    wire[3:0] w_addr, w_addr;
    reg [4:0] r_addr_a, w_addr_a;

    assign r_addr = r_addr_a[3:0];
    assign w_addr = w_addr_a[3:0];
    
    /* 读 */
    always@(posedge clk or negedge rst) begin
        if(!rst)    
            r_addr_a <= 5'b0;   //复位,读地址清零
        else begin
            if(rd_en == 1 && empty == 0) begin  //当读允许,非空时执行
                data_out <= mem[r_addr];        //读出数据
                r_addr_a <= r_addr_a + 1;       //读地址加1
            end
        end
    end
    
    /* 写 */
    always@(posedge clk or negedge rst) begin
        if(!rst)    
            w_addr_a <= 5'b0;   //复位,写地址清零   
        else begin
            if(wr_en == 1 && full == 0) begin   //当写允许,非满时执行
                mem[w_addr] <= data_in;         //数据写入指定地址
                w_addr_a <= w_addr_a + 1;       //写地址加1
            end
        end
    end

    /* 判断空满 */
    assign empty = (r_addr_a == w_addr_a) ? 1 : 0;
    assign full  = (r_addr_a[4] != w_addr_a[4] && 
                    r_addr_a[3:0] == w_addr_a[3:0]) ? 1 : 0;

endmodule
上一篇:HTML_Day1


下一篇:Java day1