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<总位宽, 整数位宽, 舍入模式, 溢出模式> // 无符号定点
- 参数说明:
- 总位宽 W:包含整数 + 小数
- I:整数部分位数(含符号位)
- 舍入模式(可选):
AP_RND四舍五入 /AP_TRUNC截断 /AP_RND_ZERO向 0 取整 - 溢出模式(可选):
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. 其他专用类型
-
ap_bool:1 位布尔,等价ap_uint<1> -
hls::stream<T>:数据流 FIFO(接口 / 流水线必备) -
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=端口名 [参数列表]
-
ap_none:普通寄存器 IO(默认)
#pragma HLS INTERFACE ap_none port=din
-
ap_ctrl_hs:握手控制信号(valid/ready)
#pragma HLS INTERFACE ap_ctrl_hs port=din
-
ap_ctrl_chain:链式流水线握手
-
ap_fifo:端口映射外部 FIFO
#pragma HLS INTERFACE ap_fifo port=stream_out depth=128
-
axis:AXI4-Stream 数据流接口
#pragma HLS INTERFACE axis port=input_stream register_mode=both
// 参数:register_mode=off/input/output/both -
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:寄存器地址偏移 -
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=1ap_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、全局变量、顶层专用
-
CONSTANT 常量强制映射 ROM
#pragma HLS CONSTANT variable=table
-
TOP 指定顶层函数(综合入口)
#pragma HLS TOP function=main_process
-
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); // 拼接高低位
十一、全局变量语法限制
- 全局数组默认生成共享 BRAM,多读写端口会产生冲突,必须加
ARRAY_PARTITION - 全局 stream 不推荐,优先函数局部 stream+dataflow
- 全局 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 |
十三、高频易错语法规则(必记)
stream只能引用传递,不能值传递;- 动态
malloc/ 递归不支持综合; #pragma HLS必须紧跟作用对象上方,不能跨代码块;- 顶层数组指针搭配
m_axi接口实现 DDR 访问; - 多端口同时读数组必须分区
ARRAY_PARTITION complete; - PIPELINE II=1 要求消除所有迭代间数据依赖,需配合
DEPENDENCE; DATAFLOW仅支持 void 子函数,依靠 stream 交互;- 定点乘法默认扩展位宽,长乘后需手动截断避免位宽爆炸;
ap_uint<1>替代 bool,综合仅 1 位寄存器;- 循环变量尽量用
ap_uint代替 int,减少符号位硬件消耗。