⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c6000优化经验.txt

📁 dsp开发过程中必备的参考资料,内有常见开发经常遇到问题的说明及应注意的问题
💻 TXT
📖 第 1 页 / 共 3 页
字号:

    j2 = *bitnop++; 

    j3 = *bitnop++; 

    j4 = *bitnop++; 

    _nassert(loop[mode]>=35); 

    for (i = 0; i < loop[mode]; i++) 

    { 

        value = value*2 + *bitsp++; 

        j--; 

        if (j == 0) 

        { 

           *prm++ = value; 

           value = 0; 

           j  = j1; 

           j1 = j2; 

           j2 = j3; 

           j3 = j4; 

           j4 = *bitnop++; 

        } 

    } 

  

3、优化说明 

    源程序按照数据位流定义取出参数,为双重循环结构,优化中采用重新根据位流的 

bit长度定义循环次数,化简为单重循环,然后优化循环,去除boundary,使pipel 

ine的数目最小。 

  

十一、copy程序的优化 

    1、源代码: 

    Word16 i; 

    for (i = 0; i < L; i++) 

    { 

        y = x; 

    } 

  

    2、改编代码: 

(1)要求数组长度能被2整除 

    Word32  i; 

    Word32      temp; 

    int *p1 = (int *)&x[0]; 

    int *q1 = (int *)&y[0]; 

    for (i = 0; i < L/2; i++) 

    { 

        temp = *p1++; 

        *q1++ = temp; 

    } 

(2)要求数组长度能被4整除 

    Word32  i; 

    Word32      temp1, temp2; 

    Word32  *pin1, *pin2, *pout1, *pout2; 

    pin1 = (Word32 *)&x[0]; 

    pin2 = (Word32 *)&x[2]; 

    pout1= (Word32 *)&y[0]; 

    pout2= (Word32 *)&y[2]; 

    for (i = 0; i < L/4; i++) 

    { 

        temp1 = *pin1; 

        temp2 = *pin2; 

        pin1+=2; 

        pin2+=2; 

        *pout1= temp1; 

        *pout2= temp2; 

        pout1+=2; 

        pout2+=2; 

    } 

  

3、优化方法说明: 

把一次循  拷贝一个word16的数改为一次循环拷贝2个word16或4个word16的数。 

  

4、技巧: 

充分利用c6xx一次读取32位数的特性,并利用一个指令周期能读取两个数据的特点。 

  

十二、set_zero程序的优化 

    1、源代码: 

    Word16 i; 

    for (i = 0; i < L; i++) 

    { 

        x = 0; 

   } 

  

    2、改编代码: 

(1)数组长度能被2整除 

    Word32 i; 

    int *x1 = (int *)&x[0]; 

    for (i = 0; i < L/2; i++) 

    { 

        *x1++ = 0; 

    } 

(2)数组长度能被4整除 

    Word32 i; 

    int *x1 = (int *)&x[0]; 

    int *x2 = (int *)&x[2]; 

    for (i = 0; i < L/4; i++) 

    { 

        *x1 = 0; 

        *x2 = 0; 

        x1++; 

        x2++; 

        x1++; 

        x2++; 

    } 

  

3、优化方法说明: 

把一次循环为一个word16的数赋值改为一次为2个或4个word16的数赋值。 

  

4、技巧: 

充分利用C6XX一次读取32位数的特点,并利用一个指令周期能读取两个数据的特点。 

  

十三、32bit数与16bit数相乘 

1、源代码: 

L_tmp0 = Mac_32_16(L_32, hi1, lo1, lo2); 

  

2、改编代码: 

L_tmp0=_sadd(_sadd(_smpyhl(hl32, lo2), 

    (_mpyus(hl32, lo2)>>16)<<1), L_32); 

  

3、优化方法说明: 

    hl32是32bit的数,hi1和lo1是16bit的数,且 hl32 = hi 1<<16 + lo1 << 1 ,即 

hi1和lo1分别是hl32的高16位数和低16位数。 

    函数Mac_32_16(L_32, hi1, lo1, lo2)实现 

        L_32 = L_32 + (hi1*lo2)<<1 + ((lo1*lo2)>>15)<<1 

    源代码是把一个32位的数拆成两个16位的数与一个16位的数相乘,优化后的代码不 

拆开32位的数,直接用32位的数与16位的数相乘。运用这种方法必须保证hl32的最 

