pragma HLS stream语法

默认情况下,数组变量被实现为RAM:

  • 顶层函数数组参数被实现为RAM接口端口。
  • 通用数组被实现为RAM,用于读写访问。
  • 在涉及 DATAFLOW optimizations(数据流优化)的子函数中,数组参数是使用RAM pingpong buffer (乒乓缓冲区)通道实现的。
  • 基于循环的DATAFLOW optimizations所涉及的数组被实现为一个RAM pingpong buffer 通道 。

如果存储在数组中的数据是按顺序使用或产生的,则更有效的通信机制是使用stream pragma指定的流数据,其中使用FIFOs而不是ram。
重要!:当顶级函数的参数指定为接口类型ap_fifo时,该数组自动实现为流格式
(即,用dataflow优化,数组存取使用RAM pingpong buffer 实现,用stream优化,数组存取使用FIFOs实现)

语法

将C源代码中的pragma放在所需位置的边界内。

#pragma HLS stream variable=<variable> depth=<int> dim=<int> off 

其中:

  • depth=<int>:只适用于数据流通道中的数组流。默认情况下,在RTL中实现的FIFO的深度与C代码中指定的数组大小相同。这个选项允许您修改FIFO的大小并指定不同的深度。
    当数组在数据流区域中实现时,通常使用depth=选项来减小FIFO的大小。例如,在一个数据流区域中,当所有循环和函数都以II=1的速率处理数据时,就不需要一个大型FIFO,因为数据是在每个时钟周期中产生和消耗的。在这种情况下,可以使用depth=选项将FIFO大小减少到1,从而大大减少RTL设计的面积。
    提示:config_dataflow -depth命令能够流化一个数据流区域中的所有数组。这里指定的depth=选项将覆盖指定变量的config_dataflow命令。

FIFO深度的含义[1]
FIFO的宽度:也就是英文资料里常看到的THE WIDTH,它只的是FIFO一次读写操作的数据位,就像MCU有8位和16位,ARM 32位等等,FIFO的宽度在单片成品IC中是固定的,也有可选择的,如果用FPGA自己实现一个FIFO,其数据位,也就是宽度是可以自己定义的。
FIFO的深度:THE DEEPTH,它指的是FIFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12 ,就可以存储12个8位的数据,FIFO的深度可大可小,个人认为FIFO深度的计算并无一个固定的公式。在FIFO实际工作中,其数据的满/空标志可以控制数据的继续写入或读出。在一个具体的应用中也不可能由一些参数算数精确的所需FIFO深度为多少,这在写速度大于读速度的理想状态下是可行的,但在实际中用到的FIFO深度往往要大于计算值。一般来说根据电路的具体情况,在兼顾系统性能和FIFO成本的情况下估算一个大概的宽度和深度就可以了。而对于写速度慢于读速度的应用,FIFO的深度要根据读出的数据结构和读出数据的由那些具体的要求来确定。

  • dim=<int>:指定要流化的数组的维度。默认是维度1。指定为从0到N的整数,用于具有N维数的数组。
  • off:禁用流数据。只适用于数据流通道中的数组流
    提示:config_dataflow -default_channel fifo命令全局暗示了对设计中所有数组上使用stream pragma。这里指定的off选项会覆盖指定变量的config_dataflow命令,并恢复使用基于RAM pingpong buffer通道的默认值。

例子1

下面的例子指定数组A[10]为流,并实现为FIFO:

#pragma HLS STREAM variable=A

例子2

#pragma HLS STREAM variable=B depth=12

例子3

在这个例子中,假设config_dataflow是启用的,则off命令覆盖config_dataflow设置,数组C是禁用stream的。

#pragma HLS STREAM variable=C off

在网络之中的应用例子

