碎碎思 · 2022年09月20日 · 北京市

乒乓操作实例讲解-FIFO

介绍

无论何时,在复杂的 FPGA 设计过程中,都不可避免地需要在模块之间发送数据,实现这一点的常用的是 FIFO。

FIFO

写入:当写入 FIFO 时,需要确保不要写入太多数据以致 FIFO 溢出。为了帮助解决这个问题,FIFO 通常有一个完整的计数标志,有时还可以使用一个watermark端口。

watermark:本质上告诉 FIFO 中的项目何时超过一定数量,这时候应该放慢速度或不放入数据。但如果想发送特定数量的数据,将需要添加额外的步骤在状态机中管理“above watermark”的情况。在状态机上工作时,可能需要添加状态和寄存器来管理边缘情况(空满情况)。

full flag:比较棘手的信号,因为 full flag 可能会在输入数据的同一时钟变高。如果有流水线设计,则需要在检测到“full”状态时缓冲这些数据。

count:计数可以大致了解可以进入 FIFO 的数据量。计数的更新比watermark和full flag慢,并且会给你一个保守的 FIFO 内的空间计数。我很想经常使用它,但我发现我需要在状态机中添加一些状态来管理它。

Reading:从 FIFO 读取通常不会那么糟糕,只要在空标志不置位时不读取即可。

Double Buffer

我师傅让我考虑使用双端口block-ram 作为双缓冲器。就像 FIFO 一样,类似具有如下行为的读取器和写入器:

  • 写入器:将数据写入block-ram,然后使用跨时钟域技术将数据的大小和状态发送给读取器。
  • 读取器:读取写入器放入 RAM 的已知数据量。

这种方法的好处在于,写入器知道它可以写入多少空间,而读取器知道它可以读取多少数据。这非常适合流水线设计。另一个方面是写入器可以在读取器读取数据时开始处理block-ram 的后半部分。不过,这种方法并不是自由操作。以下是现在需要由写入器和读取器管理的一些事情:

写入器

  • ram中有多少空间(或ram的一半)
  • 开始/结束地址指针
  • 写入了多少数据

读取器

  • 有多少数据可供读取
  • 开始/结束地址指针

我喜欢这种双缓冲区给我的数据量的预知。这允许我编写内核,将已知数量的数据从双缓冲区的输出转储到另一个位置,如音频或视频缓冲区。不幸的是,每个使用双缓冲器的模块都必须设计为能够处理上述所有问题以及更多的跨时钟域标志。

如果不需要担心 FIFO(满/空)的边缘情况,这将是最容易使用的机制。下面将这两种机制结合起来可能是最佳方案。

Ping Pong FIFO

Ping Pong FIFO 本质上是一个上面描述的双缓冲区,包裹起来看起来像一个 FIFO。所有地址指针和跨时钟域通信都包含在一个简单的模块中。模块如下所示:

module PPFIFO
#(parameter     DATA_WIDTH    = 8,
                ADDRESS_WIDTH = 4
)(

  //universal input
  input                             reset,

  //write side
  input                             write_clock,
  output reg  [1:0]                 write_ready,
  input       [1:0]                 write_activate,
  output      [23:0]                write_fifo_size,
  input                             write_strobe,
  input       [DATA_WIDTH - 1: 0]   write_data,
  output                            starved,

  //read side
  input                             read_clock,
  input                             read_strobe,
  output reg                        read_ready,
  input                             read_activate,
  output reg  [23:0]                read_count,
  output      [DATA_WIDTH - 1: 0]   read_data,

  output                            inactive
);

有单独的写入端和读取端时钟,选通用于写入和读取数据。不过也有一些新的信号:

  • write_ready:这与双缓冲区有关,需要管理缓冲区的两侧。这2 bit信号告诉双缓冲区的哪一侧已准备好。

0:缓冲区的下半部分准备好

1:上半部分准备好

  • write_activate:用户告诉 Ping Pong FIFO 它想要拥有缓冲区的一侧
  • write_fifo_size:表示用户可以写入 Ping Pong FIFO(PPFIFO) 的字数。

注意:不需要在完成之前填充写入端,PPFIFO 将跟踪写入的元素数量并将此信息发送到读取端,作为将递增数字模式写入 PPFIFO 的简单模块示例

/* Module: ppfifo_source
 *
 * Description: Populate a Ping Pong FIFO with an incrementing number pattern
 */

