Vitis HLS 学习笔记--优化指令-BIND_OP_STORAGE

2024-04-23 05:12

本文主要是介绍Vitis HLS 学习笔记--优化指令-BIND_OP_STORAGE,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1. BIND_OP_STORAGE 概述

1.1 BIND_OP

1.2 BIND_STORAGE

2. 语法解析

2.1 BIND_OP

2.2 BIND_OP 用法示例

2.3 BIND_STORAGE

2.4 BIND_STORAGE 示例

3. 实例演示

4. 总结


1. BIND_OP_STORAGE 概述

BIND_OP_STORAGE 其实是两个优化指令的合称:BIND_OP 和 BIND_STORAGE。

1.1 BIND_OP

Vitis HLS 使用特定 impl 来实现代码中的运算。BIND_OP 编译指示用于指定针对每个特定变量,都应将一项运算(mul、add、div)映射到特定器件资源,以便在 RTL 内实现 (impl)。如果不指定 BIND_OP 编译指示,Vitis HLS 会自动判定用于运算的资源。

1.2 BIND_STORAGE

BIND_STORAGE 编译指示用于将代码中的变量(阵列或函数实参)分配给 RTL 中的特定存储器类型 (type)。如果不指定此编译指示,那么 Vitis HLS 工具会判定要分配的存储器类型。HLS 工具在硬件中使用指定的实现 (impl) 来实现该存储器。

2. 语法解析

2.1 BIND_OP

#pragma HLS bind_op variable=<variable> op=<type> impl=<value> latency=<int>
  • variable=<variable>:用于定义要将 BIND_OP 编译指示分配到的变量
  • op=<type>:用于定义要绑定到特定实现资源的运算。受支持的函数运算包括:mul、add 和 sub 受支持的浮点运算包括:fadd、fsub、fdiv、fexp、flog、fmul、frsqrt、frecip、fsqrt、dadd、dsub、ddiv、dexp、dlog、dmul、drsqrt、drecip、dsqrt、hadd、hsub、hdiv、hmul 和 hsqrt。
  • impl=<value>:定义用于指定运算的实现。受支持的函数运算实现包括 fabric 和 dsp。受支持的浮点运算实现包括:fabric、meddsp、fulldsp、maxdsp 和 primitivedsp。
  • latency=<int>:定义运算的实现的默认时延。有效的时延值因指定的 op 和 impl 而异。默认值为 -1,即交由 Vitis HLS 选择时延。

支持的整数运算操作:

OP

Impl

Min Latency

Max Latency

add

fabric

0

4

add

dsp

0

4

mul

fabric

0

4

mul

dsp

0

4

sub

fabric

0

4

sub

dsp

0

0

 支持的浮点数运算操作:

操作

实现

Min Latency

Max Latency

fadd

fabric

0

13

fadd

fulldsp

0

12

fadd

primitivedsp

0

3

fexp

meddsp

0

21

fmul

maxdsp

0

7

快速记忆方法:

受支持的函数运算包括:
mul、add 、 sub受支持的浮点运算包括:
fadd fsub fdiv fexp flog fmul frsqrt frecip fsqrt
dadd dsub ddiv dexp dlog dmul drsqrt drecip dsqrt
hadd hsub hdiv           hmul               hsqrt

Impl解释:

  • fabric: 使用 FPGA 的逻辑单元和 RAM 块来实现算法。
  • dsp: 使用 FPGA DSP 功能来实现算法,例如 FFTFIRDDS 等。
  • meddsp: 使用 FPGA DSP 功能和一些逻辑单元来实现算法,适合中等复杂度的算法。
  • maxdsp: 使用 FPGA DSP 功能和更多的逻辑单元来实现算法,适合高复杂度的算法。
  • fulldsp: 使用 FPGA 的所有可用资源来实现算法,包括 DSPRAM 和逻辑单元。

2.2 BIND_OP 用法示例

double mult (double a, double b) {double c, d;
#pragma HLS BIND_OP variable=c op=dmul impl=fabric  latency=2
#pragma HLS BIND_OP variable=d op=dmul impl=fulldsp latency=10c = a * b;d = a * c;return d;
}

解释: 

  • 指定变量 的双精度浮点运算,实现方式fabric,延时为2
  • 指定变量 的双精度浮点运算,实现方式为fulldsp,延时为10

Vitis HLS 编译器得到的结果如下:

从命名可以看出:

  • dmul: 双精度乘法器。
  • 64ns: 输入数据的位宽是 64 位,ns的含义不明
  • 64: 输出数据的位宽是 64 位,3和5的含义不明。
  • max_dsp: 实现方法是使用最大数量的 DSP 功能。
  • U2: 模块的实例名字。

