您的位置:首 页 >> 技术资讯 >> 通信与网络 >> 正文
TMS320C54x数字信号处理器

中采网-电子资讯及技术频道      

    北京宁阳科技发展有限公司
 张霖峰 唐阳

摘要:以G.723.1语音编码算法的优化为例,详细介绍了TMS320C54x DSP的软件优化流程以及具体优化技巧。 
关键词:优化;DSP;G.723.1  
1  引言 
  很多人认为, 处理器仍然按照摩尔定律保持着高速发展, 所以如果对软件效率不满意, 只需选择更快更强大的处理器, 而不需要在针对处理器的软件优化上花费太多精力。 对于某些应用,这样的考虑当然正确, 比如仅仅需要一片DSP来实现某个大系统中的一部分数据处理工作, 而且此系统对于效率以及功耗没有太高要求。 但是,对于很多特定应用, 例如实现信源或信道编码, 由于编解码算法的运算量太大, 如果不经过精心优化,很可能采用最新的DSP仍然无法实现,优化后却可能在单片DSP上实现更多路的编解码算法, 从而降低每路的平均成本。 此外,在消费类电子产品中,例如手机与便携式MP3播放器这类电池供电的系统, 本身对功耗相当敏感,而DSP功耗基本上随着MIPS数的增加而线性增长。 如果对此类系统上运行的软件进行优化, 其工作时间将会大大延长。 
   还有人寄希望于将优化工作全部交给DSP开发工具自带的C编译器, 但
   以笔者多年的工作经验现在的C编译器对大部分软件并不能达到期望的优化效果, 受DSP片上资源少的约束,将来也不可能达到, 除非DSP本身在硬件资源上有较大的突破。 
  本文将以 ITU-T的标准G.723.1语音编解码算法为例, 系统讲述针对TI公司的TMS320C54x芯片的优化流程(参见图1)以及优化技巧。

图1 TMS320C54x DSP的软件优化流程

2   优化方法 
  在使用TI的集成开发环境  Code Composer Studio (CCS)建立工程时,第一步工作是把C源程序由PC平台移植到DSP平台上,保证其运行正确。C54x的数据类型并不完全与ANSI C兼容,它的char型数据为16bit,而不是正常的8bit。如果原始的C程序中有char型数据变量, 需要经过一定处理,转化为short型16bit数据变量。而且,CCS对于fread()、fwrite()等函数支持的并不好, 同样需要进一步处理以满足要求。 在建立工程开始,最好不要使用任何优化编译选项, 以避免产生无法预料的错误。 工程建立并验证正确后, 逐级升高优化编译级别,直到使用-o3选项, 仍能运行正确,就可以开始具体的优化工作了。 如果在此过程中程序出错,必须经过调试确定CCS编译时何处代码产生错误, 并降低这一部分的优化级别, 或对该处C源程序进行结构上的修改, 以避开CCS的错误。 
  G.723.1的 basop.c文件中的基本运算函数采用的是欧洲电信标准协会(ETSI)的标准函数。 通过简单地包含intrindefs.h头文件,不改变C程序,就可以在编译时将basop.c中的大部分基本运算函数用单条汇编指令替代,从而避免频繁的函数调用。 C54x的C编译器同时支持大量的 intrinsic指令, 与相应的汇编指令对应,可以适当地加以应用。 C编译器此外还支持asm(“assembler text”);的格式,在C程序中直接插入汇编指令 (inline形式),  编译器将把双引号中的字符串直接拷贝到编译输出的汇编文件中,但这种做法是相当危险的, 很可能产
   生错误, 并降低程序的可读性。这种格式最好仅仅用于向生成的汇编文件中添加注释。 
  在以上工作结束后,  使用CCS提供的统计工具对编解码算法中的各个模块进行运算量统计,作为下一步工作的依据。对于G.723.1,  会发现运算量主要集中在固定码本搜索与自适应码本搜索部分, 以及大量的滤波运算部分。 此时的优化策略取决于具体的优化目标, 如果最终目标是实现一个效率最优的编解码器, 那么可以按部就班地对所有函数依次优化。 如果目标仅止于片上实时实现, 就应该从效率最低、 运算量最大的块入手进行优化,达到目标即可结束。 而对于运算量很小主要用于控制的函数, 就不需要进行优化。 
  由于C54x本身硬件上的限制,客观上说只有 2个40bit 寄存器可以进行基本运算,所以很难仅在C语言级上进行优化,但这并不意味着优秀的汇编可以解决一切。有时算法本身的优化能够产生惊人的效果。 单纯地将C语言逐行翻译成汇编并不能称之为优化,只算得上是人工的C编译器。 真正的优化需要算法级、C语言级、 汇编语言级配合实现。 
  一般说来,算法为了保持程序可读性,有些部分必然存在着运算量上的冗余。例如,对一个很大的数组进行初始化清零,其实只需要将其中的几个元素清零即可。算法级上的优化需要真正懂得算法原理,具体算法具体分析,没有定式可循。
  在C语言级上,可做的工作很多,比较零碎但很有意义,可以为下一步快速写出优秀的汇编打好基础。G.723.1源程序中的10阶FIR、IIR滤波部分,对每一个样点进行滤波后,都对10个滤波器状态进行更新,这就造成效率的极大降低,可以将状态更新部分移到循环外,在滤波结束后更新一次即可。G.723.1中有许多移位操作,移位的位数是未知变量。C54x的移位操作最多可以左移31位,或右移16位。如果可以确定移位不超过此范围,就不需要在将来写汇编程序时用很多指令进行判断,一条简单的移位指令即可实现。判断方法有两种,一种是基于算法的理论分析,如果移位位数直/间接产生于norm_s()或norm_l()函数,那么很容易分析是否超出范 数,很多情况下永远不会发生溢出,可以用上面两种方法进行分析化简。但是在确定不了的地方,还是要采用最保险
   的方法实现。 算法级和C语言级上做的工作越充分,  下一步汇编工作就越顺利,效率也越高。下面详细讨论汇编语言级的优化。
  同样的C程序, 交给不同的人,会写出不同的汇编,但最有效率的汇编只有确定的一种,如何才能写出最优秀的汇编?  那就需要程序员在写每一个函数,甚至每一条指令的时候,都要保证它是最优的,无可替代的。程序员需要清楚地了解C54x的汇编指令集,指令间的流水线冲突。背熟厚厚一本指令集是不现实的,但至少需要知道有哪几条跳转指令,哪些乘法指令,以及如何高效实现多重循环,等等。在每次进行内存读写时,都要考虑是否可以利用相关的并行指令。至于利用跳转或循环指令的延迟,以及在流水线等待期间插入其他运行指令,是比较常见的优化方法。而优化的关键,在于被频繁调用的多重循环中的最内层循环,例如Find_Best()函数中,最内层循环体内每减少一条指令,  都将使整个算法峰值运算量下降0.288MIPS。 如果这样的程序段优化不好,将会产生灾难性后果。对于最内层循环,如果循环次数很少,且循环体非常简单,可以采用内层循环展开的方式进行优化。 例如频繁出现的10阶FIR或IIR滤波运算, 由于只是单条乘累加指令循环10次,所以将内层循环完全展开并未增加多少代码长度,却能够有很好的优化效果。以Synt()函数为例,经过算法以及C语言级的优化,C程序主体已经优化为:
for ( i = 0 ; i < SubFrLen ; i ++ ) 

Acc0 = ((Word32)Dpnt[i]) << 13 ; 
for ( j = 0 ; j < LpcOrder ; j ++ ) 
Acc0 = L_mac( Acc0, Lpc[j], Spnt[i-1-j] ) ; 
Acc0 = L_shl ( Acc0, 2 ) ; 
Spnt[i] = round( Acc0 ) ; 

循环体对应的汇编程序如下: 
; loop starts 
LD *AR_Dpnt+, 13, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +, *AR_Spnt_j-, A 
MAC *AR_Lpc +0%, *AR_Spnt_j-, A SFTA A, 2 
RND A 
MVMM AR_Spnt, AR_Spnt_j 
STH A, *AR_Spnt+ 
; loop ends 
  程序中AR寄存器采用助记名称表示以增加可读性.10次乘累加已全部展开,以减少循环控制语句消耗的运算量。BK
   设置为0,AR0设置为-9,当运行到最后一条MAC指令时,*ARx+0%模式的循环寻址方式使 Lpc系数指针自动回复到起始地址, 否则,至少需要2周期的指令对其进行指针调整。最终计算每点的10阶IIR滤波仅需要15个周期。 
  G.723.1 的程序中有许多的搜索运算。如果对C54x的指令集不熟悉,很难找到较好的解决办法,笔者也是在完成了大部分程序后才发现C54x提供的条件存储指令有很好的效果,并以此改写了已经编好的很多汇编程序。
以Find_Best()函数中一段程序为例: 
Acc2 = (Word32) 0 ; 
for ( i = 0 ; i < SubFrLen/2 ; i ++ ) 

Acc0 = L_abs( ErrBlk[i] ) 
if ( Acc0 >= Acc2 ) 

Acc2 = Acc0 ; 
indx = (Word16) i 


循环体对应的汇编程序如下: 
  STM #(SubFrLen/2-1), BRC 
  RPTB Label - 1 
  loop starts 
  SUB A, B 
  SRCCD *AR_indx, BEQ 
  DLD *AR_ErrBlk+, B 
  ABS B 
  MAX A 
 Label:loop ends 
   由于块循环计数器BRC每次循环都进行递减, 所以可以起到C程序中计数器i的作用。使用SRCCD条件存储指令即可将BRC值存到Xmem中。在循环结束后,经过一定处理,就可以方便地得到要求的indx值。 
    在一开始学习优化时写的汇编程序,有经验后就会发现效率很低,甚至今天写的程序,明天就会发现存在很多不足。所以程序写完并调试通过并不等于工作完成,回过头来细细检查一定会有收获,提高优化质量的同时也能迅速提高优化技能。 
6  优化效果 
  经过由算法级到汇编语言级的优化,G.723.1的6.3kb/s速率编解码器,包括VAD、高通滤波、 后滤波在内的峰值运算量为15.4MIPS, 并通过了ITU-T的所有测试序列。笔者所了解的最优运算量是16.9MIPS,  而程序代码大小相
   当。 这样我们就实现了可以在100MIPS运算能力的 C54x  上运行6路6.3kb/s G.723.1编解码算法的方案。 在效率改善中,高质量的汇编所起的作用仅占到约50%,其它是算法级和C语言级的作用.如果希望达到最好的优化效果,不要在优化工程一开始就写汇编,而要认真地进行算法级和C语言级的优化, 并贯穿始终,才能起到事半功倍的效果。限于篇幅,无法对其他优化技巧一一列举,希望通过本文, 表达一种优化思想-Thinking in DSP。
参考文献: 
1. International Telecommunication Union: 'Dual rate speech coder for multimedia communications transmitting at 5.3 and 6.3 kbit/s', ITU-T Recommendation G.723.1. 
2. Texas Instruments: TMS320C54x DSP Datasheets.

来源:
  相关文章链接
关于中采网成长历程广告服务版权及商标法律声明隐私申明客户反馈工作机会网站建设网络推广手机网站 商业域名友情链接网站地图

常年法律顾问于波律师著作权与商标声明隐私申明法律声明电子词典互动问答网上黄页网址大全

本频道所有文章或图片的版权和著作权均归作者本人所有,如有疑问请电邮至:sz#cnebuyer.com
Copyright©2000- CNeBuyer.com All Rights Reserved 中采网 版权所有 ICP备09029428号

中国互联网不良信息举报中心

中国互联网网络垃圾举报中心

做文明网,传播文明

深圳市网络警察在线报警平台入口