TMS320C62XDSP的混合编程研究
(1)TMS320C62X指令的执行可以用延迟间隙来说明。延迟间隙在数量上等于从指令的源操作数被读取到执行的结果可以被访问所用的指令周期。如对于乘法指令(MPY),源操作数从第i个周期被读取,则其计算结果在第(i+2)个周期才可用。
(2)使用相同功能单元的两条指令不能被安排为并行指令。
(3)使用同一条交叉通路的两条指令不能被安排在同一个执行指令包中,这是因为从寄存器组A~B或者从B~A都只有一条交叉通路。
4将数据读入到(或存储自)相同寄存器组的两条读(写)指令不能被安排在同一个执行包中。
5每一个执行包里只能允许每一寄存器组处理一个长定点类型数据。
6在一个指令周期内对同一寄存器读取多于四次是不允许的,但条件寄存器不在此限制之列。在一个指令周期内,不能同时存在两条写入同一寄存器的指令,只有在写操作不是在同一个指令周期发生时,才可以将具有同一目的地址的两条指令安排并行。
3 基于TMS320C62X的运动补偿的混合编程设计实例
运动补偿是MPEG-4标准中的一种重要算法。运动补偿是指根据运动矢量在参考帧中找出参考块。如果运动矢量的X分量和Y分量都是整象素长度,则直接在参考帧中找出参考块。如果为半象素长度,则需要通过内插运算计算出参考块,计算出的参考块需要加上解码得出的误差块才能得到当前参考块。本文给出了运动矢量的X分量和Y分量都是整象素长度时的运动补偿方法。根据运动矢量可直接在参考帧中找到参考块(8×8)。完成此功能的C语言函数如下:
void mc_case_a2unsigned char pSrc short SrcOffset short SrcWidth unsigned char pDst short RoundCtrl
……
for i=0 i<8 i++
tmp_P_Dst+i = tmp_P_Src+i
......
}
}
参数运动矢量SrcOffset对4(4个字节为一个字,长32位)的余数可能是0、1、2、3。当余数是0的时候,编译后执行代码是按字读取(LDW)的,这充分体现了TMS320C62X的优点,也使程序的运行效率比较高。而当余数不为0的时候,则可能是按字节读取(LDB)或是按半字读取(LDH),这使程序的运行效率较低。视频的编码和解码都要用到运动补偿来重构图像,这是一个很费时的操作,而且其代码也是图像处理中的核心代码,这样就要求编写高效的程序来完成此操作。为了使代码的运行效率更高,且结合TMS320C62X的硬件特点,希望对于不同的运动矢量,做运动补偿的时候都能采用按字读取和存储的方式。这需要对运动矢量参数除以4,根据余数调整指针,使指针始终指向字对齐方式而在C程序中当前块是char型的以字节方式存储的,对其进行移位处理只能是一个字节一个字节地进行移位,这就使得在C程序中不能用和汇编程序同样的方法来对程序进行优化,如运动矢量除以4以后的余数为1,为了使要取的8个象素对准字访问方式,则要按图1进行操作。
javascript:window.open(this.src);" style="cursor:pointer;"/>
根据运动矢量参数进行移位使其对准字访问的核心代码的程序为:
MVK .S2 0xFFFCtemp ;获得地址的LSB位
ADD .L1X pSrcoffsetpSrc ;参考块第一个元素的
地址
AND .L2X pSrctemptmp_pSrc ;字对准访问的地址
AND .S1 0x0003pSrcrshiftA ;用两个LSB位得
;到了需右移几个字
SUB .L1 0x04rshiftAlshiftA ;需左移几个字
MPY .M1 rshiftA8rshiftA ;需右移的#bit数
MPY .M1 lshiftA8lshiftA ;需左移的#bit数
作为一个说明C语言与汇编程序混合编程的设计例子,采用并行汇编实现了这个函数的优化。这里只给出部分汇编程序:
.text ;将该段汇编代码安排在.text
段,当然通过在C语言中用
#program_section也可以将其安排
在其它自己命名的段中。
.global mc_case_a ;函数名,用.def或.gloal对其进行
声明,使得C代码调用该函数
_mc_case_a ;标号,是C调用函数和汇编
被调用函数的接口处
……
.asg B10,ocsr
.asg B11,rw_4
STW .D2 ocsr,stack--1 ;被调用函数用到了
B10~B15,A10
STW .D2 r_w4,stack--1 ;~A15的寄存器,则
需对它们保护
MVC .S2 CSR,ocsr
AND .S2 -2,ocsr,ocsr
MVC .S2 ocsr,CSR ;关闭某些中断 ……
loop
LDW .D2 tmp_pSrc++src_width1,r_w1
;读取第一个字
LDW .D1 pSrc++1,r-w2 ;读取第二个字
LDW .D1 pSrc++src_width2,r-w3 ;读取第三个字 SHRU .S2 r_w1,rshiftB, r-w1
SHL .S1 r_w3,lshiftA, r_w3
SHL .S2X r_w2,rshiftB,r_w4
SHRU .S1 r_w2,rshiftA, r_w2
OR .L2 r_w1,r_w4, r_w1
OR .L1 r_w1,r_w3,r_w2 ;这几步作了图a
中的操作过程
STW .D2 r_w1,pDst++2
STW .D1 r_w2,tmpDst++2 ;存储取得的两
个字
B .S2 loop ;延迟跳转到标号
loop处,实现循环 ……
LDW .D2T2 ++stack1,r_w4
LDW .D2T2 ++stack1,ocsr ;对被调用函数
中自己保护的寄
存器作恢复处理
MVC .S2 ocsr CSR ;恢复中断环境
B .S2 B3 ;返回到调用函数处
……
在TI CCS上用其库函数CLOCK()对这个算法的C语言程序和并行汇编程序分别进行了性能测试。在纯C语言中,运动矢量对4的偏移量的余数为0 时约为33个指令周期 余数为1时约为93个指令周期 余数为2 时约为 51个指令周期余数为3 时约为 93个指令周期平均约耗时 67个周期。而将其用并行汇编代码编写其周期数恒定为33个指令周期。33个指令周期的执行时间,对于这个函数基本上是达到了函数的最大优化。
由此可见,程序的核心算法的代码用并行汇编程序编写,而主体的C语言程序则以函数调用的形式调用这些核心算法的并行汇编函数,是提高程序代码执行效率的一种有效方法。