打开vivado HLS command prompt,
首先是,切换盘符,直接键入
---->E:
切换到E盘,
然后,运行cd命令,
到需要打开工程的目录下,
---->cd E:\studyhls\lab3
然后显示目录已经更改成功,
E:\studyhls\lab3>
然后,运行
E:\studyhls\lab3>vivado_hls -f run_hls.tcl
建立工程。
然后dir命令,查看一下有哪些新建的文件夹。
可以看到,新建了一个fir_prj文件。
这时,运行
E:\studyhls\lab3>vivado_hls -p fir_prj
就可以启动这个工程的GUI了。
实际工作中,推荐使用TCL模式建工程,工程建好后,在GUI下运行工作任务。
使用tcl,总能找到对应的工程模式下的操作。
在每个solution中,都由一个script.tcl文件,这就是执行的命令的TCL记录文件。
而directives.tcl,则是保存了用于这个solution的directives的TCL记录命令。
下面分别说明各个命令:
+++++++++++++++++++++++++
open_project -reset fir_prj
在上级目录下,从.project文件,找到PRJ的对应信息,打开一个工程。
set_top fir
在工程中,project setting->synthesis->top function,点击browse,找到对应的函数,设置为TOP。
add_files fir_prj/src/fir.c
在工程中,添加source file。
add_files -tb fir_prj/tb/fir_test.c -cflags "-I ../src"
在工程中,添加TB文件,并指定source file的位置。
工程模式中,建议如果要添加path,不要加cflags,
而是在工程文件夹上,右键选择property,进入property for prj界面。
在C++ general->path and symbols中,
添加或者删除path。
add_files -tb fir_prj/tb/out.gold.dat
在工程中,添加TB文件,数据文件。
open_solution -reset "solution1"
在工程中,打开一个solution。
set_part
在工程中,solution setting中,设置part。
create_clock
在工程中,solution setting中,设置clock。
source “./fir_prj/solution3/directives.tcl”
在工程中,导入directives.tcl中的信息。
csim_design
在工程中,run csim.
csynth_design
在工程中,run synthesis。
cosim_design -tool xsim
在工程中,run cosim。
export_design -rtl verilog -format ip_catalog
在工程中,export RTL。
exit
退出
++++++++++++++++++++++++++++++++++++
在源文件编写时,需要一个头文件,这个头文件可以是和top模块同名的头文件,例如XXX.h,也可以定义为XXX_types.h。
在这里面,需要对所用到的类型进行统一的typedef。
例如fir,
首先是头文件保护宏。
#ifndef FIR_H_
#define FIR_H_
...
#endif
然后再添加常数的实义化定义宏。
#define N 11
然后再添加类型的实义化定义。
后缀加上“_t”标识,用来表明这是一个自定义的类型。
typedef int coef_t;
typedef int data_t;
typedef int acc_t;
然后是添加函数的原型定义。
void fir (
data_t *y,
coef_t c[N+1],
data_t x
);
+++++++++++++++++++++++++++++++++++
在源文件编写时,首先就是包含这个自有的头文件。
#include "fir.h"
在源文件中使用的数据类型,原则上,尽可能使用在H文件中typedef的那些数据类型。
如果希望HLS将变量实现为RAM或者ROM,应定义为数组,而且加上static关键字。
static data_t shift_reg[N];
++++++++++++++++++++++++++++++++++++
Csim时,首先是需要包含各个头文件。
#include <stdio.h>
#include <math.h>
#include "fir.h"
在Csim时,是由main作为TB来运行的。
main通常有两种写法,一种是
int main ()
无参数写法,表示TB并不需要从命令行提取参数。
另一种是
int main(int argc, char** argv)
带参数写法,表示TB需要从命令行中提取字符串参数。
例如:
in_gray = cv::imread(argv[1], 0);
使用了argv[1]这个字符串。
在工程模式下,project setting->simulation->input arguments中输入参数字符串。
++++++++++++++++++++++++++++++++++++++++
testbench中,推荐使用文件操作,
一方面用来从文件中读取数据,另一方面,写入文件后,与金样比对。
int ret;
FILE *fp;
...
fp=fopen("out.dat","w");
...
for (i=0;i<=SAMPLES;i++) {
if (ramp_up == 1)
signal = signal + 1;
else
signal = signal - 1;
// Execute the function with latest input
fir(&output,taps,signal);
if ((ramp_up == 1) && (signal >= 75))
ramp_up = 0;
else if ((ramp_up == 0) && (signal <= -75))
ramp_up = 1;
// Save the results.
fprintf(fp,"%i %d %d\n",i,signal,output);
}
...
fclose(fp);
ret = system("diff -w out.dat out.gold.dat");
if (ret) {
fprintf(stdout, "FAIL: Output DOES NOT match the golden output\n");
return 1;
} else {
fprintf(stdout, "PASS: The output matches the golden output!\n");
return 0;
}
声明一个FP。然后打开文件,用fp作为句柄。
在一个for循环中,执行了多次test task。
每一次的test task的执行,就是一次for循环体的迭代执行。
在每一次的test task的执行体中,大致分为如下部分,
pre-process,为DUT准备所需的数据,
Call DUT,调用DUT的函数。
post-porcess,调整环境变量,为下一次迭代,发起test task做环境准备。
record result,记录下本次DUT的test task的结果。本例中,即写入输出文件。
在所有的迭代测试任务结束后,关闭文件。
然后进行result compare,判断测试结果。
这里,使用的是系统函数system,
这个函数调用系统CMD命令行,并返回CMD命令行的执行结果。
system系统函数接受一个string参数,并解析为一个CMD命令行。
返回结果如果不是0,则为ERROR,如果为0,则为SUCCESS。
++++++++++++++++++++++++++++++++++++
在源文件编写时,需要一个头文件,这个头文件可以是和top模块同名的头文件,例如XXX.h,也可以定义为XXX_types.h。
在这里面,需要对所用到的类型进行统一的typedef。
例如fir,
首先是头文件保护宏。
#ifndef FIR_H_
#define FIR_H_
...
#endif
然后再添加常数的实义化定义宏。
#define N 11
然后再添加类型的实义化定义。
后缀加上“_t”标识,用来表明这是一个自定义的类型。
typedef int coef_t;
typedef int data_t;
typedef int acc_t;
然后是添加函数的原型定义。
void fir (
data_t *y,
coef_t c[N+1],
data_t x
);
+++++++++++++++++++++++++++++++++++
在源文件编写时,首先就是包含这个自有的头文件。
#include “fir.h”
在源文件中使用的数据类型,原则上,尽可能使用在H文件中typedef的那些数据类型。
如果希望HLS将变量实现为RAM或者ROM,应定义为数组,而且加上static关键字。
static data_t shift_reg[N];
++++++++++++++++++++++++++++++++++++
Csim时,首先是需要包含各个头文件。
#include <stdio.h>
#include <math.h>
#include "fir.h"
在Csim时,是由main作为TB来运行的。
main通常有两种写法,一种是
int main ()
无参数写法,表示TB并不需要从命令行提取参数。
另一种是
int main(int argc, char** argv)
带参数写法,表示TB需要从命令行中提取字符串参数。
例如:
in_gray = cv::imread(argv[1], 0);
使用了argv[1]这个字符串。
在工程模式下,project setting->simulation->input arguments中输入参数字符串。
++++++++++++++++++++++++++++++++++++++++
testbench中,推荐使用文件操作,
一方面用来从文件中读取数据,另一方面,写入文件后,与金样比对。
例如下面的例子:
文件求差法,将输出结果迭代写入文件,最后再将文件与金样文件求差比对。
int ret;
FILE *fp;
...
fp=fopen("out.dat","w");
...
for (i=0;i<=SAMPLES;i++) {
if (ramp_up == 1)
signal = signal + 1;
else
signal = signal - 1;
// Execute the function with latest input
fir(&output,taps,signal);
if ((ramp_up == 1) && (signal >= 75))
ramp_up = 0;
else if ((ramp_up == 0) && (signal <= -75))
ramp_up = 1;
// Save the results.
fprintf(fp,"%i %d %d\n",i,signal,output);
}
...
fclose(fp);
ret = system("diff -w out.dat out.gold.dat");
if (ret) {
fprintf(stdout, "FAIL: Output DOES NOT match the golden output\n");
return 1;
} else {
fprintf(stdout, "PASS: The output matches the golden output!\n");
return 0;
}
声明一个FP。然后打开文件,用fp作为句柄。
在一个for循环中,执行了多次test task。
每一次的test task的执行,就是一次for循环体的迭代执行。
在每一次的test task的执行体中,大致分为如下部分,
pre-process,为DUT准备所需的数据,
Call DUT,调用DUT的函数。
post-porcess,调整环境变量,为下一次迭代,发起test task做环境准备。
record result,记录下本次DUT的test task的结果。本例中,即写入输出文件。在所有的迭代测试任务结束后,关闭文件。
result compare,判断测试结果。
这里,使用的是系统函数system,
这个函数调用系统CMD命令行,并返回CMD命令行的执行结果。
system系统函数接受一个string参数,并解析为一个CMD命令行。
返回结果如果不是0,则为ERROR,如果为0,则为SUCCESS。
+++++++++++++++++++++++++++++++++++++++++
另一种方式是,
直接变量比较。
如果不是放在一个for循环里调用DUT函数,而是只在main中调用一次DUT函数就结束,则只是进行了一次test task。
同样的,一次test task,也是分为几个部分:
pre-process,为DUT准备所需的数据,
Call DUT,调用DUT的函数。
post-porcess,调整环境变量,为下一次迭代,发起test task做环境准备。本例中,不需要这个环节。
record result,记录下本次DUT的test task的结果。本例中,即写入输出变量数组。
result compare,判断测试结果。并进行counter计数。
display score,打印显示比对结果的正确次数计分和错误次数计分。
先来看看pre-process。
for (i = 0; i < WINDOW_LEN; i++) {
// Generate a test pattern for input to DUT
test_data[i] = (in_data_t)((32767.0 * (double)((i % 16) - 8) / 8.0) + 0.5);
// Calculate the coefficient value for this index
in_data_t coeff_val = (in_data_t)(WIN_COEFF_SCALE * (0.54 -
0.46 * cos(2.0 * M_PI * i / (double)(WINDOW_LEN - 1))));
// Generate array of expected values -- n.b. explicit casts to avoid
// integer promotion issues
sw_result[i] = (out_data_t)test_data[i] * (out_data_t)coeff_val;
}
由于测试数据时数组,所以使用了一个for循环体。
用for循环体,在每一次迭代中,生成了测试数据数组的一个元素,并生成了一个金样结果数组的一个元素。
再来看Call DUT。
printf("Running DUT...");
hamming_window(hw_result, test_data);
printf("done.\n");
再来看record result。
fp=fopen("result.dat","w");
printf("Testing DUT results");
for (i = 0; i < WINDOW_LEN; i++) {
fprintf(fp, "%d %d \n", hw_result[i],sw_result[i]);
printf("DUT results: Sample=%d, DUT=%d, Expected=%d\n", i, hw_result[i],sw_result[i]);
if (hw_result[i] != sw_result[i]) {
err_cnt++;
check_dots = 0;
printf("\n!!! ERROR at i = %4d - expected: %10d\tgot: %10d",
i, sw_result[i], hw_result[i]);
} else { // indicate progress on console
if (check_dots == 0)
printf("\n");
printf(".");
if (++check_dots == 64)
check_dots = 0;
}
}
fclose(fp);
由于输出结果是一个数组,所以用一个for循环来逐个处理结果数组中的每个元素。
这里,将结果记录和结果比对放在了一个for循环体中。
这里有一个常用的技巧,就是“计分板变量”。
可以设置多个不同的计分板变量,
例如err_cnt,用来对错误的比对结果进行计分,
correct_cnt,用来对正确的比对结果进行计分。
最后是display score,
if (err_cnt) {
printf("!!! TEST FAILED - %d errors detected !!!\n", err_cnt);
}
else
printf("*** Test Passed ***\n");
// Only return 0 on success
return err_cnt;
++++++++++++++++++++++++++++++++++++++++++++++++