66AK DSP程序优化说明此文档不介绍具体技术细节,相关技术细节,还望仔细理解官方文档。
如有疑问:请加QQ156898965平台配置66ak存储资源结构:存储资源包括DDRA、DDRB,共享内存MSMC,每个核的局部L2、L1P、L1D。
由于整个芯片的地址空间是物理统一编址的。
L1,L2运行时钟为主频,常规64系列L2运行时钟为主频一半。
MSMSRAM 运行在主频。
DSP core直接读取L1,L2,通过MSMC读取SRAM,外部DDRA。
DDRADDRBL1P可配置程序缓存;L1D可配置数据一级缓存,2-WayCache;L2可配置数据二级缓存,4-WayCache。
缓存区域从高地址开始分配。
如下图:程序数据存放区域分类程序存放区域:用于存放所有可以执行的代码和常量,程序运行过程中,不会发生改变;数据存放区域:用于全局变量和局部变量保留的空间,程序运行过程中会发生改变;堆栈存放区域:为系统堆栈保留的空间,用于和函数传递变量或为局部变量分配空间。
若因意外改变,会导致程序跑飞。
平台配置通过新建或修改Platform文件来实现存储资源定义,Cache大小分配,及程序数据存放区域指定。
以66ak12为例,缓存区域L1P,L1D 全部设置为缓存,L2缓存大小设置为256k。
程序存放于DDRB,数据存放于L2,堆栈存放于L2进行。
配置过程如下:Debug模式下,选择tools -> RTSC Tools -> Platform -> New,根据自己的需要选择Platform保存的路径以及对应的芯片,Next,填入所需要的各种空间的大小和起始位置。
芯片选择时钟定义Cache配置数据存放区域指定平台调用及验证调用Platform:在工程查看窗口,相应工程上右键Properties,选择General -> RTSC,找到最后一项,Other Repositories,点击Add,路径选择上一步保存的路径,需要注意选择XDCtools版本,然后就能找到自己新建的Platform验证:查看通过自动生成CMD文件查看,如下图所示,L2SRAM大小为768K。
详细程序数据存放位置通过map文件查看。
程序调试过程中,通过ROV也能查看堆栈大小。
注意事项1.多核同时运行时,必须保证数据段,堆栈存放位置不重叠。
多核共享变量除外。
2.多核共用一个程序,程序区域位置可重叠,多核采用不同程序,程序存放区域也不能重叠。
3.未在平台配置文件中定义的区域,如不定义DDRA空间,也能通过绝对地址访问。
CACHE使用66ak DSPcore cache简要描述。
Cache是介于DSPCORE与MCMSRAM和外部DDR间高速缓冲器,解决系统中数据读写速度不匹配及读写方式不一样等问题。
针对读,L1,L2差不多,都是从cache里面找,找不到再去下一级存储区域读入。
数据读时,主要作用如下:减少重复读时间:刚刚使用的数据,很近的将来也可能会被用到。
如fir滤波的参数。
减少连续读时间:某地址单元的数据被用到,相邻地址也可能会被用到。
如fir滤波的输入数据。
针对写,L1 没有写缓存,L2有写缓存:L1 cache缓存里面存在时,写到L1;L1缓存里面没,立即写入到L2,CPU不等待,硬件自动完成。
L2 cache 不主动往下一级写结果,只有当缓存区满或用户指定是再写回下一级存储区域。
Cache配置基于sysbios配置参见上一节平台配置。
裸机情况下配置,参看相应的demo演示程序Cache影响运算速度测试以DDRA区域,长度为32K,数据类型分别为uint8,uint16,uint32,float,double进行加法,乘法测试。
Cache配置分别为L1D 32K、L2 512K,L1D 32K、L2 0K测试结果如下表:从上表可看成:1.不开启L2 cache,平均耗时会增加。
16位操作改变最大。
2.开启L2 cache,从快到慢uint8,uint16,float,uint32,doubleCache 同步1.L1D cache 同步L2采用绝对地址定义,常用作共享变量,共享核内L2,定义如下:#define CDHZ_SYNC_INT_FLAG (*( volatileunsignedint *)0x108BFFF0u)#define CDHZ_SYNC_INT_FLAG_ADD ( (unsignedint *) 0x108BFFF0u) 向该标记赋值是,需要强制写回;其他核读此标志时,需要强制刷新Cache。
相应的CLS函数为。
CACHE_wbL1d(addr, sizeBytes, CACHE_WAIT); /* Writeback L1D */CACHE_invL1d(addr, sizeBytes, CACHE_WAIT);/* Invalidate L1D */ 以核间同步作为实例,如下:if(coreNum == 0){CDHZ_SYNC_INT_FLAG = 0xaa55;CACHE_wbL1d ((void *) CDHZ_SYNC_INT_FLAG_ADD, sizeof(uint32_t) , CACHE_WAIT);}Else{do{CACHE_invL1d ((void *) CDHZ_SYNC_INT_FLAG_ADD, sizeof(uint32_t) , CACHE_WAIT);} while( CDHZ_SYNC_INT_FLAG != 0xaa55);}2.L2 cache 同步DDR:主要用于核间大量数据传递,需要保证下一级能获取到上一级完整运算结果。
相应CSL函数请参考开发文档。
以多核共用一个程序,每个核处理不同算法模块为例,实现方式如下:switch(coreNum){…case CORE_SYS_1:{CACHE_wbAllL2(CACHE_WAIT);CACHE_invAllL2(CACHE_WAIT);tscl0 = TSCL;tsch0 = TSCH;core1_task();CACHE_wbAllL2(CACHE_WAIT);tscl1 = TSCL - tscl0;tsch1 = TSCH - tsch0;System_printf("Debug(Core %d) %8x%8x cycles \n", coreNum, tsch1,tscl1);}break;…}注意事项1.重新加载程序时,内部存储区域的数据可能维持原值。
2.L2 cache DDR同步时,可只回写同步感兴趣区域。
3.注意缓存数据无效与回写的区别。
针对芯片的程序优化C66x DSPcore内核结构如下图所示,C66X DSP核中CPU数据通道包含如下几个部分1.两组通用寄存器组。
(部分寄存器就特殊用途,如堆栈SP等)2.八个功能单元。
(不同单元能同时运行)3.两个从memory装在数据通道。
4.两个向memory写入数据通道。
5.两个数据地址通道。
6.两个寄存器组交叉通道。
C66x CPU包含两组通用寄存器。
支持范围从打包8bit到数据128bit定点数据。
当超过32bit是,通过寄存器对进行存储。
C66x支持SIMD单指令多数据流,也QMPY32指令为例,同时执行4个32位乘法。
优化的目的主要就是确保内部多个功能模块同时运行,执行SIMD指令,及对部分C语言进行简化。
循环展开,流水优化循环展开,流水操作的主要目的是让多个功能单元同时执行,并行度受指令周期影响,是数据通道限制。
如下示意图所示,表示5个功能单元同时执行。
通过给编译器熟悉相应信息,编译器会循环(loop)流水优化。
主要设置项如下:1.程序优化--opt_level=2 (or -O2) and --opt_level=3 (or -O3)。
2.通过restrict告诉编译器地址参数地址不重叠3.MUST_ITERATE(min, max, multiple)指定最小循环次数,循环倍数以上实例,参见TMS320C6000Programmer’s Guide,第三章。
SIMD优化通过编译器指定UNROLL(),编译器自动优化。
通过mv 选项指定为c66。
如下图所示:内联函数intrinsics它可以将C几个指令周期才能完成的工作在一个指令周期内完成,大大的提高了程序的运行效率。
能高效的插入SIMD。
如下是常用指令_sadd(a,b) 32位饱和加法;_sadd2(a,b) 两个16位饱和加法,高16位和高16位相加,低16位和低16位相加;SIMD_ssub(a,b) 32位饱和减法;_smpy2(a,b) 两个16位饱和乘法;SIMD_dxpnd4 (a)低八位扩展至64位_dcmpeq4 (a, b) 8位打包8bit进行比较,产生8bit运算结果_amem8() 64位对齐数据存取_mem4() 32位非对齐数据存取综合实例也RGB转换为例,输入为24位连续存储的RGB原始数据。
采用定点乘法。
Gray = (R*19595 + G*38469 + B*7472) >> 16。
int rgb_to_y (const uint8_t *restrict pixel_array_rgb,uint8_t* restrict pixel_array_y,uint32_t total_pixel){int i,j=0;int result[4];longlong source,multiolier;multiolier = 0x00001D3096454C8B;#pragma MUST_ITERATE(16,,16)#pragma UNROLL(4);for(i = 0; i < (total_pixel); i = i+ 4){source = _unpkbu4(_mem4_const(&pixel_array_rgb[j]));result[0] = _dotpsu4h(source,multiolier)>> 16;j = j+3;source = _unpkbu4(_mem4_const(&pixel_array_rgb[j]));result[1] = _dotpsu4h(source,multiolier)>> 16;j = j+3;source = _unpkbu4(_mem4_const(&pixel_array_rgb[j]));result[2] = _dotpsu4h(source,multiolier)>> 16;j = j+3;source = _unpkbu4(_mem4_const(&pixel_array_rgb[j]));result[3] = _dotpsu4h(source,multiolier)>> 16;j = j+3;result[0] = _pack2(result[1],result[0]);result[2] = _pack2(result[3],result[2]);_amem4(&pixel_array_y[i]) = _packl4(result[2],result[0]);}return 0;}注意事项1.C66系列支持非对齐数据存储,采用_mem4()类intrinsics。