注意:

  • 编译器对待手动指定latency,会优先满足时钟频率上的要求,然后尽量靠近用户指定的latency
  • 如上述案例,虽然指定了latency=2,但是编译器需要latency等于3才能满足时钟频率要求。
  • 给定更多latency,系统能运行在更高的时钟频率上。

2.3 BIND_STORAGE

#pragma HLS bind_storage variable=<variable> type=<type> [ impl=<value> latency=<int> ]
  • variable=<variable>:定义要将 BIND_STORAGE 编译指示分配到的变量。
  • type=<type>:定义要绑定到指定变量的存储器的类型。受支持的类型包括:fifo、ram_1p、ram_1wnr、ram_2p、ram_s2p、ram_t2p、rom_1p、rom_2p、rom_np。
  • impl=<value>:定义指定存储器类型的实现。受支持的实现包括:bram、bram_ecc、lutram、uram、uram_ecc、srl、memory 和 auto,如下所述。
  • latency=<int>:定义用于绑定类型的默认时延。如下表所示,有效的时延值因指定的 type 和 impl 而异。默认值为 -1,即交由 Vitis HLS 选择时延。

存储类型:

类型

描述

FIFO

FIFOVitis HLS 可判定如何在 RTL 中将其实现,除非指定 -impl 选项。

RAM_1WNR

1 个写入端口和 N 个读取端口的 RAM,内部使用 N bank

RAM_2P

双端口 RAM,允许在某一端口上执行操作,并在另一个端口上执行读写操作。

RAM_S2P

双端口 RAM,允许在某一端口上执行操作,并在另一个端口上执行操作。

RAM_T2P

真正的双端口 RAM,支持在 2 个端口上执行读写操作。

ROM_1P

单端口 ROMVitis HLS 可判定如何在 RTL 中将其实现,除非指定 -impl 选项。

ROM_2P

双端口 ROM

ROM_NP

多端口 ROM

实现类型:

名称

描述

MEMORY

通用存储器,允许 Vivado 工具选择实现。

URAM

UltraRAM 资源

URAM_ECC

ECC UltraRAM

SRL

移位寄存器逻辑资源,Shift Register Look-up Table(移位寄存器查找表)

LUTRAM

分布式 RAM 资源

BRAM

RAM 资源

BRAM_ECC

ECC 的块 RAM

AUTO

Vitis HLS 会自动判定变量的实现。

受支持的存储器类型、实现和时延组合:

操作

实现

Min Latency

Max Latency

FIFO

BRAM

0

0

FIFO

LUTRAM

0

0

FIFO

MEMORY

0

0

FIFO

SRL

0

0

FIFO

URAM

0

0

RAM_1P

AUTO

1

3

RAM_1P

BRAM

1

3

RAM_1P

LUTRAM

1

3

RAM_1P

URAM

1

3

RAM_1WNR

AUTO

1

3

RAM_1WNR

BRAM

1

3

RAM_1WNR

LUTRAM

1

3

RAM_1WNR

URAM

1

3

RAM_2P

AUTO

1

3

RAM_2P

BRAM

1

3

RAM_2P

LUTRAM

1

3

RAM_2P

URAM

1

3

操作

实现

Min Latency

Max Latency

RAM_S2P

BRAM

1

3

RAM_S2P

BRAM_ECC

1

3

RAM_S2P

LUTRAM

1

3

RAM_S2P

URAM

1

3

RAM_S2P

URAM_ECC

1

3

RAM_T2P

BRAM

1

3

RAM_T2P

URAM

1

3

ROM_1P

AUTO

1

3

ROM_1P

BRAM

1

3

ROM_1P

LUTRAM

1

3

ROM_2P

AUTO

1

3

ROM_2P

BRAM

1

3

ROM_2P

LUTRAM

1

3

ROM_NP

BRAM

1

3

ROM_NP

LUTRAM

1

3

2.4 BIND_STORAGE 示例

#pragma HLS bind_storage variable=coeffs type=RAM_1P impl=bram

解释:

指令告诉HLS工具将 coeffs 数组绑定到一个单端口RAM上,并且使用块RAM作为其实现方式。

3. 实例演示

