Vivado HLS 完整语法大全(C/C++ 扩展 + 综合指令 + 接口 + 优化 + 数据类型 + 函数 / 循环 / 数组)

Vivado HLS 基于标准 C/C++,额外提供 #pragma HLS 综合专用指令、硬件限定语法、接口协议语法、定点类型、并行 / 流水 / 资源约束语法,下文分模块全覆盖所有常用语法。

一、基础数据类型(HLS 硬件专用扩展)

1. 标准整数 / 浮点(兼容 C)

复制代码
char/short/int/long/unsigned char...
float/double // 浮点会综合为DSP,资源大

2. 定点类型(核心,#include "ap_fixed.h")

语法模板
复制代码
ap_fixed<总位宽, 整数位宽, 舍入模式, 溢出模式> 变量名;
ap_ufixed<总位宽, 整数位宽, 舍入模式, 溢出模式> // 无符号定点
  • 参数说明:
    1. 总位宽 W:包含整数 + 小数
    2. I:整数部分位数(含符号位)
    3. 舍入模式(可选): AP_RND四舍五入 / AP_TRUNC截断 / AP_RND_ZERO向 0 取整
    4. 溢出模式(可选): AP_WRAP循环溢出 / AP_SAT饱和限幅
示例
复制代码
ap_fixed<16,8> data;       // 16位有符号,8位整数,默认截断+循环溢出
ap_ufixed<32,10,AP_RND,AP_SAT> coeff;

3. 任意位宽整数(#include "ap_int.h",最常用硬件位宽)

复制代码
ap_uint<N>  // 无符号N位整数 N∈[1,1024]
ap_int<N>   // 有符号N位整数 N∈[1,1024]

示例:

复制代码
ap_uint<8>  byte;
ap_int<12>  sensor_val;
ap_uint<1>  flag; // 1位布尔替代bool

4. 其他专用类型

  1. ap_bool:1 位布尔,等价 ap_uint<1>

  2. hls::stream<T>:数据流 FIFO(接口 / 流水线必备)

  3. complex<T>:复数定点,#include "ap_complex.h"

    复制代码
    ap_complex<ap_fixed<16,6>> cpx;

二、数据流 hls::stream 语法(AXI-Stream 硬件 FIFO)

头文件

复制代码
#include "hls_stream.h"
using namespace hls;

定义语法

复制代码
stream<数据类型> 流名 DEPTH=深度;
// 综合深度约束 pragma 配套
stream<ap_uint<32>> data_in;

读写 API 语法(阻塞 / 非阻塞)

复制代码
// 阻塞读写(综合推荐,自动同步流水线)
stream.read(var);    // 读1个数据
stream.write(val);   // 写1个数据

// 非阻塞(带状态返回)
bool ok = stream.read_nb(var);
bool ok = stream.write_nb(val);

// 空/满判断
bool empty() = stream.empty();
bool full()  = stream.full();

// 批量读写(burst)
stream.read_block(buf, len);
stream.write_block(buf, len);

流深度约束 pragma 配套

复制代码
#pragma HLS STREAM variable=data_in depth=64
#pragma HLS STREAM variable=data_in type=fifo // fifo/shift_register

三、核心综合指令:#pragma HLS 全语法(重中之重)

所有 #pragma HLS 必须放在函数内、循环上方、变量上方,作用域分:函数级、循环级、数组 / 变量级、接口级。

(一)接口相关 pragma(顶层函数 IO,生成 AXI/IO 协议)

1. INTERFACE:指定端口硬件协议

通用语法:

复制代码
#pragma HLS INTERFACE 协议类型 port=端口名 [参数列表]
  1. ap_none:普通寄存器 IO(默认)

    #pragma HLS INTERFACE ap_none port=din

  2. ap_ctrl_hs:握手控制信号(valid/ready)

    #pragma HLS INTERFACE ap_ctrl_hs port=din

  3. ap_ctrl_chain:链式流水线握手

  4. ap_fifo:端口映射外部 FIFO

    #pragma HLS INTERFACE ap_fifo port=stream_out depth=128

  5. axis:AXI4-Stream 数据流接口

    #pragma HLS INTERFACE axis port=input_stream register_mode=both
    // 参数:register_mode=off/input/output/both

  6. s_axilite:AXI4-Lite 寄存器控制(寄存器映射)

    #pragma HLS INTERFACE s_axilite port=return bundle=CTRL
    #pragma HLS INTERFACE s_axilite port=cfg bundle=CTRL offset=0x10
    // bundle:分组同一AXI-Lite总线;offset:寄存器地址偏移

  7. m_axi:AXI4-Master 外部 DDR 读写(数组 / 指针)

    #pragma HLS INTERFACE m_axi port=ddr_buf offset=slave bundle=MEM depth=1024
    // offset=slave:偏移由AXI-Lite配置;direct:直接地址
    // max_read_burst_length/max_write_burst_length:突发长度

完整带参示例:

复制代码
#pragma HLS INTERFACE m_axi port=output offset=slave bundle=OUT_DMA max_write_burst_length=256
2. RESOURCE:绑定端口到 IO 资源
复制代码
#pragma HLS RESOURCE variable=din core=AXI_STREAM

(二)循环优化类 pragma(流水、展开、重定时)

1. PIPELINE 流水线(最常用,II = 启动间隔)

语法(放在循环 / 函数开头):

复制代码
#pragma HLS PIPELINE II=N [rewind] [flatten]
  • II=1:最优无气泡流水线

  • rewind:循环首尾直通,消除循环间隔

  • flatten:嵌套循环合并单一流水

    void top(){
    #pragma HLS PIPELINE II=1 rewind
    for(int i=0;i<1024;i++){ ... }
    }

    for(int i=0;i<64;i++){
    #pragma HLS PIPELINE II=2
    }

2. UNROLL 循环展开(并行计算,消耗更多硬件)
复制代码
// 完全展开
#pragma HLS UNROLL
// 部分展开,每3次迭代一组并行
#pragma HLS UNROLL factor=3
// 带偏移展开
#pragma HLS UNROLL factor=4 skip_exit_check
3. LOOP_FLATTEN 嵌套循环扁平化
复制代码
#pragma HLS LOOP_FLATTEN
// 把两层for合并为单层,方便统一流水
4. LOOP_MERGE 合并多个独立循环
复制代码
#pragma HLS LOOP_MERGE force
// force强制合并无依赖循环,提升吞吐
5. LOOP_TRIPCOUNT 指定循环迭代上限(辅助时序分析)
复制代码
#pragma HLS LOOP_TRIPCOUNT min=16 max=1024 avg=512
6. RESHAPE 循环迭代重排序
复制代码
#pragma HLS RESHAPE variable=arr type=block factor=4 dim=1

(三)数组存储资源约束(BRAM/LUTRAM/REG/ROM)

1. ARRAY_RESHAPE 数组分块 / 重组(并行访问,消除访存冲突)
复制代码
// 一维数组拆分为4路并行数组,块式分割
#pragma HLS ARRAY_RESHAPE variable=buf type=block factor=4 dim=1
// 循环分割 cyclic
#pragma HLS ARRAY_RESHAPE variable=buf type=cyclic factor=2 dim=1
// 完整打散为独立寄存器
#pragma HLS ARRAY_RESHAPE variable=coeff type=complete dim=1
2. ARRAY_PARTITION 数组分区(核心,解决单端口 RAM 访存瓶颈)
复制代码
#pragma HLS ARRAY_PARTITION variable=数组名 type=模式 factor=N dim=维度
  • type=complete:全分区,每个元素独立寄存器(最高并行,资源大)

  • type=block:块分区,连续 N 个元素一组

  • type=cyclic:交错分区,元素循环分配到存储块 示例:

    int coeff[16];
    #pragma HLS ARRAY_PARTITION variable=coeff type=complete dim=1

    ap_uint<32> mat[8][8];
    #pragma HLS ARRAY_PARTITION variable=mat type=block factor=4 dim=2 // 对二维第二维分区

3. ARRAY_MAP 多数组合并到同一 RAM
复制代码
#pragma HLS ARRAY_MAP variable={a,b,c} instance=shared_ram latency=1
4. RESOURCE 指定数组硬件载体
复制代码
// 绑定到Block RAM
#pragma HLS RESOURCE variable=ram_buf core=RAM_2P_BRAM
// LUTRAM分布式RAM
#pragma HLS RESOURCE variable=small_buf core=RAM_1P_LUTRAM
// 常量数组映射ROM
const int coeff[64]={...};
#pragma HLS RESOURCE variable=coeff core=ROM_2P
// 寄存器堆
#pragma HLS RESOURCE variable=reg_buf core=REG

RAM core 可选列表: RAM_1P_BRAM / RAM_2P_BRAM / RAM_TDP_BRAM / RAM_1P_LUTRAM / RAM_2P_LUTRAM

5. DEPENDENCE 消除虚假数据依赖(允许并行 / 流水)
复制代码
// RAW/WAW/WAR 依赖忽略
#pragma HLS DEPENDENCE variable=buf inter false
#pragma HLS DEPENDENCE variable=buf intra false
// inter:不同迭代间依赖;intra:同迭代内依赖

(四)函数级优化 pragma

1. INLINE 函数内联,消除函数调用层级
复制代码
// 强制内联
#pragma HLS INLINE
// 禁止内联,生成独立硬件模块
#pragma HLS INLINE off
2. STREAM 流深度、存储类型约束
复制代码
#pragma HLS STREAM variable=data_fifo depth=256 type=fifo
// type=fifo / shift_register
3. ALLOCATION 限制运算单元复用数量(控制资源)
复制代码
// 乘法器最多实例化2个
#pragma HLS ALLOCATION instances=mul limit=2 function=*
// 自定义函数最多3个硬件实例
#pragma HLS ALLOCATION instances=filter limit=3 function=filter
4. LATENCY 约束函数最大延迟
复制代码
#pragma HLS LATENCY min=10 max=100
5. RESHAPE 函数数组重塑(同数组 reshape)

(五)常量 / ROM、全局变量、顶层专用

  1. CONSTANT 常量强制映射 ROM

    #pragma HLS CONSTANT variable=table

  2. TOP 指定顶层函数(综合入口)

    #pragma HLS TOP function=main_process

  3. DATAFLOW 多函数流水线并发(模块间流传输,无全局缓存) 函数组语法

    void top(){
    #pragma HLS DATAFLOW // 函数级dataflow
    stage1(in, mid);
    stage2(mid, out);
    }

配套约束:

c

运行

复制代码
#pragma HLS DATAFLOW
#pragma HLS STREAM variable=mid depth=32

dataflow 作用:多个子函数并行流水,依靠 stream 交互,大幅提升吞吐。

四、指针与数组语法(HLS 硬件限制 + 扩展)

1. 一维 / 二维数组标准定义

c

运行

复制代码
ap_uint<16> buffer[1024];
ap_fixed<24,8> matrix[32][32];
// 常量ROM数组
const ap_uint<8> lut[256] = {0x01,0x02,...};

2. 指针约束(顶层指针默认映射 AXI-MASTER)

c

运行

复制代码
void top(ap_uint<32> *in, ap_uint<32> *out){
#pragma HLS INTERFACE m_axi port=in bundle=DMA
}
  • HLS 不支持动态 malloc/free,仅支持静态数组 / 顶层指针
  • 函数内部禁止动态内存分配

3. 数组传参语法

c

运行

复制代码
// 定长数组
void filter(int buf[64]);
// 未指定长度(推荐搭配m_axi)
void dma_transfer(int buf[]);

五、控制流扩展语法(标准 C 兼容 + HLS 硬件特性)

1. 分支 if /else if /else

标准 C,可搭配资源共享优化,分支过多会增大 latency

c

运行

复制代码
if(flag){
    a += b;
}else{
    a -= b;
}

2. switch-case(综合为多路选择器 MUX)

c

运行

复制代码
switch(op){
    case 0: res = a+b; break;
    case 1: res = a-b; break;
    default: res = 0;
}

3. 循环 for /while/do-while

支持所有标准循环,搭配 UNROLL/PIPELINE/LOOP_FLATTEN

c

运行

复制代码
for(ap_uint<10> i=0;i<1024;i++){}

ap_uint<8> cnt=0;
while(cnt<64){ cnt++; }

4. 条件运算符 ?:

综合为 2 选 1 MUX,适合流水线无分支

c

运行

复制代码
res = en ? data : 0;

5. goto(不推荐,综合时序差)

HLS 支持但强烈禁用,破坏流水线分析

六、定点 / 复数运算语法(ap_fixed/ap_complex)

1. 基础四则运算

c

运行

复制代码
ap_fixed<16,6> a,b,c;
c = a + b;
c = a * b; // 乘法自动扩展位宽,可手动截断
c = a >> 2; // 移位缩放定点

2. 定点类型转换

c

运行

复制代码
ap_fixed<32,10> big = a; // 高位宽接收低位宽自动扩展
ap_fixed<8,2> small = (ap_fixed<8,2>)big; // 强制截断

3. 复数运算 ap_complex

c

运行

复制代码
ap_complex<ap_fixed<16,5>> x,y,z;
z = x + y;
z = x * y;
z.real() // 取实部
z.imag() // 取虚部

七、函数语法与模块划分

1. 普通子函数

c

运行

复制代码
ap_uint<16> add(ap_uint<8> a, ap_uint<8> b){
#pragma HLS INLINE
    return a + b;
}

2. 顶层函数(硬件顶层模块,必须无返回 / 返回 void 或 ap_ctrl 状态)

c

运行

复制代码
void top_demo(
    stream<ap_uint<32>> &din,
    stream<ap_uint<32>> &dout,
    ap_uint<8> cfg
){
#pragma HLS TOP
#pragma HLS INTERFACE axis port=din
#pragma HLS INTERFACE axis port=dout
#pragma HLS INTERFACE s_axilite port=cfg bundle=CTRL
#pragma HLS PIPELINE II=1
}

3. 引用传参 & 流引用(stream 必须传引用,拷贝无法综合)

c

运行

复制代码
void process(stream<ap_uint<16>> &in, stream<ap_uint<16>> &out);

注意:hls::stream 不支持值拷贝,只能 & 引用传递

4. 递归函数

HLS不支持递归综合,递归代码会报错,必须展平为循环

八、结构体 struct 语法(打包多通道数据)

定义 + 流传输常用

c

运行

复制代码
typedef struct{
    ap_uint<16> data;
    ap_uint<1> valid;
} axi_pkt;

stream<axi_pkt> pkt_stream;

结构体端口接口

c

运行

复制代码
void top(stream<axi_pkt> &in);
#pragma HLS INTERFACE axis port=in

HLS 会自动把结构体打包为连续位宽总线输出 AXIS。

九、仿真专用语法(仅 C 仿真,不综合到硬件)

1. 测试激励文件 tb.c 专用函数

c

运行

复制代码
#include "hls_tb.h"
// 文件读写(仅仿真有效,综合时自动删除)
FILE *fp = fopen("input.txt","r");
fread/fwrite/fprintf
// 打印调试
printf("data = %d\n", val);
// 波形dump(生成VCD)
hls_dump_wave("wave.vcd");

2. 条件综合宏(区分仿真 / 硬件综合)

c

运行

复制代码
#ifdef __SYNTHESIS__
// 仅综合执行(硬件代码)
#else
// 仅C仿真执行(激励打印、文件IO)
#endif

__SYNTHESIS__ 是 HLS 内置宏,综合工具自动定义。

十、位操作硬件专用语法(ap_uint/ap_int)

1. 切片取位(核心硬件操作)

c

运行

复制代码
ap_uint<32> word = 0x12345678;
ap_uint<8> byte0 = word.range(7,0); // [7:0]低8位
ap_uint<4> nibble = word.range(11,8);
word.range(15,8) = 0xAA; // 位域赋值

ap_uint<1> bit3 = word[3]; // 单bit读取
word[5] = 1; // 单bit写

2. 移位、按位运算

c

运行

复制代码
word << 2; word >> 1;
word & mask; word | val; word ^ 0xFF; ~word;

3. 拼接 concat ()

c

运行

复制代码
ap_uint<16> high = 0xABCD;
ap_uint<16> low  = 0x1234;
ap_uint<32> full = concat(high, low); // 拼接高低位

十一、全局变量语法限制

  1. 全局数组默认生成共享 BRAM,多读写端口会产生冲突,必须加ARRAY_PARTITION
  2. 全局 stream 不推荐,优先函数局部 stream+dataflow
  3. 全局 const 数组自动映射 ROM

c

运行

复制代码
const ap_uint<16> sine_lut[256] = { ... };
#pragma HLS RESOURCE variable=sine_lut core=ROM_1P

十二、完整语法速记分类表

表格

类别 核心语法 / 关键字
硬件位宽 ap_uint<N> ap_int<N>
定点小数 ap_fixed ap_ufixed ap_complex
数据流 FIFO hls::stream<T> .read() .write()
综合指令 #pragma HLS PIPELINE UNROLL ARRAY_PARTITION INTERFACE DATAFLOW INLINE ALLOCATION DEPENDENCE STREAM RESOURCE TOP
数组优化 ARRAY_PARTITION / ARRAY_RESHAPE / ARRAY_MAP
接口协议 axis m_axi s_axilite ap_fifo ap_ctrl_hs
循环优化 PIPELINE II LOOP_FLATTEN LOOP_MERGE LOOP_TRIPCOUNT UNROLL
位操作 .range() [] concat()
综合宏 __SYNTHESIS__
并行架构 DATAFLOW 多函数流水线
存储资源 RAM_BRAM RAM_LUTRAM ROM REG
仿真专用 printf fopen fread hls_dump_wave

十三、高频易错语法规则(必记)

  1. stream 只能引用传递,不能值传递;
  2. 动态malloc/ 递归不支持综合;
  3. #pragma HLS 必须紧跟作用对象上方,不能跨代码块;
  4. 顶层数组指针搭配 m_axi 接口实现 DDR 访问;
  5. 多端口同时读数组必须分区 ARRAY_PARTITION complete
  6. PIPELINE II=1 要求消除所有迭代间数据依赖,需配合DEPENDENCE
  7. DATAFLOW 仅支持 void 子函数,依靠 stream 交互;
  8. 定点乘法默认扩展位宽,长乘后需手动截断避免位宽爆炸;
  9. ap_uint<1> 替代 bool,综合仅 1 位寄存器;
  10. 循环变量尽量用ap_uint代替 int,减少符号位硬件消耗。