Altera的单时钟同步FIFO,带almost_empty和almost_full端口

相关文章
1.Altera的单时钟同步FIFO,带almost_empty和almost_full端口https://blog.csdn.net/qq_39485231/article/details/105345164
2.Altera的单时钟同步FIFO,带empty和full端口https://blog.csdn.net/qq_39485231/article/details/105351146
3.Altera的异步FIFO,读写用同频不同相时钟https://blog.csdn.net/qq_39485231/article/details/105352597
4.Altera的异步FIFO学习心得https://blog.csdn.net/qq_39485231/article/details/105364241

程序

module ip_fifo_a  //顶层模块
    (
        input   sys_clk,
        input   sys_rst_n
    );
    
wire            wrreq;
wire    [7:0]   data;
wire            empty;
wire            full;
wire     [7:0]  usedw;
wire            almost_empty;
wire            almost_full;

wire            rdreq;
wire    [7:0]   q;


//例化FIFO模块
fifo u_fifo(
    .clock          (sys_clk),
    .data           (data),
    .rdreq          (rdreq),
    .wrreq          (wrreq),
    
    .almost_empty   (almost_empty),
    .almost_full    (almost_full),
    .empty          (empty),
    .full           (full),
    .q              (q),
    .usedw          (usedw)
    
);

//例化写FIFO模块
fifo_wr u_fifo_wr(
    .clk     (sys_clk ),          // 写时钟
    .rst_n   (sys_rst_n),         // 复位信号

    .wrreq   (wrreq   ),          // 写请求
    .data    (data    ),          // 写入FIFO的数据
    .empty   (almost_empty ),          // 写空信号
    .full    (almost_full  )           // 写满信号
);

//例化读FIFO模块
fifo_rd u_fifo_rd(
    .clk     (sys_clk ),          // 读时钟
    .rst_n   (sys_rst_n),         // 复位信号

    .rdreq   (rdreq   ),          // 读请求
    .data    (q       ),          // 从FIFO输出的数据
    .empty   (almost_empty ),          // 读空信号
    .full    (almost_full  )           // 读满信号

);

endmodule 
module fifo_rd   //读模块
    (
        input           clk,
        input           rst_n,
        
        input   [7:0]   data,
        input           full,
        input           empty,
        output  reg     rdreq
    );
    
reg [7:0]   data_fifo;
reg [1:0]   flow_cnt;

always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
                rdreq <= 1'b0;
                data_fifo <= 8'b0;
                flow_cnt <= 2'd0;
            end
        else
            begin
                case(flow_cnt)
                    2'd0:begin
                            if(full)
                                begin
                                    rdreq <= 1'b1;
                                    flow_cnt <= flow_cnt + 1'b1;
                                end
                            else
                                flow_cnt <= flow_cnt;
                         end
                    2'd1:begin
                            if(empty)
                                begin
                                    rdreq <= 1'b0;
                                    flow_cnt <= 2'b0;
                                    data_fifo <= 8'd0;
                                end
                            else
                                begin
                                    data_fifo <= data;
                                    rdreq <= 1'b1;
                                end
                         end
                    default: flow_cnt <= 2'd0;
                endcase
            end
    end
endmodule 
module fifo_wr     //写模块
    (
        input           clk,
        input           rst_n,

        input           full,
        input           empty,
        output  reg [7:0] data,
        output  reg     wrreq
    );
    

reg [1:0]   flow_cnt;

always @ (posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            begin
                wrreq <= 1'b0;
                data <= 8'd0;
                flow_cnt <= 2'd0;
            end
        else
            begin
                case(flow_cnt)
                    2'd0:begin
                            if(empty)
                                begin
                                    wrreq <= 1'b1;
                                    flow_cnt <= flow_cnt + 1'b1;
                                end
                            else
                                flow_cnt <= flow_cnt;
                         end
                    2'd1:begin
                            if(full)
                                begin
                                    wrreq <= 1'b0;
                                    flow_cnt <= 2'd0;
                                    data <= 8'd0;
                                end
                            else
                                begin
                                    data <= data + 1'b1;
                                    wrreq <= 1'b1;
                                end
                         end
                    default: flow_cnt <= 2'd0;
                endcase
            end
    end
endmodule 
`timescale  1ns/1ns                // tb程序

module  tb;               // 测试模块

//parameter  define
parameter  T = 20;                 // 时钟周期为20ns

//reg define
reg  sys_clk;                      // 时钟信号
reg  sys_rst_n;                    // 复位信号

//*****************************************************
//**                    main code
//*****************************************************

//给输入信号初始值
initial begin
    sys_clk            = 1'b0;
    sys_rst_n          = 1'b0;     // 复位
    #(T+1)  sys_rst_n  = 1'b1;     // 在第21ns的时候复位信号信号拉高
end

//50Mhz的时钟,周期则为1/50Mhz=20ns,所以每10ns,电平取反一次
always #(T/2) sys_clk = ~sys_clk;

//例化led模块
ip_fifo_a  u0 (
    .sys_clk     (sys_clk  ),
    .sys_rst_n   (sys_rst_n)
);

endmodule

单时钟同步FIFO,带almost_empty和almost_full端口

首先让Quartus根据我们的需要生成FIFO
在这里插入图片描述

在这里插入图片描述
现在来看一下almost_empty和almost_full的含义,almost_empty是usedw小于我们设定的50才会把almost_empty置位;almost_full是usedw大于等于我们设定的200才会把almost_full置位。区别是其中一个能取到等与。usedw指的是FIFO含有的数据量的多少。

1. almost_empty置位时

这里我们来看用ModelSim仿真的结果:
在这里插入图片描述
可以从图中发现当usedw小于50后,立马把almost_empty置位,与上面对almost_empty置位条件吻合。置位一个时钟周期后,wrreq被拉高,rdreq被拉低,这也与程序的定义吻合
在这里插入图片描述
在这里插入图片描述
所以可以看到在almost_empty拉高后,usedw仍然减小了,就是因为rdreq的延时变化造成的;在wrreq拉高后一个时钟周期usedw才增加1,所以数据写入FIFO其实会延后一个时钟周期

2. almost_full置位时

在这里插入图片描述
可以从图中发现当usedw等于200后,立马把almost_full置位,与上面对almost_full置位条件吻合。置位一个时钟周期后,wrreq被拉低,rdreq被拉高,这也与程序的定义吻合。
在这里插入图片描述
在这里插入图片描述
所以可以看到在almost_full拉高后,usedw仍然增加了,就是因为wrreq的延时变化造成的;在rdreq拉高后一个时钟周期usedw才减少1,所以数据读出FIFO其实会延后一个时钟周期

3. 总结

  1. 单时钟同步FIFO在读写时都有一个时钟周期延时,即wrreq置位后不能立马写入数据,一个T后,数据才会成功写进FIFO;当rdreq置位后不能立马读出数据,一个T后,数据才会成功从FIFO中读出,可以发现和RAM的机制类似
  2. usedw和写入、读出数据是同步更新的,即每成功读出或写入一个数据,usedw也同步更新,usedw实时显示了FIFO的数据量。观察两个仿真图可以知道usedw在48-201之间变化,理论上是49-200之间变换,主要是程序设计wrreq和rdreq的延时变化造成的。
  3. almost_empty和almost_full是根据usedw的值来确定的。
  4. 在向FIFO写数据时,他的输出端q会保持最后一次输出的值。
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页