某水课课程作业,记录全流程顺便做个教程。作业具体要求如下:
FIR滤波器的HLS实现
工程准备
新建工程---------->略
在工程目录下新建一个放代码文件的文件夹,这里命名为src(推荐,方便管理代码),该文件夹下新建三个新文件,命名如下图。前两个文件用于HLS综合,后一个用来写testbench。
进入HLS软件,添加相对应的文件。
FIR滤波器设计
使用Matlab的fdatool工具进行FIR滤波器设计,设计完成后先对滤波器系数进行定点化后再导出。
导出得到的就是待会需要使用的滤波器系数。
FIR滤波器实现
FIR的原理这里就不写了,直接贴HLS实现的代码。
使用常量储存滤波器系数,输入数据缓存则是使用静态变量防止每次执行都被初始化,for循环内实现输入缓存移位与乘项累加。因为乘法与加法都会扩大数据位宽,所以这里函数顶层的输出接口位宽会比输入接口位宽大得多。
#include "fir_low.h"
const int Filter_N = 16;
const ap_int<16> coe[Filter_N] = {
0xfe39, 0xfd84, 0xfdd4, 0x048d, 0x16a6, 0x3352, 0x51f9, 0x65f1,
0x65f1, 0x51f9, 0x3352, 0x16a6, 0x048d, 0xfdd4, 0xfd84, 0xfe39
};
void Fir_Test(ap_int<16> Input, ap_int<32> *LowPass)
{
static ap_int<16> data_buffer[Filter_N] = {0};
ap_int<32> result = 0;
for (ap_uint<5> i = Filter_N - 1; i > 0; i--)
{
data_buffer[i] = data_buffer[i - 1];
result += data_buffer[i] * coe[i];
}
data_buffer[0] = Input;
result += data_buffer[0] * coe[0];
*LowPass = result;
}
#ifndef __FIR_LOW_H
#define __FIR_LOW_H
#include "ap_int.h"
void Fir_Test(ap_int<16> Input, ap_int<32> *LowPass);
#endif
设置好Top Function后,进行HLS综合。
目前没有添加任何优化约束,HLS综合结果如下图,Interval还未达到预期,接下来进行优化。
FIR滤波器优化
因为代码主要执行部分为for循环且循环内不存在数据依赖,可以考虑将该循环做展开。循环外还有部分操作,因此可以直接使用PIPELINE指令进行优化,HLS编译器会将循环自动展开并流水化。
void Fir_Test(ap_int<16> Input, ap_int<32> *LowPass)
{
static ap_int<16> data_buffer[Filter_N] = {0};
ap_int<32> result = 0;
#pragma HLS PIPELINE
for (ap_uint<5> i = Filter_N - 1; i > 0; i--)
{
data_buffer[i] = data_buffer[i - 1];
result += data_buffer[i] * coe[i];
}
data_buffer[0] = Input;
result += data_buffer[0] * coe[0];
*LowPass = result;
}
添加以上约束后,HLS综合结果如下图,Interval已优化为1,达到设计目的。
FIR滤波器仿真
仿真激励代码如下,每一次调用Fir_Test函数即相当于在一个时钟周期输入一个数据并获取一个输出值,这里生成的输入信号为周期等于20个时钟周期的方波。
#include "fir_low.h"
int main(void)
{
ap_int<32> out;
for(int k = 0; k < 10; k++)
{
for(int i = 0; i < 10; i++)
{
Fir_Test(10000, &out);
printf("%d\r\n", out);
}
for(int j = 0; j < 10; j++)
{
Fir_Test(-10000, &out);
printf("%d\r\n", out);
}
}
return 0;
}
选择C Simulation开始仿真,操作及结果输出如图。当然这里我没有写正确性检验,只是单纯输出了结果也不好脑补滤波后的信号,接下来进行联合仿真看看实际波形。
选择Cosimulation进行联合仿真,操作及结果输出如图,然后点击这个小波形图打开Vivado查看仿真波形。找到箭头所指的两个信号:输入与输出,修改一下波形格式就可以观察到明显的滤波器效果了。
模块接口优化
考虑到模块使用的便捷性,对其接口再进行一些优化,去掉其握手信号。
#pragma HLS INTERFACE mode=ap_ctrl_none port=return
#pragma HLS INTERFACE mode=ap_none port=Input
#pragma HLS INTERFACE mode=ap_none port=LowPass
其他
总体来说,使用HLS设计算法模块还是很简单快捷的,而且Xilinx推出了许多算法函数库,直接调库就可以实现大部分算法(例如上文的FIR滤波器)。
Vitis_Libraries库:https://docs.xilinx.com/r/en-US/Vitis_Libraries/index.html