C66x DSP是TI最新出的定点和浮点混合DSP,后向兼容C64x+和C67x+、C674x系列DSP。本文介绍了基于C66x架构的常用优化技巧,首先介绍C66x相对于C64x+定点DSP的浮点和定点处理能力的增强,以及C66x新引入的128-bit的数据类型。接下来说明c66x特有的特性和相关的优化技术,重点在其浮点增强以及对复数运算和矩阵、向量运算的intrinsics选择,最后是如何解决寄存器不足、SIMD move的使用平衡寄存器和功能单元的分配以及解决寄存器生命周期过长的问题的高级优化技巧。本文中的编译结果基于CCSv4.1中的CGTools v7.2编译器,编译选项–o3 –s –mw –mv6600
C66x DSP简介
C66x DSP是TI最新出的定点和浮点混合DSP,后向兼容C64x+和C67x+、C674x系列DSP。最高主频到1.25GHz,RSA指令集扩展。每个核有32KB的L1P和32KB的L1D,512KB到1MB L2存储区,2MB~4MB的多核共享存储区MSM,多核共享存储控制器MSMC能有效的管理核间内存和数据一致性。针对通信应用,其片内集成了2个TCP3d Turbo码字译码器,一个TCP3e Turbo码编码器,2个FFT/IFFT,DFT/IDFT协处理器以及4个VCP2 Viterbi译码器。高速互联总线,4个串行RapidIO接口,千兆网口、EMIF-DDR3内存控制器。TeraNet Switch用于片内和外设间的快速交互
C66x DSP的架构和指令增强
TMS320C66x ISA架构是对TMS320C674x DSP的增强,也是基于增强VLIW架构的,具有8个功能单元(2个乘法器,6个ALU算术运算单元),该架构的基本增强如下:
4倍的乘累加能力, 每个周期32个 (16x16-bit)或者8个单精度浮点乘法;
浮点运算的增强:优化了将TMS320C67x +和TMS320C64x+ DSP 结合的TMS320C674x DSP,原生支持IEEE 754单精度和双精度浮点运算,包括所有的浮点操作,加减乘除;浮点运算的SIMD支持以及单精度复数乘法,附加的灵活性,如在.L和.S单元完成INT到单精度SP的相互转换
浮点和定点向量处理能力的增强: TMS320C64x+/C674x DSPs支持2-way的16-bit数据SIMD或者4-way的8-bit,C66x增加了SIMD的宽度,增加了128-bit的向量运算。如QMPY32能做2个包含4x32-bit向量的乘法。另外SIMD的处理能力也得到增强;
复数和矩阵运算的引入和增强:针对通信信号处理中的常用复数算术函数和如矩阵运算的线性算法的应用,如单周期可以完成两个[1×2]复数向量和[2×2]的矩阵乘法
图2. QMPY32的向量操作
图2. C64x+/C674x/C66x ISA定点和浮点处理能力对比
C66x有更强的SIMD处理能力,进一步的优化可以考虑浮点乘法、数据加载等。如数据加载采用_amem8(addr)来加载8字节对齐的整型数据,_amemd8(addr) 来加载8字节对齐的浮点数据。因而定义如下的复数数据结构,就能用_amemd8(addr)一次加载一个复数的实部和虚部了,注意一下定义同时考虑了大小端,保证加载的高4字节是虚步,低4字节是实部。
#ifdef _LITTLE_ENDIAN
typedef struct _CPLXF
{
float imag;
float real;
} cplxf_t;
#else
typedef struct _CPLXF
{
float real;
float imag;
} cplxf_t;
#endif
对于加载的寄存器对的数据,可以采用_hif(src)来得到实部,用_lof(src)来得到虚部,类似于C64x+中的_hill(src) 和 _loll(src)。组成一个寄存器对,可以采用类似_itoll(srcq, src2) 的_fod(src1, scr2).
C66x处理器除了提供C674x+ DSP已经包含的MPYSP (SPxSP->SP), MPYDP (DPxDP->DP), MPYSPDP(SPxDP->DP), 以及MPYSP2DP (SPxSP->DP)外,还有新的DMPYSP以及CMPYSP和QMPYSP指令。
DMPYSP:浮点的C = A * B for i=0 to 1
CMPYSP: 用于浮点数据的复数乘法,结果为128-bit格式
C3 = A[1] * B[1]
C2 = A[1] * B[0]
C1 = -A[0] * B[0]
<span style="font-style: italic;"><span style="font-style: normal;"> </span><span style="font-style: italic;"><span style="font-style: normal;">C0 = A[0] * B[1]</span></span></span>
为得到复数的实部和虚部,定义128-bit的数据C:
__x128_t C_128;
C_128 = _cmpysp(A, B);
C = _daddsp(_hid128(C_128), _lod128(C_128)),直接得到C3+C1 和 C2+C0。
或者使用
intrinsics _complex_mpysp():
C=_complex_mpysp(A, B)
得到A和B的共轭的乘积,考虑如下步骤:
__x128_t C_128;
C_128 = _cmpysp(B, A);
C3 = B[1] * A[1]
C2 = B[1] * A[0]
C1 = -B[0] * A[0]
C0 = B[0] * A[1]
C = _dsubsp(_hid128(C_128), _lod128(C_128))
直接得到C3-C1 和 C2-C0;
或者采用简单的
intrinsics _complex_conjugate_mpysp():
C=_complex_conjugate_mpysp(A, B)
<span style="font-style: italic;"><span style="font-style: normal;">QMPYSP: C = A * B</span><span style="font-style: italic;"><span style="font-style: normal;"> for i=0 to 3.</span></span></span>
使用SIMD修改的程序如下
<span style="font-style: normal;">_nassert(n % 4 == 0);
_nassert((int) a % 8 == 0);
_nassert((int) ejalpha % 8 == 0);
_nassert((int) abs_a % 8 == 0);
#pragma MUST_ITERATE(4,100, 4);
for ( i = 0; i < n; i++)
{
</span>dtemp =_amemd8(&a<span style="font-style: italic;"><span style="font-style: normal;">);
/* using SIMD CMPYSP with conjugation for power calculation */
a_sqr =_hif(_complex_conjugate_mpysp(dtemp, dtemp));
/* or use the following */
/* dtemp2 = _dmpysp(dtemp, dtemp); */
/* a_sqr = _hif(dtemp2) + _lof(dtemp2); */
oneOverAbs_a = _rsqrsp(a_sqr); /* 1/sqrt() instruction 8-bit mantissa precision*/
/* 1st interpolation*/
oneOverAbs_a = oneOverAbs_a * (1.5f - (a_sqr/2.f)* oneOverAbs_a*oneOverAbs_a);
abs_a</span><span style="font-style: italic;"><span style="font-style: normal;"> =a_sqr * oneOverAbs_a;
dtemp1 =_ftod(oneOverAbs_a, oneOverAbs_a);
/* using SIMD DMPYSP for the following operations */
/* ejalpha</span><span style="font-style: italic;"><span style="font-style: normal;">.real = a</span><span style="font-style: italic;"><span style="font-style: normal;">.real * oneOverAbs_a;*/
/* ejalpha</span><span style="font-style: italic;"><span style="font-style: normal;">.imag = a</span><span style="font-style: italic;"><span style="font-style: normal;">.imag * oneOverAbs_a;*/
_amemd8(&ejalpha</span><span style="font-style: italic;"><span style="font-style: normal;">) = _dmpysp(dtemp, dtemp1);
}</span></span></span></span></span></span></span></span>
_complex_conjugate_mpysp(a, a)计算能量,只保存32 MSB到寄存器,还可以通过DMPYSP(a, a) 和_hif() + _lof()来计算能量。
得到的结果是需要419个周期。
一周热门 更多>