Vitis HLS 学习笔记--函数例化(Function Instantiation)

目录

1. 简介

2. 功能分析

3. 示例分析

3.1 不使用 FUNCTION_INSTANTIATE

3.2 使用 FUNCTION_INSTANTIATE

4. 总结


1. 简介

函数例化(Function Instantiation)是 Vitis HLS 中的一个高级优化技术。它允许开发者在保持函数层次结构的同时,对函数的特定实例进行局部优化。如果函数的某些输入参数在调用时是已知的常量,那么可以利用这些信息来简化函数的控制逻辑,从而可能改善延迟和吞吐量。

2. 功能分析

在 Vitis HLS 中的函数,在没有特别指定编译指示的情况下,HLS 工具会遵循以下原则进行处理:

  • 函数保留为独立层级块:每个函数在生成的RTL(寄存器传输级)代码中都会作为一个独立的模块存在。这有助于保持设计的模块化,使得每个函数都可以独立地被验证和复用。
  • 函数分解(或内联)到更高层次的函数中:如果HLS工具决定将一个函数内联到另一个函数中,那么在RTL代码中,原本独立的函数将不再作为单独的模块存在。相反,它的逻辑会被合并到调用它的函数中。这通常是为了优化性能,减少函数调用的开销。
  • 所有实例使用单一RTL实现:如果一个函数被多次调用,每个调用实例在默认情况下都会共享相同的RTL代码块。这有助于减少生成的硬件资源的数量,因为不需要为每个函数调用创建单独的硬件实现。

Function Instantiation 语法:

#pragma HLS FUNCTION_INSTANTIATE variable=<variable>

其中,variable=<variable>:这是必需的实参,用于定义要用作为常量的函数实参。

FUNCTION_INSTANTIATE 编译指示用于为函数的每个实例创建唯一的 RTL 实现,允许根据函数调用对每个实例进行局部最优化。鉴于调用函数时部分函数输入可能是常量,此编译指示可藉此简化周围控制结构,并生成进一步优化的、更小的函数块。

3. 示例分析

3.1 不使用 FUNCTION_INSTANTIATE

char foo(char inval, char incr) {
#pragma HLS INLINE OFF
//#pragma HLS FUNCTION_INSTANTIATE variable = incr
    return inval + incr;
}

void top(char inval1, char inval2, char inval3, char* outval1, char* outval2,
         char* outval3) {
    *outval1 = foo(inval1, 0);
    *outval2 = foo(inval2, 1);
    *outval3 = foo(inval3, 100);
}

经过综合,得到如下文件结构:

可以发现,代码会为 top 中的函数的全部 3 个实例生成函数 foo 的单一 RTL 实现。函数 foo 的每个实例都是以相同方式实现的。这对于函数复用并无影响,并且可以减少函数的每次实例调用所需的面积,但是函数内部的控制逻辑必须更复杂,以便应对每次调用 foo 时产生的变化。

如下代码可以看到每次函数调用的情况:

...

example_foo tmp_foo_fu_79(
    .ap_ready(tmp_foo_fu_79_ap_ready),
    .inval(inval1),
    .incr(6'd0),
    .ap_return(tmp_foo_fu_79_ap_return)
);

example_foo tmp_1_foo_fu_88(
    .ap_ready(tmp_1_foo_fu_88_ap_ready),
    .inval(inval2),
    .incr(6'd1),
    .ap_return(tmp_1_foo_fu_88_ap_return)
);

example_foo tmp_2_foo_fu_97(
    .ap_ready(tmp_2_foo_fu_97_ap_ready),
    .inval(inval3),
    .incr(6'd36),
    .ap_return(tmp_2_foo_fu_97_ap_return)
);

always @ (*) begin
    if ((ap_start == 1'b1)) begin
        outval1_ap_vld = 1'b1;
    end else begin
        outval1_ap_vld = 1'b0;
    end
end

always @ (*) begin
    if ((ap_start == 1'b1)) begin
        outval2_ap_vld = 1'b1;
    end else begin
        outval2_ap_vld = 1'b0;
    end
end

always @ (*) begin
    if ((ap_start == 1'b1)) begin
        outval3_ap_vld = 1'b1;
    end else begin
        outval3_ap_vld = 1'b0;
    end
end

assign ap_done = ap_start;

assign ap_idle = 1'b1;

assign ap_ready = ap_start;

assign outval1 = tmp_foo_fu_79_ap_return;

assign outval2 = tmp_1_foo_fu_88_ap_return;

assign outval3 = tmp_2_foo_fu_97_ap_return;

endmodule //example

3.2 使用 FUNCTION_INSTANTIATE

char foo(char inval, char incr) {
#pragma HLS INLINE OFF
#pragma HLS FUNCTION_INSTANTIATE variable = incr
    return inval + incr;
}

void top(char inval1, char inval2, char inval3, char* outval1, char* outval2,
         char* outval3) {
    *outval1 = foo(inval1, 0);
    *outval2 = foo(inval2, 1);
    *outval3 = foo(inval3, 100);
}

经过综合,得到如下文件结构:

可以发现,代码会为 top 中的函数的由 3 个独立的实例生成函数 foo 的 RTL 实现:example_foo_0.v、example_foo_1.v、example_foo_2.v。

在以上代码样本中:

#pragma HLS FUNCTION_INSTANTIATE variable = incr

FUNCTION_INSTANTIATE 编译指示会生成函数 foo 的 3 个不同实现,每个实现都会按incr 指定值进行最优化,从而减少面积并改善函数实现的性能。

提示:Vitis HLS 工具会将小函数自动分解(或内联)到更高层次的调用函数中。即使对于函数例化也同样如此。将 INLINE 编译指示与 OFF 选项搭配使用即可阻止此自动内联操作。

4. 总结

函数例化是Vitis HLS中的一种高级优化技术,它允许开发者在保持函数层次结构的同时,对特定函数实例进行局部优化。这种技术通过利用编译时已知的常量输入参数,简化函数的控制逻辑,从而可能改善延迟和吞吐量。默认情况下,函数在RTL中作为独立层级块保留,或者分解到更高层次的函数中,所有实例共享单一RTL实现。通过使用FUNCTION_INSTANTIATE编译指示,可以为每个函数调用创建唯一的RTL实现,允许针对每个实例进行局部最优化。这样,即使原始函数包含复杂的控制逻辑,每个实例化的函数也可以被优化以仅包含必要的逻辑,减少硬件资源消耗并提高性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值