目录
1. 介绍
2. 示例
2.1 代码解析
2.2 串流数据类型
2.3 综合报告
3. 总结
1. 介绍
在Vitis HLS中,hls::stream是一个用于在C/C++中进行高级合成的关键数据结构。它类似于C++标准库中的std::stream,但是专门设计用于硬件描述语言(如Verilog或VHDL)中的数据流。hls::stream提供了一种方便的方法来处理数据流,使得在设计硬件加速器时更加灵活和可控。
hls::stream<> 类实现的串流具有如下属性:
- hls::stream<> 的行为与无限深度的 FIFO 相似。
- 按顺序对其执行读取和写入。即,从 hls::stream<> 读取数据之后,无法再次对其进行读取。
- 顶层接口上的 hls::stream<> 默认情况下使用 ap_fifo 接口来实现或者作为 AXIS 接口来实现。
- 串流可定义为局部或全局,并且始终作为内部 FIFO 来实现。全局作用域内定义的串流遵循的规则与任何其它全局变量相同。
常见有两种串流声明方法:
- hls::stream<Type>:指定串流的数据类型。设计内部的 hls::stream<> 作为 FIFO 来实现,默认深度为 2。STREAM 编译指示或指令可用于更改深度。
- hls::stream<Type, Depth>:指定串流的数据类型和 FIFO 深度。设置深度以防止停滞。如果设计中的任意任务生产或使用样本的速度大于指定深度,那么 FIFO 可能因无法读取(或写入)而变为空(或满),从而导致停滞。
2. 示例
2.1 代码解析
#include "ap_axi_sdata.h"
#include "ap_int.h"
#include "hls_stream.h"
typedef ap_axiu<64, 0, 0, 0> trans_pkt;
struct data {
ap_int<64> data_filed;
ap_int<1> last;
};
void example(hls::stream<trans_pkt> & inStreamTop,
hls::stream<data> & outTop) {
#pragma HLS INTERFACE axis register_mode = both register port = inStreamTop
trans_pkt in_val;
in_val = inStreamTop.read();
data out_val = {in_val.data, in_val.last};
outTop.write(out_val);
}
该示例会生成如下IP:
请注意,虽然顶层函数参数 inStreamTop 和 outTop,同为 hls::stream 类型的数据,但是综合成的 IP 却有很大的差别:
- 指令 #pragma HLS INTERFACE axis 会限定 inStreamTop 以 AXI Stream 接口来实现。
- 默认的 hls::stream 会以 ap_fifo 接口来实现,outTop。
我么可以看下标准的 fifo 接口:
可以看到,outTop 与 FIFO_WRITE 具有一致的接口信号。
在此例中,我们有个数据打包的操作:
data out_val = {in_val.data, in_val.last};
目的是将 AXI Stream 中的 TLAST 也作为数据的一部分,给到 FIFO 接口中。所以我们 outTop 中的 outTop_din[64:0] 有65位。
2.2 串流数据类型
针对 hls::stream 以 AXI Stream 实现的情况,当串流数据类型 (T) 为简单的整数类型时,有 2 种预定义的 AXI4-Stream 实现类型可用:
- AXI4-Stream 类的有符号实现
hls::axis<ap_int<WData>, WUser, WId, WDest>
或者使用简写:
ap_axis<Wdata, WUser, WId, WDest>
- AXI4-Stream 类的无符号实现
hls::axis<ap_uint<WData>, WUser, WId, WDest>
或者使用简写:
ap_axiu<WData, WUser, WId, WDest>
2.3 综合报告
================================================================
== HW Interfaces
================================================================
* AXIS
+-------------+---------------+-------+-------+-------+--------+-------+--------+
| Interface | Register Mode | TDATA | TKEEP | TLAST | TREADY | TSTRB | TVALID |
+-------------+---------------+-------+-------+-------+--------+-------+--------+
| inStreamTop | both | 64 | 8 | 1 | 1 | 8 | 1 |
+-------------+---------------+-------+-------+-------+--------+-------+--------+
* AP_FIFO
+-----------+------------+
| Interface | Data Width |
+-----------+------------+
| outTop | 65 |
+-----------+------------+
* TOP LEVEL CONTROL
+-----------+------------+-----------------------------------+
| Interface | Type | Ports |
+-----------+------------+-----------------------------------+
| ap_clk | clock | ap_clk |
| ap_rst_n | reset | ap_rst_n |
| ap_ctrl | ap_ctrl_hs | ap_done ap_idle ap_ready ap_start |
+-----------+------------+-----------------------------------+
其中 AXIS 和 AP_FIFO 的报告均符合预期。
================================================================
== SW I/O Information
================================================================
* Top Function Arguments
+-------------+-----------+---------------------------------------------+
| Argument | Direction | Datatype |
+-------------+-----------+---------------------------------------------+
| inStreamTop | in | stream<hls::axis<ap_uint<64>, 0, 0, 0>, 0>& |
| outTop | out | stream<data, 0>& |
+-------------+-----------+---------------------------------------------+
软件IO依然提供了丰富的信息。
虽然示例代码中使用了简写“ ap_axiu<64, 0, 0, 0>”,报告仍然还原了全称。
3. 总结
在Vitis HLS中,hls::stream是一个关键的数据结构,用于处理数据流。它类似于C++标准库中的std::stream,但专门设计用于硬件描述语言。hls::stream具有类似无限深度的FIFO的行为,支持顺序读写操作,并可灵活定义数据类型和FIFO深度。通过示例代码和综合报告,我们了解到hls::stream在硬件设计中的重要作用,以及如何根据需求配置不同的接口实现。这使得在设计硬件加速器时更加灵活、可控。