void DoCompute(ap_uint<64> * in, ap_uint<64> * out, const unsigned int numReps) {
#pragma HLS DATAFLOW

	stream<ap_uint<64> > inter0("DoCompute.inter0"); //文件中DoCompute.inter0的数组
	stream<ap_uint<192> > inter0_1("DoCompute.inter0_1");
	stream<ap_uint<24> > inter0_2("DoCompute.inter0_2");
#pragma HLS STREAM variable=inter0_2 depth=128 //stream处理,数组深度(大小)是128
	stream<ap_uint<64> > inter1("DoCompute.inter1");
#pragma HLS STREAM variable=inter1 depth=128
	stream<ap_uint<64> > inter2("DoCompute.inter2");
	stream<ap_uint<64> > inter3("DoCompute.inter3");
#pragma HLS STREAM variable=inter3 depth=128
	stream<ap_uint<128> > inter4("DoCompute.inter4");
#pragma HLS STREAM variable=inter4 depth=128
	stream<ap_uint<128> > inter5("DoCompute.inter5");
	stream<ap_uint<128> > inter6("DoCompute.inter6");
#pragma HLS STREAM variable=inter6 depth=81
	stream<ap_uint<256> > inter7("DoCompute.inter7");
#pragma HLS STREAM variable=inter7 depth=1
	stream<ap_uint<256> > inter8("DoCompute.inter8");
#pragma HLS STREAM variable=inter8 depth=1
	stream<ap_uint<64> > inter9("DoCompute.inter9");
#pragma HLS STREAM variable=inter9 depth=128
	stream<ap_uint<64> > inter10("DoCompute.inter10");
#pragma HLS STREAM variable=inter10 depth=3
	stream<ap_uint<64> > memOutStrm("DoCompute.memOutStrm");

参考:
[1]深入理解FIFO(包含有FIFO深度的解释)

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这段代码是一个用于实现FIR滤波器的函数。下面是对每个部分的详细注释: ```cpp #include "./fir.h" ``` 这行代码包含了一个名为"fir.h"的头文件,用于定义FIR滤波器所需的数据类型和常量。 ```cpp coef_t c[N]; ``` 这行代码定义了一个长度为N的系数数组c,用于存储滤波器的系数。 ```cpp void fir(data_t *y, data_t x) ``` 这行代码定义了一个名为fir的函数,它接受一个指向输出结果y的指针和一个输入x作为参数。 ```cpp #pragma HLS ARRAY_PARTITION variable=c complete dim=0 ``` 这行代码使用HLS指令,将系数数组c按照完全分区的方式进行分区。 ```cpp static data_t shift_reg[N]; ``` 这行代码定义了一个静态的长度为N的移位寄存器数组shift_reg,用于存储滤波器的历史输入数据。 ```cpp #pragma HLS ARRAY_PARTITION variable=shift_reg complete dim=0 ``` 这行代码使用HLS指令,将移位寄存器数组shift_reg按照完全分区的方式进行分区。 ```cpp acc_t acc; int i; acc = 0; ``` 这行代码定义了一个累加器acc和一个整型变量i,并将累加器初始化为0。 ```cpp #pragma HLS PIPELINE II=1 ``` 这行代码使用HLS指令,指示编译器将以下for循环展开为流水线,每个步骤的间隔为1个时钟周期。 ```cpp for (i = N - 1; i >= 0; i--) { if (i == 0) { acc += x * c[0]; shift_reg[0] = x; } else { shift_reg[i] = shift_reg[i - 1]; acc += shift_reg[i] * c[i]; } } ``` 这段代码是FIR滤波器的核心算法部分。它使用一个for循环遍历滤波器的系数数组和移位寄存器数组,根据当前的系数和移位寄存器的值计算累加器的值,并更新移位寄存器中的值。 ```cpp *y = acc; ``` 这行代码将累加器的值赋给输出结果y。 ```cpp void fir_wrap(data_t *y, data_t *x, int len, coef_t *coef) ``` 这行代码定义了一个名为fir_wrap的函数,它接受指向输出结果y、输入x、输入长度len和系数数组coef的指针作为参数。 ```cpp #pragma HLS INTERFACE m_axi port=coef offset=slave depth=99 #pragma HLS INTERFACE m_axi port=x offset=slave depth=100 #pragma HLS INTERFACE m_axi port=y offset=slave depth=100 #pragma HLS INTERFACE s_axilite port=len bundle=CTRL #pragma HLS INTERFACE s_axilite port=return bundle=CTRL ``` 这段代码使用HLS指令,定义了函数fir_wrap的接口。它指定了系数数组coef、输入数组x和输出数组y的访问方式和传输深度,以及输入长度len和返回值的传输方式。 ```cpp data_t res; for (int i =0; i < N; i++) { #pragma HLS PIPELINE II=1 c[i] = *coef++; } ``` 这段代码使用一个for循环将系数数组coef的值赋给数组c。在循环中使用HLS指令,将赋值操作展开为流水线,每个步骤的间隔为1个时钟周期。 ```cpp for (int i = 0; i < len; i++) { #pragma HLS PIPELINE II=1 fir(&res,*x++); *y = res; y++; } ``` 这段代码使用一个for循环对输入数组x中的每个元素进行滤波操作,并将结果存储在输出数组y中。在循环中使用HLS指令,将滤波操作展开为流水线,每个步骤的间隔为1个时钟周期。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值