同步FIFO

同步FIFO架构

下图展示了一个同步FIFO的通用架构。DPRAM(双端口RAM)用作FIFO的存储器以使读、写可以独立进行
在这里插入图片描述
通过读、写指针产生各自的读、写地址,送到读、写端口。写指针指向下一个要写入的地址,读指针指向下一个要读取的地址。有效写使能使写地址递增,而有效的读使能使读指针递增。

在上图中的状态模块产生fifo_emptyfifo_full信号。如果fifo_full有效,说明FIFO内的空间已满不能再写入数据。如果fifo_empty有效说明FIFO内没有可供读取的下一个有效数据。通过对两个指针进行相同的逻辑,该模块也指示出任意时刻FIFO中空或满区域的个数。

双端口存储器(DPRAM)可以同步读取或异步读取。对于同步读操作,应该在数据在FIFO输出端有效前提供明确的读信号。对于异步读操作,DPRAM没有寄存的数据输出;有效数据在写入后即可用(先读数据然后递增指针值)。

空满信号判断方法

第一种方法:通过多设置一位的读写指针信号判断空满,当读写指针相等时则为空,当读写指针最高位相反,其余为相等时则为满(相当于写指针比读指针多绕了一圈)。
第二种方法:设置一个额外的计数器来判断,计数器在复位时初始化为0。随后的任何写操作会使其递增1,任何读操作会使其递减1。当计数器的值为0时则为空,当计数器的值等于FIFO深度时,则为满。
但是该方法比第一种方法相比效率要低一些。因为这种方法要求增加额外的硬件来产生FIFO空和满的条件。随着FIFO深度的增加,比较器的宽度也会增加。

设计代码

代码设计要点主要为读写指针的控制,且根据读写指针的大小关系判断空满,
且代码设计为满后即使写使能拉高也不能往里写数据,为空后即使读使能拉高后也读取不了数据,



module syn_fifo#(
        parameter DATA_WIDTH = 16,
        parameter DEPTH = 8)
        (        
                input clk,
                input rst,
                
                input wr_en,
                input [DATA_WIDTH-1:0]wdata,
                
                input rd_en,
                output reg [DATA_WIDTH-1:0]rdata,
                output reg full,
                output reg empty);
                
    reg [DATA_WIDTH-1:0]ram[DEPTH-1:0];
    reg [$clog2(DEPTH):0]wpoint,rpoint;
    wire full_r,empty_r;

    assign empty_r = (wpoint == rpoint);
    assign full_r = ((wpoint[$clog2(DEPTH)]!=rpoint[$clog2(DEPTH)])&&(wpoint[$clog2(DEPTH)-1:0]==rpoint[$clog2(DEPTH)-1:0]));
    
    always@(posedge clk or negedge rst)begin
    if(rst)begin
        full <= 1'b0;
        empty <= 1'b0;
    end
    else if(full_r)
        full <= 1'b1;
    else if(empty_r)
        empty <= 1'b1;
    else begin
        full <= 1'b0;
        empty <= 1'b0;
    end
    end
    
    always@(posedge clk or negedge rst)begin
        if(rst)
            wpoint <= 0;
        else if(wr_en&&(!full_r))
            wpoint <= wpoint + 1;
        end
     always@(posedge clk or negedge rst)begin
            if(rst)
                rpoint <= 0;
            else if(rd_en&&(!empty_r))
                rpoint <= rpoint + 1;
            end       
    always@(posedge clk or negedge rst)begin
        if(rst)
            ram[wpoint[$clog2(DEPTH)-1:0]] <= 0;
        else if(wr_en&&(!full_r))
            ram[wpoint[$clog2(DEPTH)-1:0]] <= wdata;
     end
    always@(posedge clk or negedge rst)begin
         if(rst)
             rdata <= 0;
         else if(rd_en&&(!empty_r))
             rdata <=ram[rpoint[$clog2(DEPTH)-1:0]];
      end
        
            
                
endmodule
                

仿真文件

module tb();
parameter DATA_WIDTH = 8;
parameter DEPTH = 8;
reg clk,rst;
reg wr_en;


                     
reg [DATA_WIDTH-1:0]wdata;     
                           
reg rd_en;                     
wire [DATA_WIDTH-1:0]rdata;
wire full, empty;               



initial begin
clk = 1;
rst = 1;
wr_en = 0;
rd_en = 0;
wdata = 0;

end

always #10 clk = ~clk;

initial begin
#25;
rst = 1'b0;
#3;
wr_en = 1;
repeat(9)begin
    @(negedge clk)
        wdata = $random;
end

@(negedge clk)
wr_en = 0;
rd_en = 1;

repeat(8)begin
    @(negedge clk);
end

end

 syn_fifo #(
        .DATA_WIDTH(DATA_WIDTH),
        .DEPTH(DEPTH))
        inst (        
                .clk(clk),
                .rst(rst),
                
                .wr_en(wr_en),
                .wdata(wdata),
                
                .rd_en(rd_en),
                .rdata(rdata),
                .full(full),
                .empty(empty));




endmodule




这里设计深度为8,但设置了九个输入数据。可以看到01并没有写入到ram中
在这里插入图片描述
读数据
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值