Altera的异步FIFO,读写用同频不同相时钟

相关文章
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

Altera的异步FIFO,读写用同频不同相时钟

程序

module ip_fifo    //顶层模块
    (
        input   sys_clk,
        input   sys_rst_n
    );
    
wire            wrreq;
wire    [7:0]   data;
wire            wrempty;
wire            wrfull;
wire    [7:0]   wrusedw;

wire            rdreq;
wire    [7:0]   q;
wire            rdempty;
wire            rdfull;
wire    [7:0]   rdusedw;

wire    rst_n;
wire    locked;

assign  rst_n = sys_rst_n & locked;

pll_clk u_pll_clk
    (
        .areset     (~sys_rst_n),
        .inclk0     (sys_clk),
        .c0         (clk_50m_wr),
        .c1         (clk_50m_180deg_rd),
        .locked     (locked)
    );

//例化FIFO模块
fifo u_fifo(
    .wrclk   ( clk_50m_wr ),         // 写时钟
    .wrreq   ( wrreq   ),         // 写请求
    .data    ( data    ),         // 写入FIFO的数据
    .wrempty ( wrempty ),         // 写空信号
    .wrfull  ( wrfull  ),         // 写满信号
    .wrusedw ( wrusedw ),         // 写侧数据量
    
    .rdclk   ( clk_50m_180deg_rd ),         // 读时钟
    .rdreq   ( rdreq   ),         // 读请求
    .q       ( q       ),         // 从FIFO输出的数据
    .rdempty ( rdempty ),         // 读空信号
    .rdfull  ( rdfull  ),         // 读满信号
    .rdusedw ( rdusedw )          // 读侧数据量
);

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

    .wrreq   (wrreq   ),          // 写请求
    .data    (data    ),          // 写入FIFO的数据
    .wrempty (wrempty ),          // 写空信号
    .wrfull  (wrfull  )           // 写满信号
);

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

    .rdreq   (rdreq   ),          // 读请求
    .data    (q       ),          // 从FIFO输出的数据
    .rdempty (rdempty ),          // 读空信号
    .rdfull  (rdfull  )           // 读满信号

);

endmodule 
module fifo_rd  //读fifo模块
    (
        input           clk,
        input           rst_n,
        input   [7:0]   data,
        input           rdfull,
        input           rdempty,
        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(rdfull)
                                begin
                                    rdreq <= 1'b1;
                                    flow_cnt <= flow_cnt + 1'b1;
                                end
                            else
                                flow_cnt <= flow_cnt;
                         end
                    2'd1:begin
                            if(rdempty)
                                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    //写fifo模块
    (
        input           clk,
        input           rst_n,

        input           wrfull,
        input           wrempty,
        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'd11;
                flow_cnt <= 2'd0;
            end
        else
            begin
                case(flow_cnt)
                    2'd0:begin
                            if(wrempty)
                                begin
                                    wrreq <= 1'b1;
                                    flow_cnt <= flow_cnt + 1'b1;
                                end
                            else
                                flow_cnt <= flow_cnt;
                         end
                    2'd1:begin
                            if(wrfull)
                                begin
                                    wrreq <= 1'b0;
                                    flow_cnt <= 2'd0;
                                    data <= 8'd22;
                                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;                    // 复位信号

//wire define


//*****************************************************
//**                    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  u0 (
    .sys_clk     (sys_clk  ),
    .sys_rst_n   (sys_rst_n)
);

endmodule

1. FIFO为空,开始写入时

在这里插入图片描述

  1. 可以看到在wrreq持续一个T后,wrempty信号拉低,证明此时有数据写进了FIFO(和同步FIFO一样,写入会延时一个T完成),但是此时的wrusedw仍然为0,按理此时已经成功写入,该值应该为1,所以wrusedw的更新延后了实际FIFO的数据量一个写周期。
  2. 在FIFO已经写入了几个数据之后,rdempty才拉低,证明此时才能读出,所以数据在刚写入FIFO后,不能立马读出。
  3. 当rdempty拉低的时刻,按同步FIFO的理解,应该读端有一个数据,但rdusedw还是为0,一个读周期后才为1,所以和写端的wrusedw一样,读端的rdusedw也比实际的FIFO数据量晚一个读周期更新。

2. FIFO为满,开始读出时

在这里插入图片描述

  1. 当wrusedw为255时,wrfull信号就拉高,其实此时FIFO的数据量实际上是满的,因为上面有讲到wrusedw延后了实际写FIFO数据量一个写周期
  2. 由于程序设计的原因,wrreq延后wrfull一个写周期,所以在写满后,仍然写了一个数据,但这个数据其实没有写入FIFO中。所以在以后程序设计中,当检查到wrfull拉高以后立马要停止其他模块向FIFO传数据,不立马停止会导致个别数据丢失
  3. 上面有讲到在写入数据,一段时间后才会在读端更新,所以rdusedw是晚于wrusedw到达最大值。
  4. 当rdusedw为255时,rdfull信号就拉高,其实此时FIFO的数据量实际上是满的,因为上面有讲到rdusedw延后了实际读FIFO数据量一个读周期

3.总结

  1. 在用异步FIFO时,假如要用他的empty和full信号。那么在向FIFO写数据时,用wrempty和wrfull信号控制。当wrempty信号拉高时,此刻FIFO的写端正好没有数据量;当wrfull信号拉高时,此刻FIFO的写端正好写满了。如果用xxempty和xxfull信号信号控制读写FIFO,那么在xxempty和xxfull发生变化后就要立即停止其他模块与FIFO的数据互动,不然有些数据会没能写进FIFO或者读出无效FIFO数据!!!
  2. 在用异步FIFO时,假如要用他的empty和full信号。那么在从FIFO读数据时,用rdempty和rdfull信号控制。当rdfull信号拉高时,此刻FIFO的读端正好是满的;当rdempty信号拉高时,此刻FIFO的读端正好读空了。
  3. 无论是wrusedw还是rdusedw他们都不能表示写端和读端的数据量,他们与真实数据量之间,都有相应时钟域的一个时钟周期的延迟。即此刻wrusedw的值实际上是上一个写时钟周期时写端FIFO的数据量,rdusedw同理。
  4. 最可靠的使用异步FIFO还是通过他的xxusedw来控制他,当读时用wrusedw,当写时用rdusedw。虽然xxusedw不能表示真实的数据量,但是与真实数据量相差也很小,只要留出一定的阈值就不会出现数据没写进去或者读出无效数据的情况
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值