录
一、函数介绍
ihc_hls_enqueue(void *retptr, void *funcptr,/*function arguments*/)
- 参数:
retptr:返回值
funcptr:将要调用的HLS component
这个函数对HLS组件的一次调用进行排队。返回值存储在第一个实参中,该实参应该是指向返回类型的指针。在调用ihc_hls_component_run_all()之前,组件不会运行。
ihc_hls_enqueue_noret(void* funcptr,/*function arguments*/)
- 参数:
funcptr:将要调用的HLS component
这个函数对HLS组件的一次调用进行排队。当HLS组件的返回类型为void时,应该使用这个函数。在调用ihc_hls_component_run_all()之前,组件不会运行。
ihc_hls_component_run_all(void* funcptr)
- 参数:
funcptr:将要调用的HLS component
这个函数接受一个指向HLS组件函数的指针。组件的所有排队调用在运行时将被推入,当组件能够接受新的调用时,HDL模拟器就能以最快的速度运行。
二、HLS相关
2.1 简介
HLS简介
HLS(High-Level Synthesis)高层综合,就是将 C/C++的功能用 RTL 来实现,将 FPGA 的组件在一个软件环境中来开发,这个模块的功能验证在软件环境中来实现,无缝的将硬件仿真环境集合在一起,使用软件为中心的工具、报告以及优化设计,很容易的在 FPGA 传统的设计工具中生成 IP。
传统的 FPGA 开发,首先写 HDL 代码,然后做行为仿真,最后做综合、时序分析等,最后生成可执行文件下载到 FPGA 使用,开发周期比较漫长。
使用 HLS,用高级语言开发可以提高效率。
因为在软件中调试比硬件快很多,在软件中可以很容易的实现指定的功能,而且做 RTL仿真比软件需要的时间多上千倍。
2.2 HLS工程的编译流程
三、普通仿真
普通仿真就是不调用以上函数,不使用流水线进行仿真。
3.1 代码
#include "HLS/stdio.h"
#include "HLS/hls.h"
#include "assert.h"
#include "stdio.h"
component int multi(int a,int b)
{
return a*b;
}
int main()
{
srand(0);//0是随机数的种子
int x,y,z,i;
for(i = 0;i<10;i++)
{
x = rand() % 10;
y = rand() % 10;
z = multi(x,y);
// printf("%d = %d + %d \n",z,x,y);
// assert(z == x+y);//断言函数,出错时报错
}
return 0;
}
3.2 i++命令前事
- 用win+R+cmd打开电脑终端
- 我们以自带的counter.cpp为例 ,直接编译会报错的
- 这时需要返回上两级目录下,进行一个编译的初始化环境的操作。
- 使用
cd ..
,使用两次,然后有一个init_hls.bat
文件,用它来初始化
- 之后就可以进行编译了,注意 每次都要切换到.c文件的目录下。
每次打开一个终端都要进行初始化.
3.3 命令行编译
- 先切换到.c文件所在目录。
1. x86模式
在默认情况下是生成
a.exe
文件,如果需要指定 则在后面加-o b.exe
下一节流水线会用到
-
命令:
i++ -march=x86-64 multi.c -v
之后:a
-
编译没问题就进行联合仿真。
2. 联合仿真模式
- 命令:
i++ -march=CycloneV multi.c -v -ghdl
之后:a
最后打开仿真:vsim a.prj\verification\vsim.wlf
3.4 仿真结果
- 打开ModelSim后添加自己命名函数的
_inst
文件到wave - 我这里为
multi_inst
- 可见是每次对每一对数值进行了计算,且有一个延时。
四、流水线
使用流水线仿真,我们不会用到第二个函数。
4.1 代码
#include "HLS/stdio.h"
#include "HLS/hls.h"
#include "assert.h"
#include "stdio.h"
component int multi(int a,int b)
{
return a*b;
}
int main()
{
srand(0);//0是随机数的种子
int x[10],y[10],z,i;
for(i = 0;i<10;i++)
{
x[i] = rand() % 10;
y[i] = rand() % 10;
ihc_hls_enqueue(&z,&add,x[i],y[i]);
}
ihc_hls_component_run_all(multi);
return 0;
}
4.2 命令行编译
1. x86模式
在默认情况下是生成
a.exe
文件,如果需要指定 则在后面加-o b.exe
为了方便查看生成的报告,所以我们这里的命令后会加-o x.exe
- 命令:
i++ -march=x86-64 multi.c -v -o b.exe
之后:b
- 同样编译没问题就进行联合仿真
2. 联合仿真模式
- 命令:
i++ -march=CycloneV multi.c -v -ghdl -o b
之后:b
最后打开仿真:vsim b.prj\verification\vsim.wlf
注意这里的 b.prj ,因为前面改变了,所以这里也要变
4.3 仿真结果
- 打开ModelSim后添加自己命名函数的
_inst
文件到wave - 同上我这里为
multi_inst
- 结果
可见同样有延时并是流水线进行,一组数据直接没有时间间隔。
五、报告对比
- 按图分别打开
a.prj
与b.prj
下的报告
a.prj
- 初始页面资源查看
- 资源分析详细查看
b.prj
可见两者所用资源情况完全相同。
总代码
- 两个模块放一起,用
ifdef
条件编译来分块使用
#include "HLS/stdio.h"
#include "HLS/hls.h"
#include "assert.h"
#include "stdio.h"
#define DEBUG //不注释掉时使用前面的代码
component int multi(int a,int b)
{
return a*b;
}
int main()
{
srand(0);//0是随机数的种子
#ifdef DEBUG
int x,y,z,i;
for(i = 0;i<10;i++)
{
x = rand() % 10;
y = rand() % 10;
z = multi(x,y);
// printf("%d = %d + %d \n",z,x,y);
// assert(z == x+y);//断言函数,出错时报错
}
#else
int x[10],y[10],z,i;
for(i = 0;i<10;i++)
{
x[i] = rand() % 10;
y[i] = rand() % 10;
// z[i] = add(x[i],y[i]); //不能赋值
ihc_hls_enqueue(&z,&add,x[i],y[i]);
}
ihc_hls_component_run_all(multi);
#endif
return 0;
}
- 参考文献