在C++中使用内联汇编的乘加指令

9

我正在ARM9处理器上实现FIR滤波器,并尝试使用SMLAL指令。

最初,我已经实现了以下滤波器,它工作得非常完美,但这种方法使用的处理能力太大,不能在我们的应用程序中使用。

uint32_t DDPDataAcq::filterSample_8k(uint32_t sample)
 {
    // This routine is based on the fir_double_z routine outline by Grant R Griffin
    // - www.dspguru.com/sw/opendsp/alglib.htm 
    int i = 0; 
    int64_t accum = 0; 
    const int32_t *p_h = hCoeff_8K; 
    const int32_t *p_z = zOut_8K + filterState_8K;


    /* Cast the sample to a signed 32 bit int 
     * We need to preserve the signdness of the number, so if the 24 bit
     * sample is negative we need to move the sign bit up to the MSB and pad the number
     * with 1's to preserve 2's compliment. 
     */
    int32_t s = sample; 
    if (s & 0x800000)
        s |= ~0xffffff;

    // store input sample at the beginning of the delay line as well as ntaps more
    zOut_8K[filterState_8K] = zOut_8K[filterState_8K+NTAPS_8K] = s;

    for (i =0; i<NTAPS_8K; ++i)
    {
        accum += (int64_t)(*p_h++) * (int64_t)(*p_z++);
    }

    //convert the 64 bit accumulator back down to 32 bits
    int32_t a = (int32_t)(accum >> 9);


    // decrement state, wrapping if below zero
    if ( --filterState_8K < 0 )
        filterState_8K += NTAPS_8K;

    return a; 
} 

我一直在尝试使用内联汇编来替换乘加指令,因为即使开启了优化,GCC也没有使用MAC指令。我用以下代码替换了for循环:

uint32_t accum_low = 0; 
int32_t accum_high = 0; 

for (i =0; i<NTAPS_4K; ++i)
{
    __asm__ __volatile__("smlal %0,%1,%2,%3;"
        :"+r"(accum_low),"+r"(accum_high)
        :"r"(*p_h++),"r"(*p_z++)); 
} 

accum = (int64_t)accum_high << 32 | (accum_low); 

使用SMLAL指令得到的输出结果并不是我期望的过滤数据。我一直得到随机值,似乎与原始信号或我期望的数据没有任何模式或连接。

我有一种感觉,在将64位累加器拆分为高位和低位寄存器以进行指令操作时,我做错了什么,或者我重新组合它们时出现了问题。无论哪种情况,我不确定为什么通过用内联汇编替换C代码后无法获得正确的输出。


你为什么不直接使用DSP库呢? - Hans Passant
4
你使用的是哪个编译器版本?我尝试使用GCC 4.4.3编译了你的纯C代码,并使用选项-O3 -march=armv5te,它生成了smlal指令。 - Nils Pipenbrinck
你已经将迭代次数从“NTAPS_8K”更改为“NTAPS_4K”。 - Mike Seymour
2
@Nils:把你的评论变成一个答案吧 :) - Merlyn Morgan-Graham
1
看起来你对大多数求和的产品不会在每次调用时进行更改。如果你保持一个运行总和,你可以使用适当的增量每次更新总和,那么你就不需要汇编语言。但当然我可能读错了。 - Ian
显示剩余2条评论
1个回答

3
你使用的是哪个编译器版本?我尝试将你的C代码使用GCC 4.4.3编译,使用选项 -O3 -march=armv5te,生成了smlal指令。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接