#define BUFFER_SIZE 1024
#define DATA_SIZE 4096// TRIPCOUNT identifier
const unsigned int c_len = DATA_SIZE / BUFFER_SIZE;
const unsigned int c_size = BUFFER_SIZE;extern "C" {
void vadd(const unsigned int* in1, // Read-Only Vector 1const unsigned int* in2, // Read-Only Vector 2unsigned int* out_r,     // Output Resultint size                 // Size in integer) {unsigned int v1_buffer[BUFFER_SIZE];   // Local memory to store vector1unsigned int v2_buffer[BUFFER_SIZE];   // Local memory to store vector2unsigned int vout_buffer[BUFFER_SIZE]; // Local Memory to store result// Using the BIND_OP pragma the user can specify the operator, implementation
// and latency
#pragma HLS BIND_OP variable = v1_buffer op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = v2_buffer op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = vout_buffer op = add impl = DSP
// Using the BIND STORAGE the used can choose the type, resource and latency
#pragma HLS BIND_STORAGE variable = v1_buffer type = RAM_1P impl = BRAM latency = 2
#pragma HLS BIND_STORAGE variable = v2_buffer type = RAM_1P impl = LUTRAM latency = 2
#pragma HLS BIND_STORAGE variable = vout_buffer type = RAM_1P impl = URAM// Per iteration of this loop perform BUFFER_SIZE vector additionfor (int i = 0; i < size; i += BUFFER_SIZE) {
#pragma HLS LOOP_TRIPCOUNT min = c_len max = c_lenint chunk_size = BUFFER_SIZE;// boundary checksif ((i + BUFFER_SIZE) > size) chunk_size = size - i;// Auto-pipeline is going to apply pipeline to these loopsread1:for (int j = 0; j < chunk_size; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_sizev1_buffer[j] = in1[i + j] * in1[i + j];}read2:for (int j = 0; j < chunk_size; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_sizev2_buffer[j] = in2[i + j] * in2[i + j];}vadd:for (int j = 0; j < chunk_size; j++) {
// As the outer loop is not a perfect loop
#pragma HLS loop_flatten off
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_size// perform vector additionvout_buffer[j] = v1_buffer[j] + v2_buffer[j];}// burst write the resultwrite:for (int j = 0; j < chunk_size; j++) {
#pragma HLS LOOP_TRIPCOUNT min = c_size max = c_sizeout_r[i + j] = vout_buffer[j];}}
}
}

其中关键的优化指令如下:

// Using the BIND_OP pragma the user can specify the operator, implementation and latency
#pragma HLS BIND_OP variable = v1_buffer    op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = v2_buffer    op = mul impl = DSP latency = 2
#pragma HLS BIND_OP variable = vout_buffer op = add impl = DSP


// Using the BIND STORAGE the used can choose the type, resource and latency
#pragma HLS BIND_STORAGE variable = v1_buffer    type = RAM_1P impl = BRAM     latency = 2
#pragma HLS BIND_STORAGE variable = v2_buffer    type = RAM_1P impl = LUTRAM latency = 2
#pragma HLS BIND_STORAGE variable = vout_buffer type = RAM_1P impl = URAM

运行 Vitis HLS 编译器,我们得到如下结果:

================================================================
== Pragma Report
================================================================
* Valid Pragma Syntax
+----------------+----------------------------------------------------------------+-------------------------+
| Type           | Options                                                        | Location                |
+----------------+----------------------------------------------------------------+-------------------------+
| bind_op        | variable = v1_buffer     op = mul    impl = DSP    latency = 2 | src/vadd.cpp:20 in vadd |
| bind_op        | variable = v2_buffer     op = mul    impl = DSP    latency = 2 | src/vadd.cpp:21 in vadd |
| bind_op        | variable = vout_buffer   op = add    impl = DSP                | src/vadd.cpp:22 in vadd |
| bind_storage   | variable = v1_buffer   type = RAM_1P impl = BRAM   latency = 2 | src/vadd.cpp:24 in vadd |
| bind_storage   | variable = v2_buffer   type = RAM_1P impl = LUTRAM latency = 2 | src/vadd.cpp:25 in vadd |
| bind_storage   | variable = vout_buffer type = RAM_1P impl = URAM               | src/vadd.cpp:26 in vadd |
+----------------+----------------------------------------------------------------+-------------------------+

请注意区分,一个变量可以同时使用这两种绑定,例如 v1_buffer 既被指定了op,又被指定了storage,op 绑定和 storage 绑定关注不同的方面。op 绑定关心的是如何执行计算,而storage 绑定关心的是如何存储数据。

4. 总结

这些指令指导了高级综合(HLS)工具在优化指定数组的存储和操作实现时的行为。它们有助于在 FPGA 设计中实现更好的性能和资源利用率。存储类型的选择(BRAM、LUTRAM 或 URAM)以及专用 DSP 资源的使用会影响设计的整体效率。指定的延迟控制了这些操作的时序特性。

这篇关于Vitis HLS 学习笔记--优化指令-BIND_OP_STORAGE的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/927873

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份