module ppfifo_source #(
  parameter                       DATA_WIDTH    = 8
)(
  input                           clk,
  input                           rst,
  input                           i_enable,

  //Ping Pong FIFO Interface
  input       [1:0]               i_wr_rdy,
  output  reg [1:0]               o_wr_act,
  input       [23:0]              i_wr_size,
  output  reg                     o_wr_stb,
  output  reg [DATA_WIDTH - 1:0]  o_wr_data
);

//Local Parameters
//Registers/Wires
reg   [23:0]          r_count;
//Submodules
//Asynchronous Logic
//Synchronous Logic
always @ (posedge clk) begin
  //De-assert Strobes
  o_wr_stb          <= 0;

  if (rst) begin
    o_wr_act        <=  0;
    o_wr_stb        <=  0;
    o_wr_data       <=  0;
    r_count         <=  0;
  end
  else begin
    if (i_enable) begin
      if ((i_wr_rdy > 0) && (o_wr_act == 0))begin
        r_count     <=  0;
        if (i_wr_rdy[0]) begin
          //Channel 0 is open
          o_wr_act[0]  <=  1;
        end
        else begin
          //Channel 1 is open
          o_wr_act[1]  <=  1;
        end
      end
      else if (o_wr_act > 0) begin
        if (r_count < i_wr_size) begin
          //More room left in the buffer
          r_count   <=  r_count + 1;
          o_wr_stb  <=  1;
          //put the count in the data
          o_wr_data <=  r_count;
        end
        else begin
          //Filled up the buffer, release it
          o_wr_act  <=  0;
        end
      end
    end
  end
end

endmodule

正如所看到的,通过添加一个额外的寄存器来跟踪添加到 PPFIFO 的数据量,不必担心full flags、water marks 或者counts。

阅读方面更容易。PPFIFO 知道首先写入哪个缓冲区,因此用户只需要观察一个read_ready标志,然后使用read_activate告诉它我们有控制权。以下是从 PPFIFO 读取数据的示例:

这里有更具体的细节:

  • 用户监视“read_ready”位:当“read_ready”信号为 1 时,ppfifo 为用户准备好一个数据块。
  • 用户使用“read_activate”信号激活该块并使用“read_strobe”读取 NEXT 数据
  • “read_count”是缓冲区中数据元素的总数。
  • 用户必须在将“read_activate”设置为低之前读取所有数据
/* Module: ppfifo_sink
 *
 * Description: Whenever data is available within the FIFO activate it and read it all
 */

module ppfifo_sink #(
  parameter                       DATA_WIDTH    = 8
)(
  input                           clk,
  input                           rst,

  //Ping Pong FIFO Interface
  input                           i_rd_rdy,
  output  reg                     o_rd_act,
  input       [23:0]              i_rd_size,
  output  reg                     o_rd_stb,
  input       [DATA_WIDTH - 1:0]  i_rd_data
);

//Local Parameters
//Registers/Wires
reg   [23:0]          r_count;
//Submodules
//Asynchronous Logic
//Synchronous Logic
always @ (posedge clk) begin
  //De-Assert Strobes
  o_rd_stb            <=  0;

  if (rst) begin
    o_rd_act          <=  0;
    r_count           <=  0;
    o_rd_stb          <=  0;
  end
  else begin
    if (i_rd_rdy && !o_rd_act) begin
      r_count         <=  0;
      o_rd_act        <=  1;
    end
    else if (o_rd_act) begin
      if (r_count < i_rd_size) begin
        o_rd_stb      <=  1;
        r_count       <=  r_count + 1;
      end
      else begin
        o_rd_act      <=  0;
      end
    end
  end
end
endmodule

下面设计一个简单的测试模块来演示 Ping Pong FIFO。

源代码地址:

https://github.com/CospanDesign/verilog_ppfifo_demo

下面是几个简单模拟的截图:

image.png

在读事务开始和下一个写事务开始时放大仿真区域:

image.png

在读取事务之间放大

image.png

半放大

image.png

截图可能不清晰,建议自己仿真。

总结

PPFIFO除了上面用于解决FIFO的“痛处”外,常见的还是处理高速数据流处理,下面是一个10M数据流分成两个5M数据流的例子。

代码可以参考:

https://github.com/DOOKNET/Pingpang_RAM

image.png

图片来源:CSDN @我的天不可能

原文:OpenFPGA
作者:碎碎思

相关文章推荐

更多FPGA技术干货请关注FPGA 的逻辑技术专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
10614
内容数
577
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息