AI 引擎包含标量处理器,可用于实现标量数学运算、非线性函数及其他常规运算。有时,代码的黄金标量参考版本很有用。但请注意,代码的标量版本在仿真和硬件中运行时所耗费的时间比矢量化版本要长得多。
以下提供了 32 抽头滤波器的标量版本的代码示例:
static cint16 eq_coef[32]={{1,2},{3,4},...};
//keep margin data between different invocations of the graph
static cint16 delay_line[32];
__attribute__((noinline)) void fir_32tap_scalar(input_stream<cint16> * sig_in,
output_stream<cint16> * sig_out){
//For profiling only
unsigned cycle_num[2];
aie::tile tile=aie::tile::current();
for(int i=0;i<SAMPLES;i++){
cycle_num[0]=tile.cycles();//cycle counter of the AI Engine tile
cint64 sum={0,0};//larger data to mimic accumulator
for(int j=0;j<32;j++){
//auto integer promotion to prevent overflow
sum.real+=delay_line[j].real*eq_coef[j].real-delay_line[j].imag*eq_coef[j].imag;
sum.imag+=delay_line[j].real*eq_coef[j].imag+delay_line[j].imag*eq_coef[j].real;
}
sum=sum>>SHIFT;
//produce one sample per loop iteration
writeincr(sig_out,{(int16)sum.real,(int16)sum.imag});
for(int j=0;j<32;j++){
if(j==31){
delay_line[j]=readincr(sig_in);
}else{
delay_line[j]=delay_line[j+1];
}
}
//For profiling only
cycle_num[1]=tile.cycles();//cycle counter of the AI Engine tile
printf("start=%d,end=%d,total=%d\n",cycle_num[0],cycle_num[1],cycle_num[1]-cycle_num[0]);
}
}
void fir_32tap_scalar_init()
{
//initialize data
for (int i=0;i<32;i++){
int tmp=get_ss(0);
delay_line[i]=*(cint16*)&tmp;
}
};
注释:
-
fir_32tap_scalar_init
函数用作为内核的初始化函数,执行graph.run()
后仅调用一次。 - 在标量处理器中不支持舍入与饱和模式。这些模式可通过标准 C 语言操作(如,
shift
)来实现。 - 拼块计数器用于对代码主循环进行剖析。
从剖析结果中可以看到,每个样本耗时 3068 个周期。如果您在 AI 引擎仿真期间启用
--profile
选项,那么也可在 Vitis IDE 的“Profile”(剖析)部分下查看类似信息。图 1. 剖析详情
如需了解有关计算图构造和不同类型的剖析技巧的更多信息,请参阅 AI 引擎工具和流程用户指南 (UG1076) 中的基于 AI 引擎仿真的性能分析和在硬件上执行 AI 引擎计算图应用性能分析。