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

相关文章

51单片机学习记录———定时器

文章目录 前言一、定时器介绍二、STC89C52定时器资源三、定时器框图四、定时器模式五、定时器相关寄存器六、定时器练习 前言 一个学习嵌入式的小白~ 有问题评论区或私信指出~ 提示:以下是本篇文章正文内容,下面案例可供参考 一、定时器介绍 定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。 定时器作用: 1.用于计数系统,可

问题:第一次世界大战的起止时间是 #其他#学习方法#微信

问题:第一次世界大战的起止时间是 A.1913 ~1918 年 B.1913 ~1918 年 C.1914 ~1918 年 D.1914 ~1919 年 参考答案如图所示

[word] word设置上标快捷键 #学习方法#其他#媒体

word设置上标快捷键 办公中,少不了使用word,这个是大家必备的软件,今天给大家分享word设置上标快捷键,希望在办公中能帮到您! 1、添加上标 在录入一些公式,或者是化学产品时,需要添加上标内容,按下快捷键Ctrl+shift++就能将需要的内容设置为上标符号。 word设置上标快捷键的方法就是以上内容了,需要的小伙伴都可以试一试呢!

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

大学湖北中医药大学法医学试题及答案,分享几个实用搜题和学习工具 #微信#学习方法#职场发展

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式,可以快速查找问题解析,加深对题目答案的理解。 1.快练题 这是一个网站 找题的网站海量题库,在线搜题,快速刷题~为您提供百万优质题库,直接搜索题库名称,支持多种刷题模式:顺序练习、语音听题、本地搜题、顺序阅读、模拟考试、组卷考试、赶快下载吧! 2.彩虹搜题 这是个老公众号了 支持手写输入,截图搜题,详细步骤,解题必备

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

《offer来了》第二章学习笔记

1.集合 Java四种集合:List、Queue、Set和Map 1.1.List:可重复 有序的Collection ArrayList: 基于数组实现,增删慢,查询快,线程不安全 Vector: 基于数组实现,增删慢,查询快,线程安全 LinkedList: 基于双向链实现,增删快,查询慢,线程不安全 1.2.Queue:队列 ArrayBlockingQueue:

硬件基础知识——自学习梳理

计算机存储分为闪存和永久性存储。 硬盘(永久存储)主要分为机械磁盘和固态硬盘。 机械磁盘主要靠磁颗粒的正负极方向来存储0或1,且机械磁盘没有使用寿命。 固态硬盘就有使用寿命了,大概支持30w次的读写操作。 闪存使用的是电容进行存储,断电数据就没了。 器件之间传输bit数据在总线上是一个一个传输的,因为通过电压传输(电流不稳定),但是电压属于电势能,所以可以叠加互相干扰,这也就是硬盘,U盘