1 引言
G.723.1.删除组织于1996年推出的低码率语音编码算法标准,也是组织发布的语音压缩标准中码率最低的标准。G.723.1主要用于对语音及其它多媒体声音信号的压缩,目前在一些数字音视频传输、高质量语音压缩等系统中都得到广泛应用。
2 G.723.分析算法的复杂性
将G.723.1移植到TMS320C64xx之后,可以借助TI集成开发工具CCS(Code Composer Studio)的Profile功能评估每个子程序或函数的执行操作量,从而将程序优化集中在对程序性能影响最大的代码上。
通过分析可以看出,在G.723.在编码解码算法中,码本搜索的运算量比较大,比如Find_Best(),Find_Fcbk(),Find_Acbk():另外,在LPC分析和LSP也有运算量大的参数计算,比如Comp_Lpc(),Lsp_Qnt(),Lsp_Svq()。
3 代码的优化
代码优化有两个目的:一是提高执行速度,实现实时;二是尽量不扩大程序体积(Code Size),使其在内存允许的范围内。显然,两者之间存在一定的矛盾。当今超大规模集成电路的发展使RAM资源不再是系统的瓶颈,所以这部分工作的主要任务是如何提高执行速度。代码优化主要集中在代码优化上CCS在环境中进行。优化的原则是充分考虑C64xx处理器超长指令、多个操作单元和深流水线的结构特征,避免过多的读写内存指令和程序转移指令,充分发挥其强大的操作能力。具体方法包括:
3.1优化基本运算集
G.723.1算法程序用定点操作完成浮点操作。为了防止定点操作过程中溢出,许多操作需要饱和判断。因此,该程序专门定义了饱和加法、饱和乘法、除法和移位等基本操作集。这些操作在程序中调用相当频繁CCS的profile工具测试,基本运算函数集的调用占95%以上CPU时间。因此,我们应该从优化基本操作集开始。在熟悉掌握C64xx在指令集的前提下,对基本函数完成的基本操作进行分析C64xx指令集的前提下,分析基本运算集中各个函数完成的功能和对全局变量产生的影响,用C64xx替换或改编指令。它包括对跳转和装配线的优化讨论、乘积的饱和调整的讨论OveRFlow相关操作。
由于基本操作集以函数的形式存在,两次跳转f函数的调用和返回1至关重要,这将导致流水线的两次中断,表现为占用12个指令周期。将基本运算函数集改为宏的形式,即基本运算嵌入(inline)至lJ在调用程序中,该镇消除了跳转和装配线中断带来的指令周期占用,提高了执行速度。虽然这增加了代码长度,占用了更多的内存,但由于基本操作函数体积较小,经过一定的代码优化,程序体积的牺牲几乎被忽略。
基本运算的函数定义BASIC.C如果这些简单的永数可以在文件中内联指令(intrinsic)优化可以事半功倍。内联指令是汇编指令的直接映射,效率高。同时,一个问题是溢出保护位Overflow判断是基本函数中用来识别溢出的全局变量,其作用相当于CSR(Control Status Register)寄存器的SAT(SaturaTIon)当数据溢出时,位,SAT位被系统自动设置为1,所以编解码函数是对的Overflow判断可以转化为对SAT位的判断。引用CSR寄存器需要在一开始就声明extem cregister volaTIle ansigned int CSR。
C64xx饱和乘法指令提供了饱和乘法指令SMPY,实现16"调整16位乘法和饱和结果,实施如下:
if(cond){
if((src 1*src2<<1)!=0x80000000)
dst=((src 1*src2)<<1);
else
dst=0x7ffffff;
}
else
nop;
将原指令中的乘法指令改为SMPY可完成乘法和饱和调整两种计算,以节省饱和调整三个指令。类似于其他饱和操作,C64xx所有这些都提供了相应的实现指令,用饱和运算指令代替普通运算指令,可以节省饱和结果调整部分的运算。
优化3.2主程序
主程序优化方法主要采用以下方法:
(1)使用内联函数(intrinsics)
内联函数可以直接映射C64xx在指令前添加指令的特殊函数"_例如:
#define L_add(L_var1,L_var2) _sadd(L_var1,L_var2)
#define L_mult(var1,vat2) _smpy(var1,var2)
等等,基本函数的内联优化需要熟悉原函数的定义和内联指令。
用内联函数代替相应的C语句是一种非常简单高效的优化方法。C语句中提到的饱和乘法。我们通常使用两个嵌套条件来判断句子来检查结果是否溢出,以及指令int_smpy(int a.int b) 完成乘b操作后,再进行饱和处理。DSP指令可以完成C语言中多个句子的计算,可以节省大量的时钟周期。
(2)循环展开(loop—unrolling)
程序中有许多双重循环和多晕循环(如代数码本搜索计算),因为C64xx优化器,优化器只在最内层循环中形成指令流水(最多可达8级流水),使循环句不能充分利用软件流水线,内部循环次数少,消耗prolog和eplog时钟周期不容忽视。针对这种情况,一种有效的方法是扩展双重或多重循环,减少循环次数。这样,虽然代码长度增加了,但可以参与更多的操作pipeline中。由于流水线排空减少,功能单元利用率提高,程序执行速度将大大提高。
(3)减少分支和调用指令,减少判断指令
程序中的分支、调用和判断指令会导致程序跳转,每个跳转指令有5个延迟间隙。因此,延长了程序执行时间;此外,循环跳转也会阻塞软件流量,降低代码执行效率。在优化中,可以使用嵌入式和合并判断句来减少判断次数或使用逻辑指令来代替判断,以尽可能消除中断装配线指令的影响。
(4)存取和计算使用单词或双词
C64xx系列DSP是32位CPU,当16位数据连续存储在内存中时,可以使用uint_amem4(void*ptr)或double & _amemd8 (void*ptr)读取或存储单词或双字数据的指令。这样,每次可以同时存取2个或4个16位数据,因为从内存执行取数操作需要4个delay,因此,减少访问次数可以节省大量时钟同期;同时,可以使用C64xx指令集中特有的打包指令_pack2(unsigned a,unsigned b),_packh2(unsigned a,unsigned b)将两个16位数打包成一个32位数,用于乘法和计算_add 2(int a,int b)、_mpy2(int a,int b)同时完成两组16位数的加法和乘法,效率是单纯16位数的加法和乘法的两倍。
3.3汇编编程优化
线性汇编是TI提供的汇编语言的指令系统与汇编语言的指令系统完全相同,但编写时不需要指定寄存器和操作单元,也不需要考虑延迟。因此,编写线性汇编相对容易。
经过上述优化,音频编码程序在DM642上的运行状态有了很大的改善,但测试后仍未达到可接受的水平,高级语言的效率几乎发挥到了极致。因此,在分析了耗时的模块特性后,采用线性汇编语言重新编写C代码的低效段程序,逐步提高了程序的执行效率。
为了提高代码执行效率,我们需要遵循以下原则:
(1)编写并行代码:减少循环中的执行周期数,优化线性汇编代码。这里的关键问题是找出指令的相关性,只有不相关的指令才能并行执行。确定指令是否相关。您可以使用相关的图片。
(2)处理跳转指令和转移指令:汇编程序的主要特点之一是频繁跳转。当满足不同条件时,程序需要进行不同的操作或跳到相应的位置。对于大于、大于等于、小于、小于等于等更接近的逻辑判断和处理,应仔细处理,否则会出现逻辑错误,难以调试。当溢出需要相应处理时,这种现象尤为突出。
(3)尽量减少循环体内的指令[7]:G.72.1的许多算法都是在循环中完成的,有些地方就像在定码本搜索过程中使用多个循环来确定四个非0脉冲的位置和范围。在循环中,特别是在嵌套较深的循环中,减少指令可以大大降低程序的操作次数。例如。对于每重循环8次的四重嵌套循环,每减少最内层循环的指令,整个程序可以少执行84次=4096语句。因此在设计程序时,能够放在循环体外执行的语句.尽量放在循环体外执行。
(4)展开程序体:尽量在一定条件下展开程序,减少子程序的调用和返回次数,牺牲空问换取时间。
代码效率明显高于C语言直接编译。
4 优化工作创新点
在对G.723.1的优化。本文以前人的研究成果为基础DSP C64xx系列芯片提}n一些有价值的新方法。这些创新点在语音编解码中提高了代码的优化速度和执行效率DSP在实时实现中起着关键作用。下面,本文将以一些经典的方法为例。
(1)编制连接命令文件。cmd
编明确了系统的程序和数据映射地址后,编序和数据映射地址后,将部分调用次数较多的函数、堆栈段和数据段放入内存:cmd文件内容如下:
一L\evmdm642_echocfg.cmd //连接CCS连接命令文件提供
SECTIONS
{
.tahles>SDRAM
.cinit>ISRAM ////将变量初值表放入内存
. far >SDRAM
.const>ISRAM ////将常数段放入内存
.pinit>SDRAM
. tin >SDRAM
.text>SDRAM
.test >ISRAM
}
一levmdm642_edma_aic23.164 //连接驱动程序的库文件
一lc6xlx_edma_mcasp.J64 //连接串口McASP的库文件
其中.test是笔者在C程序内用#pragma CODE_SECTION或DATA_SECTION自定义的段。
(2)高速缓冲寄存器Cache的使用
Cache即高速缓存,是位于CPU和片内存储器之间的规模小速度快的存储器。Cache的工作原理是保存CPU中最常用的数据。当Cache中保存着CPU要读写的数据时,CPU直接访问Cache。由于Cache的速度与CPU相当,CPU能在零等待状态下迅速地实现数据存取。只有在Cache中不舍有CPU所需的数据时CPU才去访问片内存储器。因此Cache的有效利用对整个程序速度的提高有着举足轻重的作用。在主函数中加入以下代码,使Cache使能:
CACHE_clean (CACHE_L2ALL,0,0}; //清除Cache内原有内容
CACHE_setL2Mode (CACHE_64KCACHE); //设置Cache的大小为64K
CACHE_enableCaching (CACHE_EMIFA_CE00); //Cache使能
添加以上代玛后,测试速度由原来的20帧/s提高到了400帧/s。提高了将近20倍。
5 结束语
本文详缁分绍了G.723.1标准的DSP代码优化工作,重点描述了代码优化的方法和本课题的创新点.对于算法中的一些函数提出了独创性改写方法。基于线性汇编的优化以及Cache的有效利用使本课题的工作取得了显著成果,在没有降低音质的情况下,实现了DSP的语音实时编解码。
本文作者创新点:在对G.723.1的优化中,针对TMS320DM 642 DSP系列芯片提出了一些有价值的新方法。例如:编写连接命令文件.cmd和高速缓冲寄存器Cache的使用。这些创新点在不同程度上提高了代码的优化速度和执行效率,在语音编解码的DSP实时实现中起到了关键性作用。