Главная arrow Программирование arrow ARM arrow ARM: как быстро начать писать на ассемблере Monday, December 11 2017  
ГлавнаяКонтактыАдминистрированиеПрограммированиеСсылки
UK-flag-ico.png English Version
GERMAN-flag-ico.png Die deutsche Version
map.gif карта сайта
нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Поделиться:

ARM: как быстро начать писать на ассемблере Версия для печати
Написал microsin   
27.12.2008

Поначалу ARM довольно непривычный ассемблер (если переучиваться с x86, MCS51 или AVR). Но у него довольно простая и логичная организация, поэтому усваивается быстро.

Документации на русском языке по ассемблеру совсем мало. Могу посоветовать зайти на 2 ссылки (может, Вы найдете больше, и подскажете мне? Буду благодарен.):
Архитектура и система команд RISС-процессоров семейства ARM - http://www.gaw.ru/html.cgi/txt/doc/micros/arm/index.htm
Постигаем ассемблер ARM, из цикла статей «GBA ASM», автор Mike H, пер. Aquila - http://wasm.ru/series.php?sid=21.

Последняя ссылка мне очень помогла, развеяла туман =). Второе, что хорошо может помочь - это, как ни странно, C-компилятор IAR Embedded Workbench for ARM (далее просто IAR EW ARM). Дело в том, что он со стародавних времен умеет (как и все уважающие себя компиляторы, впрочем) компилировать C-код в код ассемблера, который, в свою очередь, так же легко компилируется ассемблером IAR в объектный код. Поэтому нет ничего лучше написать простейшую функцию на C, скомпилировать её в ассемблер, и сразу станет понятно, какая команда ассемблера что делает, как передаются аргументы и как возвращается результат. Убиваете сразу двух зайцев - обучаетесь ассемблеру и заодно получаете информацию, как интергрировать ассемблерный код в проект на C. Я тренировался на функции подсчета CRC16, и в результате получил её полноценную версию на ассемблере. 

Вот исходная функция на C (u16 означает unsigned short, u32 - unsigned int, u8 - unsigned char):
// файл crc16.c
u16 CRC16 (void* databuf, u32 size)
{
   u16 tmpWord, crc16, idx;
   u8 bitCnt;
   #define CRC_POLY 0x1021;

   crc16 = 0;
   idx=0;
   while (size!=0)
   {
      /* сложим по xor старший байт crc16 и входной байт */
      tmpWord = (crc16>>8) ^ (*(((u8*)databuf)+idx));
      /* результат запишем в старший байт crc16 */
      tmpWord <<= 8;
      crc16 = tmpWord + (0x00FF & crc16);
      for (bitCnt=8;bitCnt!=0;bitCnt--)
      {
         /* проверим старший разряд аккумулятора CRC */
         if (crc16 & 0x8000)
         {
            crc16 <<= 1;
            crc16 ^= CRC_POLY;
         }
         else
            crc16 <<= 1;
      }
   idx++;
   size--;
   }
   return crc16;
}

Заставить генерировать код ассемблера IAR EW ARM очень легко. В опциях файла crc16.c (добавленного к проекту) поставил галку Override inherited settings, а потом на закладке List поставил 3 галки - Output assembler file, Include source и Include call frame information (хотя последнюю галку, наверное, можно не ставить - она генерит кучу ненужных CFI-директив). После компиляции получился файл папка_проекта \ ewp \ at91sam7x256_sram \ List \ crc16.s. Этот файл также легко можно добавить в проект, как и C-файл (он будет нормально компилироваться).
    
Конечно, когда я подсунул C-компилятору необрезанный вариант C-кода, то он мне выдал такой листинг ассемблера, что я ничего в нем не понял. Но когда выкинул из функции все C-операторы, кроме одного, стало понятнее. Потом шаг за шагом добавлял C-операторы, и вот в итоге что получилось:

; файл crc16.s
        NAME crc16
        PUBLIC CRC16
       
CRC_POLY    EQU    0x1021

        SECTION `.text`:CODE:NOROOT(2)
        ARM
       
// u16 CRC16 (void* databuf, u32 size)
;R0 - результат возврата, CRC16
;R1 - параметр size
;R2 - параметр databuf (он был при входе в R0)
;R3, R12 - временные регистры

CRC16:
        PUSH     {R3,R12}       ;методом тыка выяснил, что R3 и R13 сохранять
                                ; необязательно. Но решил сохранить на всякий
                                ; случай.
        MOVS     R2,R0          ;теперь R2==databuf
        MOV      R3,#+0
        MOVS     R0,R3          ;crc16 = 0
CRC16_LOOP:
        CMP     R1, #+0         ;все байты обработали (size==0)?
        BEQ     CRC16_RETURN    ;если да, то выход
        LSR     R3, R0, #+8     ;R3 = crc16>>8
        LDRB    R12, [R2]       ;R12 = *databuf
        EOR     R3, R3, R12     ;R3 = *databuf ^ HIGH (crc16)
        LSL     R3, R3, #+8     ;R3 <<= 8 (tmpWord <<= 8)
        AND     R0, R0, #+255   ;crc16 &= 0x00FF
        ADD     R0, R0, R3      ;crc16 = tmpWord + (0x00FF & crc16)
        MOV     R12, #+8        ;bitCnt = 8
CRC16_BIT_LOOP:
        BEQ      CRC16_NEXT_BYTE    ;bitCnt == 0?
        TST      R0,#0x8000         ;Еще не все биты обработаны.
        BEQ      CRC16_BIT15ZERO    ;Проверяем старший бит crc16.
        LSL      R0,R0,#+1          ;crc16 <<= 1
        MOV      R3,   #+(LOW (CRC_POLY))          ;crc16 ^= CRC_POLY
        ORR      R3,R3,#+(HIGH(CRC_POLY) << 8)     ;
        EOR      R0,R3,R0                          ;
        B        CRC16_NEXT_BIT

CRC16_BIT15ZERO:
        LSL      R0,R0,#+1          ;crc16 <<= 1
CRC16_NEXT_BIT:
        SUBS     R12,R12,#+1        ;bitCnt--
        B        CRC16_BIT_LOOP     ;

CRC16_NEXT_BYTE:       
        ADD      R2,R2,#+1          ;databuf++
        SUBS     R1,R1,#+1          ;size--
        B        CRC16_LOOP         ;цикл по всем байтам
   
CRC16_RETURN:
        POP      {R3,R12}           ;восстанавливаем регистры
        BX       LR                 ;выход из подпрограммы, R0==crc16

        END

Компилятор C от IAR делает на удивление хороший код. Мне совсем мало удалось его оптимизировать. Выкинул только лишний временный регистр, который хотел использовать компилятор (он почему-то взял в качестве лишнего временного регистра LR, хотя R3 и R12 было достаточно), а также убрал пару лишних команд, проверяющих счетчики и выставляющих флаги (просто добавив суффикс S к нужным командам).

Последнее обновление ( 08.04.2009 )
 

Комментарии  

  1. #1 Prottey
    2013-03-2411:56:39 В принципе, генерировать ассемблерные листинги из сишного кода может и GCC с параметром -S. Ассемблерные файлы на выходе можно собирать при помощи GNU Assembler (gas), собранного под нужный таргет, в данном случае arm-eabi. У Sourcery Codebench Lite как раз есть такие сборки.

Добавить комментарий

:D:lol::-);-)8):-|:-*:oops::sad::cry::o:-?:-x:eek::zzz:P:roll::sigh:

Защитный код
Обновить

< Пред.

Top of Page
 
microsin © 2017