Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование inline assembler в ARM GCC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ek74
Возникла проблема при использовании inline assembler в ARM GCC. Есть следующий работающий код:
Код
typedef signed long        fr32;
typedef signed long long fx64;

fr32 fr32_mul(fr32 arg1, fr32 arg2)
{
  fr32 result;
  asm
  (
    "smull ip, r3, %1, %2    \n"
    "mov  ip, ip, lsr #%a3    \n"
    "orr    %0, ip, r3, lsl #2    \n"
    : "=r" (result)
    : "r" (arg1), "r" (arg2), "I" (FR32_FRACTION_BITS)
    : "r3", "ip"
    );
  return result;
}

В нём аргумены и результат ("=r" (result), "r" (arg1), "r" (arg2)) 32-битные, а как описать 64-битные данные непонятно?
Код
fx64 fx64_mul(fx64 arg1, fx64 arg2)
{
  fx64 result;
  asm
  (
...
    : "=r" (result)        // <- Какие модификатор тут должны быть ?
    : "r" (arg1), "r" (arg2)    // <- Какие модификатор тут должны быть ?
  );
return result;
}

Есть, конечно, вариант реализовать аргументы и результат через объединение:
Код
union
{
  fx64 value;
  struct
  {
    signed long msw;
    unsigned long lsw;
  } words;
};

Но может, есть способ проще?

К слову сказать для msp430 gcc существуют модификаторы:
Код
• %A[tag] acts as %[tag] for a register or address constant operand, or wraps an integer value as #llo(). #llo is an
assembler macro, which extracts the lower 16 bits of the value.
• %B[tag] adds 1 to a register number, or 2 to an address constant, or substitutes #lhi() for an integer constant.
• %C[tag] adds 2 to a register number, or 4 to an address constant, or substitutes #hlo() for an integer constant.
• %D[tag] adds 3 to a register number, 6 to an address constant, or substitutes #hhi() for an integer constant.

#define LONGVAL 0x12345678l
{
  long a, b;
...
  asm("mov %A2, %A0 \n\t"
         "mov %B2, %B0 \n\t"
         "mov %A2, %A1 \n\t"
         "mov %B2, %B1 \n\t"
         : "=r"((long)a), "=m"((long)b)
         : "i"((long)LONGVAL) );
...
}

А вот для arm gcc, я что-то подобного не нашёл.
amw
На сколько я знаю, для ARM такого нет.
По крайней мере в GCC 3.x.x.
ek74
Цитата(amw @ Apr 18 2007, 18:14) *
На сколько я знаю, для ARM такого нет.
По крайней мере в GCC 3.x.x.


Перечитал всю документацию и пришёл к выводу, что в 4.1.1 тоже такого нет. Так что придётся использовать union sad.gif
Alex03
Немного не по вопросу, но...
Если оно не инлайн, то что мешает полностью асм-овую функцию написать?
Можно опять же встроенную в С, только объявить её c __attribute__((naked)), стандарт на ARM по передаче параметров вроде компиляторами поддерживается.

Ещё не понял про FR32_FRACTION_BITS и "lsl #2". У Вас FR32_FRACTION_BITS может быть только 30? Или не нашли как из 32-х вычесть FR32_FRACTION_BITS (видимо можно так "lsl #(32 - %a3)" )?

Кстати код
Код
    b3 = (fr32)((((int64_t) b1) * ((int64_t) b2)) >> FR32_FRACTION_BITS);

Генерит без учёта загрузки значений в регистры и сохранение результата
на -O1 .. -O3
Код
    smull r1, r0, r2, r3
    mov r3, r0, lsr #0x1e
    orr r3, r3, r1, lsl #0x02
    mov r4, r1, asr #0x1e     // лишняя командочка r4 потом не используется


А на -Os вообще то что надо.
Код
    smull r3, r12, r1, r2
    mov r12, r12, lsr #0x1e
    orr r1, r12, r3, lsl #0x02

При этом на -Os GCC ещё и заинлайнил fr32_mul() вот в таком коде
Код
    a3 = fr32_mul(a1, a2);
    b3 = (fr32)((((int64_t) b1) * ((int64_t) b2)) >> FR32_FRACTION_BITS);



GCC - 4.1.2
PS Ещёб ответ на исходный вопрос найти. smile.gif

Упс!
Про -Os наврал.
Код
         mov r4, r1, asr #0x02

там присутствует, просто код настолько наоптимизирован (перепутан) что строки
Код
    a3 = fr32_mul(a1, a2);
    b3 = (fr32)((((int64_t) b1) * ((int64_t) b2)) >> FR32_FRACTION_BITS);

на практике выполняются практически в обратном порядке.
ek74
Цитата(Alex03 @ Apr 19 2007, 18:35) *
Если оно не инлайн, то что мешает полностью асм-овую функцию написать?

В программе функция fr32_mul реализованна как инлайн, просто в вопросе я это опустил.

Цитата(Alex03 @ Apr 19 2007, 18:35) *
Можно опять же встроенную в С, только объявить её c __attribute__((naked)), стандарт на ARM по передаче параметров вроде компиляторами поддерживается.

Тип fx64 имеет следующее представление: si.f, где s - знаковый бит, i - целая часть (23 бита), f - дробная часть (40 бит). Сейчас функция fx64_mul реализована без найкед, следующим образом
Код
fx64 fx64_mul(fx64 arg1, fx64 arg2)
{
    register fx64 result asm("r0"); // Это формальность, а то gcc страшно ругается
    asm
    (
        "umull    r5, ip, r0, r2        \n"
        "umull    lr, r5, r1, r2        \n"
        "mov    r4, r1, asr #31        \n"
        "mla    r4, r2, r4, r5        \n"
        "adds    r2, lr, ip            \n"
        "adc    ip, r4, #0            \n"
        "umull    r4, lr, r0, r3        \n"
        "mov    r5, r3, asr #31        \n"
        "mla    r5, r0, r5, lr        \n"
        "adds    r4, r4, r2            \n"
        "adc    r5, r5, ip            \n"
        "mov    r4, r4, lsr #8        \n"
        "orr    r2, r4, r5, lsl #24    \n"
        "smull    r4, ip, r1, r3        \n"
        "mov    r3, r5, asr #8        \n"
        "mov    ip, ip, lsl #24        \n"
        "orr    r1, ip, r4, lsr #8    \n"
        "mov    r0, r4, lsl #24        \n"
        "adds    r0, r0, r2            \n"
        "adc    r1, r1, r3            \n"
        : /* no outputs */
        : /* no inputs */
        : "r0", "r1", "r2", "r3", "r4", "r5", "ip", "lr"
    );
    return result; // Это формальность, а то gcc страшно ругается
}

Но мне так не очень нравится, поэтому и задал вопрос...

Цитата(Alex03 @ Apr 19 2007, 18:35) *
Ещё не понял про FR32_FRACTION_BITS и "lsl #2". У Вас FR32_FRACTION_BITS может быть только 30? Или не нашли как из 32-х вычесть FR32_FRACTION_BITS (видимо можно так "lsl #(32 - %a3)" )?

Тут я согласен - вышла ошибочка, спасибо. Хотя с другой стороны FR32_FRACTION_BITS у меня всегда 30. Но для универсальности надо исправить.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.