前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何理解HLS中的Stream

如何理解HLS中的Stream

作者头像
Lauren的FPGA
发布2019-10-30 18:55:39
4.3K0
发布2019-10-30 18:55:39
举报
文章被收录于专栏:Lauren的FPGALauren的FPGA

思考一下:

大位宽的数据延迟或数据缓存,采用LUT实现时会有哪些弊端?

数据缓存采用LUT时,实际上用的是SLICEM里的LUT。如果使用量大,就会出现这些LUT分布在不同列,同时,也增加了CLB的端口密度(Pin Density),这样容易导致局部布线拥塞,不利于时序收敛。

什么是流数据(Streaming Data)

流数据是指数据的采样是按顺序进行的,因此不需要地址层面的操作(不需要读地址,也不需要写地址)。

关于HLS Stream Library

HLS提供了C++类模板hls::stream<>用于流数据的算法建模。需要说明的是hls::stream<>是类模板,故只可用于C++设计中。基于hls::stream<>的流数据具有如下属性:

  • hls::stream<>的行为类似于一个深度无限大FIFO,因此,并不需要定义hls::stream<>的规模
  • 从流中读取数据或向流中写入数据都是顺序进行的,这意味着数据只能从流中读取一次,不能反复读取,这与第一个特征相吻合
  • 如果一个hls::stream<>的流为顶层函数接口,最终该接口会被综合为ap_fifo接口类型
  • 如果一个hls::stream<>的流用于内部函数之间的数据传递,那么该接口最终被综合为一个深度为1的FIFO。HLS提供了directive “STREAM“,可用于修改该FIFO的深度

创建流数据

从代码风格的角度而言,一般在头文件(.h)中创建数据类型。如图1所示,创建流数据类型与其他数据类型类似,其中第2行代码是必须要有的。如果声明了namespace(第3行代码),那么可直接创建流(对应第6行和第7行代码)。如果未声明namespace,则需要指明namespace为hls,如第8行和第9行所示。

图1 在头文件中创建流数据类型
图1 在头文件中创建流数据类型

在源文件(.cpp)中也可创建流数据类型,如下图所示。同样地,第11行代码是必须要有的。此外,可以给流数据命名,如第14行代码,命名的好处在于报告以及日志文件中会以该名字显示流数据,如图3所示。

图2 在源文件中创建流数据类型
图2 在源文件中创建流数据类型
图3 log文件中显示的流数据信息
图3 log文件中显示的流数据信息

由此可得如下结论:

采用hls_stream::<T>创建流数据,这里T可以是C++自身的数据类型,如int,float或结构体;也可以是HLS新增的任意精度数据类型,如ap_int<5>或ap_fixed<10,8>等。流数据必须以引用(Reference)的形式出现在函数形参列表中,如图4所示。其中,din_stream和dout_stream分别为图1代码第6行和第7行定义的流数据类型。

图4 在形参列表中声明流数据
图4 在形参列表中声明流数据

流数据的阻塞式读(Blocking Write and Read)

如前所示,无论流数据是位于顶层函数还是内部函数,最终都会综合为FIFO接口或者FIFO实体。对于FIFO,我们有一个基本的认知:一旦FIFO读空,就无法继续执行读操作;一旦FIFO写满,就无法继续执行写操作。在这两种情形下,如果继续执行相应的操作就会出现错误,为此,一旦出现上述情形,就阻塞,终止相应操作,这就是阻塞的缘由。

  • 阻塞式读

从流上获取数据需要读操作。HLS提供了三种读操作方式,如图5所示。其中第三种方法使用了“>>“,C++中的输入操作符,也是右移运算符。只有从流上获取了数据之后,才可以对该数据进行进一步的处理。

图5 三种阻塞式读方法
图5 三种阻塞式读方法
  • 阻塞式写

将数据写入流需要写操作。HLS提供了两种写操作方式。其中第二种方法利用了”<<”,这其实就是C++中的输出操作符,也是左移运算符。数据处理完毕之后,可通过写操作进入流。

图6 两种阻塞式写方法
图6 两种阻塞式写方法

流数据的非阻塞式读写

(Non-BlockingWrite and Read)

采用非阻塞式读写就意味着即使读空或写满也不会终止相应操作,但并不表示读空之后读到的数据或写满之后写入的数据依然有效。

  • 非阻塞式读

非阻塞式读需要用到read_nb(nb就是Non-Blocking的简写)。不同于阻塞式的读,read_nb有返回值,返回值类型为bool。当从流上成功读取到数据时,返回值为true,否则为false。具体用法如图7所示。

图7 非阻塞式读方法
图7 非阻塞式读方法

此外,HLS还提供了针对了是否为空的检测函数empty,其返回值为bool。当流为空时,返回为true,否则返回为false。具体用法如图8所示。

图8 检测流是否为空
图8 检测流是否为空
  • 非阻塞式写

采用非阻塞式方式将数据写入流需用用到write_nb。不同于阻塞式写write,write_nb具有返回值,返回值类型为bool。一旦数据成功写入流,则返回true,否则返回false。具体用法如图9所示。

图9 非阻塞式写方法
图9 非阻塞式写方法

此外,HLS还提供了用于检测流是否写满的方法full。若已写满,则返回ture,否则返回false。

图10 检测流是否为满
图10 检测流是否为满

思考一下:

对于如图11所示的顶层函数,HLS会将其接口综合成何种形式?

图11 形参为stream的顶层函数
图11 形参为stream的顶层函数
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Lauren的FPGA 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是流数据(Streaming Data)
  • 关于HLS Stream Library
  • 创建流数据
  • 流数据的阻塞式读(Blocking Write and Read)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档