低一位数必须为0,否则应用指令_clr(hl32, 0, 0)把最低位清零。 

  

4、技巧: 

    源代码中的低16位数lo1是hl32的低16位右移一位得到的(留出一位符号位)。在 

与lo2相乘时又右移了15位,所以在改编代码中右移16位,并且是以无符号数与lo2 

相乘。 

  

十四、32bit数与32bit数相乘 

1、源代码: 

           L_tmp = Mac_32   (L_32, hi1, lo1, hi2, lo2); 

  

2、改编代码: 

    L_tmp = _sadd(_sadd(_smpyh(hl1_32, hl2_32), 

            ((_mpyhslu(hl1_32, hl2_32)>>16)<<1)+ 

            ((_mpyhslu(hl2_32, hl1_32)>>16)<<1)), L_32); 

  

3、优化方法说明: 

    两个32位的数相乘,不必分成四个16位的数相乘,直接用32位相乘。其中: 

        hl1_32 = hi1<<16 + lo1<<1,       hl2_32 = hi2 <<16 + lo2 <<1 。 

源代码实现: L_32 = L_32 + (hi1*hi2)<<1 + ( (hi1*lo2)>>15 + (lo1*hi2)>>15) 

<<1 

  

4、技巧: 

低16位与高16位相乘时,低16位使用的是无符号数。 

  

十五、16位除法的优化 

1、源代码: 

Word16 div_s (Word16 var1, Word16 var2) //实现  var1/var2 

{ 

    Word16 var_out = 0; 

    Word16 iteration; 

    Word32 L_num = (Word32)var1; 

    Word32 L_denom = (Word32)var2; 

            for (iteration = 0; iteration < 15; iteration++) 

            { 

                var_out <<= 1; 

                L_num <<= 1; 

                if (L_num >= L_denom) 

                { 

                    L_num = L_sub (L_num, L_denom); 

                    var_out = add (var_out, 1); 

                } 

            } 

    return (var_out); 

} 

  

2、改编代码: 

Word16 div_s1 (Word16 var1, Word16 var2) 

{ 

    Word32 var1int; 

    Word32 var2int; 

    var1int = var1 << 16; 

    var2int = var2 << 15; 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    var1int = _subc(var1int,var2int); 

    return (var1int & 0xffff); 

} 

  

3、优化方法说明: 

实现16位的除法,要求被除数var1和除数var2都是整数,且var1<=var2。利用C6XX 

特有的指令subc,实现除法的循环移位相减操作。 

  

4、技巧: 

把被除数和除数都转换成32位数来操作,返回时取低16位数。 

  

十六、C6X优化inline举例: 

1、原程序: 

    for (i = LO_CHAN; i <= HI_CHAN; i++) 

    { 

        norm_shift = norm_l(st->ch_noise); 

        Ltmp = L_shl(st->ch_noise, norm_shift); 

        norm_shift1 = norm_l(st->ch_enrg); 

        Ltmp3 = L_shl1(st->ch_enrg, norm_shift1 - 1); 

        Ltmp2 = L_divide(Ltmp3, Ltmp); 

        Ltmp2 = L_shr(Ltmp2, 27 - 1 + norm_shift1 - norm_shift); 

                    // * scaled as 27,4 * 

        if (Ltmp2 == 0) 

            Ltmp2 = 1; 

        Ltmp1 = fnLog10(Ltmp2); 

        Ltmp3 = L_add(Ltmp1, LOG_OFFSET - 80807124); 

                    // * --ound(log10(2^4)*2^26 * 

        Ltmp2 = L_mult(TEN_S5_10, extract_h(Ltmp3)); 

        if (Ltmp2 < 0) 

            Ltmp2 = 0; 

        // * 0.1875 scaled as 10,21 * 

        Ltmp1 = L_add(Ltmp2, CONST_0_1875_S10_21); 

        // * tmp / 0.375  2.667 scaled as 5,10, Ltmp is scaled 15,16 * 

        Ltmp = L_mult(extract_h(Ltmp1), CONST_2_667_S5_10); 

        ch_snr = extract_h(Ltmp); 

    } 

    */ 

  

