块串流建模风格 - 2021.2 Chinese

Vitis 高层次综合用户指南 (UG1399)

Document ID
UG1399
Release Date
2021-12-15
Version
2021.2 Chinese

从另一方面来看,对于块串流,生产者与使用者之间的通信以类阵列对象串流方式来建模,这样与通过 PIPO 进行阵列传输相比存在多方面优势。

在代码中使用块串流需要以下 include 文件:
#include "hls_streamofblocks.h"

块串流对象模板为:hls::stream_of_blocks<block_type, depth> v

其中:
  • <block_type> 用于指定块串流所包含的阵列或多位阵列的数据类型
  • <depth> 是可选实参,可提供与 hls::stream 或 PIPO 相似的深度控制,并指定块的总数,包括在任意时间生产者获取的块和使用者获取的块。默认值为 2
  • v 为块串流对象指定变量名称
使用以下步骤访问块串流中的某一个块:
  1. 如果生产者或使用者进程要首先访问串流,则需要使用 hls::write_lockhls::read_lock 对象获取对该串流的访问权。
  2. 当生产者获取锁定后,它即可开始写入(或读取)获取的块。此块完全初始化后,当 write_lock 对象超出范围时,生产者即可将此块释放。
    注释: 具有 write_lock 的生产者进程也可以读取此块,前提是它从已写入的位置读取,因为新获取的块必须假定包含未初始化的数据。仅限生产者进程才能对块进行写入和读取,不支持使用者执行此操作。
  3. 随后,此块将在块串流中以 FIFO 方式排队,当使用者获取 read_lock 对象后,此块即可供使用者进程读取。

前述示例中所示的 hls::stream_of_blocks 与 PIPO 机制之间的主要差异在于一旦 write_lock 超出范围,块就会变为对使用者可用,而不是仅在生产者进程返回时才可用。因此,通过块串流方式管理前述示例所需的存储器大小比 PIPO 小得多:在该示例中,为 2N 而不是 2xMxN。

以下示例显示了如何重写前述示例以使用 hls::stream_of_blocks。生产者通过构造名为 bhls::write_lock 对象,并将名为 s 的块串流对象引用传递给该对象,即可获取此块。write_lock 对象可提供重载阵列访问运算符,这样即可像阵列一样访问此对象,以便按随机顺序访问底层存储器,如以下示例所示。

提示: 通过构造 write_lock/read_lock 对象即可执行锁定的获取,当对象超出范围时,就会被销毁,从而自动释放锁定。此方法使用常用的资源获取即初始化 (RAII) 风格的锁定和解锁。
#include "hls_streamofblocks.h"
typedef int buf[N];
void producer (hls::stream_of_blocks<buf> &s, ...) {
  for (int i = 0; i < M; i++) {
    // Allocation of hls::write_lock acquires the block for the producer
    hls::write_lock<buf> b(s);
    for (int j = 0; j < N; j++)
      b[f(j)] = ...;
    // Deallocation of hls::write_lock releases the block for the consumer
  }
}
 
void consumer(hls::stream_of_blocks<buf> &s, ...) {
  for (int i = 0; i < M; i++) {
    // Allocation of hls::read_lock acquires the block for the consumer
    hls::read_lock<buf> b(s);
    for (int j = 0; j < N; j++)
       ... = b[g(j)] ...;
    // Deallocation of hls::write_lock releases the block to be reused by the producer
  }
}
 
void top(...) {
#pragma HLS dataflow
  hls::stream_of_blocks<buf> s;
 
  producer(b, ...);
  consumer(b, ...);
}

此方法的关键特征包括:

  • 以上生产者的外层循环的目标性能是达成总体启动时间间隔 (II) 为 1 的目标
  • 锁定的块虽可使用,但它仅供生产者或使用者进程专用,直至被释放为止。
  • 生产者的阵列对象的初始状态并未定义,但它包含由生产者为使用者写入的值。
  • 块串流的主要优势在于允许重叠执行使用者和生产者的多次迭代,以提升吞吐量。