Я использую FIR-фильтр на процессоре ARM9 и пытаюсь использовать инструкцию 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 на встроенную сборку.