2、优化后程序: 

    //因循环体太大,拆成两个循环并把相应的函数内嵌以使程序能pipeline, 

    //用L_div_tmp[]保存因拆分而产生的中间变量。 

    for (i = LO_CHAN; i <= HI_CHAN; i++) 

    { 

        //norm_shift = norm_l(st->ch_noise); 

        norm_shift = _norm(st->ch_noise); 

        Ltmp = _sshl(st->ch_noise, norm_shift); 

        //norm_shift1 = norm_l(st->ch_enrg); 

        norm_shift1 = _norm(st->ch_enrg); 

        //Ltmp3 = L_shl1(st->ch_enrg, norm_shift1 - 1); 

        LLtmp1 = st->ch_enrg; 

        LLtmp1 = LLtmp1 << (norm_shift1 + 7); 

        Ltmp3 = (Word32)(LLtmp1 >> 8); 

        Ltmp2 = IL_divide(Ltmp3, Ltmp); 

        //Ltmp2 = L_shr(Ltmp2, 27 - 1 + norm_shift1 - norm_shift); 

        Ltmp2 = (Ltmp2 >> (27 - 1 + norm_shift1 - norm_shift)); 

        if (Ltmp2 == 0) 

            Ltmp2 = 1; 

        L_div_tmp = Ltmp2; 

    } 

    for (i = LO_CHAN; i <= HI_CHAN; i++) 

    { 

        Ltmp2 = L_div_tmp; 

        Ltmp1 = IfnLog10(Ltmp2); 

        //Ltmp3 = L_add(Ltmp1, LOG_OFFSET - 80807124); 

        Ltmp3 = _sadd(Ltmp1, LOG_OFFSET - 80807124); 

        //Ltmp2 = L_mult(TEN_S5_10, extract_h(Ltmp3)); 

        Ltmp2 = _smpy(TEN_S5_10, (Ltmp3 >> 16)); 

        if (Ltmp2 < 0) 

            Ltmp2 = 0; 

  

        Ltmp1 = _sadd(Ltmp2, CONST_0_1875_S10_21); 

  

        //Ltmp = L_mult(extract_h(Ltmp1), CONST_2_667_S5_10); 

        Ltmp = _smpy((Ltmp1 >> 16), CONST_2_667_S5_10); 

        //ch_snr = extract_h(Ltmp); 

        ch_snr = (Ltmp >> 16); 

    } 

  

3、优化说明 

    观察上面这个循环,循环体本身比较大,且含有两个函数L_divide()和 

    fnLog10(),而C62内部只有32个寄存器,且有些寄存器是系统用的,如B14、B1 

5这样循环体太大将会导致寄存器不够分配,从而导致系统编译器无法实现循环的p 

ipeline。 

  

    为了实现循环的pipeline。我们需要把循环体进行拆分,拆分时要考虑以下几点: 

  

    (1)、拆分成几个循环比较合适?在各个循环能pipeline的前提下,拆开的循环 

个数越少越好。这就要求尽可能让各个循环的运算量接近。 

    (2)考虑在什么地方把程序拆开比较合适?循环体里的数据流往往并不是单一的 

,在拆开的断点处势必要用中间变量保存上次的循环运算结果,供以后的循环用。 

适当的拆开循环体,使所需的中间变量越少越好。 

    (3)循环体中的函数调用必须定义成内嵌形式,含有函数调用的循环系统是无法 

使之pipeline的;各个循环体中的判断分支机构不可太多,否则系统也无法使之pi 

peline,为此应近可能把可以确定下来的分支确定下来,并尽可能用内嵌指令。 

  



    针对上面这个例子,考虑: 

    (1)为让各个循环的运算量大致相当,应把L_divide()和fnLog10()分到两个 

循环中去,从循环体大小上考虑,估计拆成两个循环比较合适。 

    (2)考虑在什么地方把程序拆开比较合适?在 

        if (Ltmp2 == 0) 

            Ltmp2 = 1; 

后拆开,因为后面用到的数据只有Ltmp2,故只需用一个数组保存每次循环的Ltmp2 

值即可。 

    (3)循环体中的两处函数调用L_divide()和fnLog10()都定义了其内嵌形式, 

IL_divide()和IfnLog10()。当把可以确定下来的分支作确定处理,并尽可能用 

内嵌指令后,该循环体中所剩的分支结构已很少,循环体可以pipeline。优化前程 

序用2676 cycle,优化后用400 cycle。优化后两个子循环的MII分别为14和6cycle 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -