Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR C & ASM
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
MALLOY2
В проекте (EWARM 5.20) не хватает немного скорости решил переписать на асм функцию подсчета CRC32
открыл листинг этой функции и возникло несколько вопросов



Код
\                                 In section .text, align 4, keep-with-next
     26          u32_t crc32_update(void *data, u32_t crc, u32_t len)
     27          {
   \                     crc32_update:
   \   00000000   00502DE9           PUSH     {R12,LR}
     28            u32_t i,z;
     29            u8_t  *buf = data;
     30            for (i = 0; i < len; i++)
   \   00000004   000052E3           CMP      R2,#+0
   \   00000008   0C00000A           BEQ      ??crc32_update_0
   \   0000000C   34309FE5           LDR      R3,??crc32_update_1 ;; 0xedb88320
     31              {
     32                crc ^= buf[i];
   \                     ??crc32_update_2:
   \   00000010   00C0D0E5           LDRB     R12,[R0, #+0]
   \   00000014   01102CE0           EOR      R1,R12,R1
     33                for (z = 0; z < 8; z++ )
   \   00000018   08C0A0E3           MOV      R12,#+8
     34                crc = crc & 0x01 ? (crc >> 1) ^ poly32 : crc >> 1;
   \                     ??crc32_update_3:
   \   0000001C   A1E0A0E1           LSR      LR,R1,#+1
   \   00000020   010011E3           TST      R1,#0x1
   \   00000024   0E102310           EORNE    R1,R3,LR
   \   00000028   0E10A001           MOVEQ    R1,LR
   \   0000002C   01C05CE2           SUBS     R12,R12,#+1
   \   00000030   F9FFFF1A           BNE      ??crc32_update_3
     35              }
   \   00000034   010080E2           ADD      R0,R0,#+1
   \   00000038   012052E2           SUBS     R2,R2,#+1
   \   0000003C   F3FFFF1A           BNE      ??crc32_update_2
     36            return (crc);
   \                     ??crc32_update_0:
   \   00000040   0100A0E1           MOV      R0,R1
   \   00000044   0280BDE8           POP      {R1,PC}         ;; return
   \                     ??crc32_update_1:
   \   00000048   2083B8ED           DC32     0xedb88320
     37          }


В мануале на IAR написано
Цитата
Any of the registers R0 to R3, and R12, can be used as a scratch register by the function.


Далее я не понял о чем речь
Цитата
Note that R12 is a scratch register also when calling between assembler functions only
because of automatically inserted instructions for veneers.


Собственно вопрос за чем компилятор при входе в функцию загоняет R12 в стек, а потом его восстанавливает в R1 ?

Если я использую в своей функции R12 его надо сохранять ?

Еще вопрос по строке
Цитата
SECTION .text:CODE(2)
, все понятно кроме 2 в скобках, в мануале не нашел, логика подсказывает что это алигмент, так или не так ?
KRS
Цитата(MALLOY2 @ Mar 4 2009, 18:14) *
Собственно вопрос за чем компилятор при входе в функцию загоняет R12 в стек, а потом его восстанавливает в R1 ?
Если я использую в своей функции R12 его надо сохранять ?

сейчас 5ки под рукой нет, в 4ке такого кода не видел, да и в 5ке тоже не помню
А у вас какая настройка, INTERWORKING включен?
Вообще R12 используется в ARM7 для переключения в THUMB режим, потому что у него нет инструкции BLX ( а есть только BX)

Цитата(MALLOY2 @ Mar 4 2009, 18:14) *
Еще вопрос по строке , все понятно кроме 2 в скобках, в мануале не нашел, логика подсказывает что это алигмент, так или не так ?

да это выравнивание.
насколько помню лучше про это в документации на линкер или ассемблер почитать.
MALLOY2
Значит так режим ARM, интерверкинг выключен.

При оптимизации "Balanced" выдает такой код.

При оптимизации "Speed" выдает такой

Код
    \                                 In section .text, align 4, keep-with-next
     25          u32_t crc32_update(void *data, u32_t crc, u32_t len)
     26          {
   \                     crc32_update:
   \   00000000   00402DE9           PUSH     {LR}
   \   00000004   04D04DE2           SUB      SP,SP,#+4
     27            u32_t i,z;
     28            u8_t  *buf = data;
     29            for (i = 0; i < len; i++)
   \   00000008   000052E3           CMP      R2,#+0
   \   0000000C   0C00000A           BEQ      ??crc32_update_0
   \   00000010   38309FE5           LDR      R3,??crc32_update_1 ;; 0xedb88320
     30              {
     31                crc ^= buf[i];
   \                     ??crc32_update_2:
   \   00000014   00C0D0E5           LDRB     R12,[R0, #+0]
   \   00000018   01102CE0           EOR      R1,R12,R1
     32                for (z = 0; z < 8; z++ )
   \   0000001C   08C0A0E3           MOV      R12,#+8
     33                crc = crc & 0x01 ? (crc >> 1) ^ poly32 : crc >> 1;
   \                     ??crc32_update_3:
   \   00000020   A1E0A0E1           LSR      LR,R1,#+1
   \   00000024   010011E3           TST      R1,#0x1
   \   00000028   0E102310           EORNE    R1,R3,LR
   \   0000002C   0E10A001           MOVEQ    R1,LR
   \   00000030   01C05CE2           SUBS     R12,R12,#+1
   \   00000034   F9FFFF1A           BNE      ??crc32_update_3
     34              }
   \   00000038   010080E2           ADD      R0,R0,#+1
   \   0000003C   012052E2           SUBS     R2,R2,#+1
   \   00000040   F3FFFF1A           BNE      ??crc32_update_2
     35            return (crc);
   \                     ??crc32_update_0:
   \   00000044   0100A0E1           MOV      R0,R1
   \   00000048   04D08DE2           ADD      SP,SP,#+4       ;; stack cleaning
   \   0000004C   0080BDE8           POP      {PC}            ;; return
   \                     ??crc32_update_1:
   \   00000050   2083B8ED           DC32     0xedb88320
     36          }


Здесь он зачем-то в стеке резервирует 4 байта smile.gif

При оптимизации "Size" такой

Код
   \                                 In section .text, align 4, keep-with-next
     25          u32_t crc32_update(void *data, u32_t crc, u32_t len)
     26          {
   \                     crc32_update:
   \   00000000   00502DE9           PUSH     {R12,LR}
     27            u32_t i,z;
     28            u8_t  *buf = data;
     29            for (i = 0; i < len; i++)
   \   00000004   0030A0E3           MOV      R3,#+0
   \   00000008   020000EA           B        ??crc32_update_0
     30              {
     31                crc ^= buf[i];
     32                for (z = 0; z < 8; z++ )
   \                     ??crc32_update_1:
   \   0000000C   01E05EE2           SUBS     LR,LR,#+1
   \   00000010   0500001A           BNE      ??crc32_update_2
   \   00000014   013083E2           ADD      R3,R3,#+1
   \                     ??crc32_update_0:
   \   00000018   020053E1           CMP      R3,R2
   \   0000001C   0800002A           BCS      ??crc32_update_3
   \   00000020   00C0D3E7           LDRB     R12,[R3, +R0]
   \   00000024   01102CE0           EOR      R1,R12,R1
   \   00000028   08E0A0E3           MOV      LR,#+8
     33                crc = crc & 0x01 ? (crc >> 1) ^ poly32 : crc >> 1;
   \                     ??crc32_update_2:
   \   0000002C   A1C0A0E1           LSR      R12,R1,#+1
   \   00000030   010011E3           TST      R1,#0x1
   \   00000034   10109F15           LDRNE    R1,??crc32_update_4 ;; 0xedb88320
   \   00000038   0C102110           EORNE    R1,R1,R12
   \   0000003C   0C10A001           MOVEQ    R1,R12
   \   00000040   F1FFFFEA           B        ??crc32_update_1
     34              }
     35            return (crc);
   \                     ??crc32_update_3:
   \   00000044   0100A0E1           MOV      R0,R1
   \   00000048   0280BDE8           POP      {R1,PC}         ;; return
   \                     ??crc32_update_4:
   \   0000004C   2083B8ED           DC32     0xedb88320
     36          }
KRS
очень похоже на глюк оптимизатора.
от переменной в стеке избавился, но место все равно резервирует smile.gif
у IAR такие артефакты частенько появляются.
я просто 5.xx в основном для кортекса использовал, надо будет помучать его...
А вы 5.30 не пробовали ставить?

А вообще если критические места писать на асм, то пролог и эпилог не сильно будут влиять!
R12 можно смело использовать.
вот здесь описано какие регистры и как можно использовать
http://infocenter.arm.com/help/topic/com.a...0042A_aapcs.pdf
MALLOY2
Пока ехал домой вспомнил что читал в мануале на Cortex про бит в регистре ядра, если его у становить то ядро при автоматическом сохранении контекста выравнивает стек на 8 ( или что то в этом духе уже точно не помню), комментировали они это тем что некоторые компиляторы требуют выравнивания стека на 8. просмотрев остальные функции действительно стек везде выровнен на 8.
Интересно для чего это сделано ?
У меня 2 версии ответа

1) для 64 битных переменных, почему бы тогда в настройках не сделать такую галочку которая разруливала эту ситуацию.
2) оптимизация по IAR RTOS чтобы контекстом быстрее клацала
KRS
Цитата(MALLOY2 @ Mar 4 2009, 22:24) *
Пока ехал домой вспомнил что читал в мануале на Cortex про бит в регистре ядра, если его у становить то ядро при автоматическом сохранении контекста выравнивает стек на 8 ( или что то в этом духе уже точно не помню), комментировали они это тем что некоторые компиляторы требуют выравнивания стека на 8.

Точно!!! И в новом стандарте ARM это обязательно! A 5.xx IAR же как раз в основном и отличался от 4.xx что поддердивал ARM ABI. ( они даже кортекс туда позже добавили так торопились!)

Зачем такое выравнивание для 32 разрядного процессора не понятно! В ARM7 и Cortex-M3 точно смылса не имеет там же нет ни кешей ни .... Но вроде при работе с float сопроцессором может пригодится!
Вообще в ссылке (выше) ARM Procedure Call Standart все требования описаны.

Надо поискать может у IAR и можно отключить выравнивание стека.
KRS
Не нашел у IAR отключения этой фичи sad.gif
Причем в стандарте написано что стек должен быть выравнен при вызове public interface. А данная функция ничего не вызывает, т.е. это бага (фича) оптимизатора стек не должен быть тут выравнен!
Выравнивание сделано что бы LDRD работала (которй отродясь в ARM7 не было), причем эта инструкция требует выравнивания на 8 только у ARMv5, а у ARMv6 ARMv7 уже работает и с выравниванием на 4
MALLOY2
Но ее может прерывание прервать smile.gif, в друг я там переключусь в user режим .....
KRS
Цитата(MALLOY2 @ Mar 5 2009, 15:43) *
Но ее может прерывание прервать smile.gif, в друг я там переключусь в user режим .....

Прерывание может прервать и такой поток инструкций
\ 00000000 00402DE9 PUSH {LR}
\ 00000004 04D04DE2 SUB SP,SP,#+4
и прерывания не относятся к публичным интерфейсам, они должны заботится о выравнии стека сами ( кстати у кортекса есть настройка и он может аппаратно выравнивать стек при входе в прерывания)
MALLOY2
Походу еще несколько вопросов

Написал функцию, оформил все как полагается, сделал к ней хедер файл с декларацией функции.

Теперь я в этом хедере объявил дефайн как его можно у видеть в асм файле ? если я этот хедер подключаю в асм файл получаю кучу матов на мою декларацию функции, что есть логично. Но все же какие есть варианты ?

И самый главный вопрос можно ли компилятору объяснить как-то чтобы он эту функцию умел инлайнить ? (что то мне кажется это не реальным) я так понимаю за это отвечает встроенный модификатор __intrinsic но он типа внутринний. К примеру сделать функцию аналогичную __no_operation() но чтобы она вставляла 8 нопов к примеру.
Сергей Борщ
Цитата(MALLOY2 @ Mar 5 2009, 15:50) *
Теперь я в этом хедере объявил дефайн как его можно у видеть в асм файле ? если я этот хедер подключаю в асм файл получаю кучу матов на мою декларацию функции, что есть логично. Но все же какие есть варианты ?
обрамить относящиеся к С части файла в #ifndef __IAR_SYSTEMS_ASM__ #endif. Вы можете подсмотреть это в заголовочных файлах описания регистров процессора (ioXXX.h). 

Цитата(MALLOY2 @ Mar 5 2009, 15:50) *
И самый главный вопрос можно ли компилятору объяснить как-то чтобы он эту функцию умел инлайнить ? (что то мне кажется это не реальным) я так понимаю за это отвечает встроенный модификатор __intrinsic но он типа внутринний. К примеру сделать функцию аналогичную __no_operation() но чтобы она вставляла 8 нопов к примеру.
Встроить вашу - только написать ее на инлайн-асме. Но он довольно убогий, 8 нопов - это чуть ли не верх его возможностей:
Код
_Pragma("inline=forced") void nop8(void)
{
    __no_operation();
    __no_operation();
    __no_operation();
    __no_operation();
    __no_operation();
    __no_operation();
    __no_operation();
    __no_operation();
}
__intrinsic указывает, что тело функции генерит сам компилятор по месту, код для этого жестко встроен в компилятор.
MALLOY2
Всем спасибо за помощь. Функцию переписал.

Результат в симуляторе:

Размер блока 10000 байт
Начальное значение 0xFF
Функция на С - 460008 циклов
Функция на ASM - 170137 циклов

В железе будет еще быстрее так как меньше перегрузок конвеера


Прототип С

Код
u32_t crc32_update2(u32_t crc, void *data, u32_t len)
{
  u32_t i,z;
  u8_t  *buf = data;
  for (i = 0; i < len; i++)
    {
      crc ^= buf[i];
      for (z = 0; z < 8; z++ )
      crc = crc & 0x01 ? (crc >> 1) ^ poly32 : crc >> 1;
    }
  return (crc);
}



Может кому пригодится присоединяю ассемблерный код
GetSmart
Советую избавиться от этого изврата
Код
REPTI 1,1,1,1,1,1,1,1,1;дублируем 8 раз

Стоило бы написать
Код
REPT 8;дублируем 8 раз


И по правилам хорошего тона для асм вставок/процедур следует сохранять и восстанавливать используемые регистры (кроме параметров процедур), в частности R3 и R12. Это никак не отразится на быстродействии, но избавит от непонятных глюков. Я уже вставал на грабли с R12 в IARе.
MALLOY2
из мауала на IAR
Цитата
Any of the registers R0 to R3, and R12, can be used as a scratch register by the function.
вы топик полностью читали ?


Цитата
REPT 8;дублируем 8 раз
можно и так незнаю зачем я сделал так как сделал конец рабюочего дня наверное .... smile.gif
GetSmart
Читал. Даже название прочитал. Но опять же получается функция привязана к конкретному компилятору. ИМХО плохой тон и точка.

ЗЫ. как-то заинлайнил функцию, которая использовала R12 и не сохраняла. Потом долго искал причину глюков. Так что и вам того же желаю smile.gif
MALLOY2
Цитата
Но опять же получается функция привязана к конкретному компилятору. ИМХО плохой тон и точка.


С каких пор ассемблер стал кросс платформенным ?
sergeeff
Вы же собираетесь что-то на ассемблере использовать совместно с С. Если компилятор удовлетворяет APCS требованиям, вы их должны соблюдать в своих asm-процедурах. Если есть мазохическое желание все написать на ассемблере, можете придумать сами свои собственные условия использования регистров - флаг в руки. Вот и все, что нужно себе уяснить.
MALLOY2
А я о чем ?

1) код на 100% соответствует мануалу на который дал ссылку KRS, а также мануалу EWARM_AssemblerReference.
2) просмотрев код который генерирует IAR я убедился что он нигде не сохраняет R12 это дает дополнительную уверенность в том что IAR тоже следует ARM ABI
3) Если этот код будет глючить у кого-то это его половые трудности, я его не продаю и не накладываю никаких ограничений просто поделился вот и все кому что не нравится тот его не юзает.
4) Люди страдающие параноей могут весь файл регистров загонять в стек и еще CPSR, мне нужен был максимально быстрый код под мой проект думаю я его получил.

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