两种简单的同步fifo(不同的输出时序)

本文介绍了简单FIFO的设计要点及其实现细节,包括输入输出端口定义、空满信号处理、读写逻辑控制等,并提供了RTL代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单fifo的设计在这推一波西南交通大学邸志雄老师的课

fifo的输入输出端口如上图所示。

本次设计fifo输入输出32位,深度为8,读写信号由上游发送,空满信号由fifo产生。

设计要点:

1.在实际应用中,write信号和read信号由上游模块给出,有可能存在fifo满了,write信号还没有拉低的情况;或者说上游节点write信号不拉低,只是说收到了full信号后当前数据不发生变化,这就需要考虑到full信号拉高的时候的时序问题,如果没处理好就可能会丢失掉最后一个数据,就如下图所示。

假设fifo深度为n,如果使用时序逻辑,full信号在第n个时钟上升沿拉高,但要下一个时钟上升沿才能检测到,然后write信号才能拉低。此时的第n+1个数据已经发送出去了,fifo又满了,无法写入,就会造成数据丢失。此处可以用almost_full解决这个问题,在fifo快满的时候提示上游节点别发送新数据。本设计没使用almost_full信号,使用了组合逻辑:用full信号取反&w_en信号,用这个条件来控制fifo是否继续写入。此时write信号拉低与否就跟我fifo是否写入没有太大关系了:write信号就算拉高我也不一定写,write信号拉低我一定不写。组合结果就如上图红笔所示,写使能信号在full信号拉低后自己马上拉低,上游节点可以通过这个信号来判断是否继续发送数据,就不会造成数据丢失。(注,时序逻辑的情况下,write信号就是写使能信号,用组合逻辑full信号取反&w_en信号才是写使能)

2.在read方面,也有两种读的方式。假如同时读写,第一种情况是写入的数据马上能读出,使用组合逻辑;第二种情况就是写进去的数据,至少要在下一个时钟沿的时候才能读,使用时序逻辑,具体实现见代码。

3.读写与空满的情况。读写与空满有四种组合:读空(读信号有效与fifo空,后面类似),读满,写空,写满。读满和写空两种情况基本不用考虑,一定能成功,主要是看写满,读空的情况,这两种情况又主要是看读写指针的位置,如何判断空满参考上面推荐的课程(免费的),讲的很仔细。

RTL代码:

module fifo#(
    parameter RAM_WIDTH     = 6'd32,
    parameter RAM_DEPTH     = 4'd8,
    parameter ADDR_WIDTH    = 3'd4
)(
    input                   clock,
    input                   resetn,
    input       [RAM_WIDTH-1:0]      data_in,
    input                   write_en,
    input                   read_en,
    output      [RAM_WIDTH-1:0]      data_out,
    output                  full,
    output                  empty
);

    reg     [ADDR_WIDTH-1:0]        write_addr;
    reg     [ADDR_WIDTH-1:0]        read_addr;
    reg     [RAM_WIDTH-1:0]         RAM[RAM_DEPTH-1:0];

    always@(posedge clock or negedge resetn)
        if(!resetn)
            write_addr <= 'b0;
        else if(full == 1'b0 && write_en == 1'b1)
            write_addr <= write_addr + 1'b1;
        else
            write_addr <= write_addr;
    
    always@(posedge clock or negedge resetn)
        if(!resetn)
            read_addr <= 'b0;
        else if(empty == 1'b0 && read_en == 1'b1)
            read_addr <= read_addr + 1'b1;
        else
            read_addr <= read_addr;
    
    always@(posedge clock)begin
        if(full == 1'b0 && write_en == 1'b1)
            RAM[write_addr[2:0]] <= data_in;
        // if(empty == 1'b0 && read_en == 1'b1)   //延时一拍后输出,需要把data_out改成output reg类型
        //     data_out <= RAM[read_addr[2:0]];
    end

    assign data_out = (empty == 1'b0 && read_en == 1'b1)?RAM[read_addr[2:0]]:'b0;//组合逻辑输出
    assign empty = (write_addr == read_addr)?1'b1:1'b0;//空信号判断
    assign full  = ((write_addr[ADDR_WIDTH-1] != read_addr[ADDR_WIDTH-1]) && (write_addr[ADDR_WIDTH-2:0] == read_addr[ADDR_WIDTH-2:0]))?1'b1:1'b0;//满信号判断

endmodule 

Simulation:

testbench随便写写吧。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值