|
IAR C & ASM, Scratch registers |
|
|
|
Mar 4 2009, 15:14
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
В проекте (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 в скобках, в мануале не нашел, логика подсказывает что это алигмент, так или не так ?
|
|
|
|
|
Mar 4 2009, 15:51
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(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 в скобках, в мануале не нашел, логика подсказывает что это алигмент, так или не так ? да это выравнивание. насколько помню лучше про это в документации на линкер или ассемблер почитать.
|
|
|
|
|
Mar 4 2009, 16:00
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Значит так режим 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 байта При оптимизации "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 }
|
|
|
|
|
Mar 4 2009, 16:30
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
очень похоже на глюк оптимизатора. от переменной в стеке избавился, но место все равно резервирует  у IAR такие артефакты частенько появляются. я просто 5.xx в основном для кортекса использовал, надо будет помучать его... А вы 5.30 не пробовали ставить? А вообще если критические места писать на асм, то пролог и эпилог не сильно будут влиять! R12 можно смело использовать. вот здесь описано какие регистры и как можно использовать http://infocenter.arm.com/help/topic/com.a...0042A_aapcs.pdf
|
|
|
|
|
Mar 4 2009, 19:43
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(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 и можно отключить выравнивание стека.
|
|
|
|
|
Mar 5 2009, 12:54
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(MALLOY2 @ Mar 5 2009, 15:43)  Но ее может прерывание прервать  , в друг я там переключусь в user режим ..... Прерывание может прервать и такой поток инструкций \ 00000000 00402DE9 PUSH {LR} \ 00000004 04D04DE2 SUB SP,SP,#+4 и прерывания не относятся к публичным интерфейсам, они должны заботится о выравнии стека сами ( кстати у кортекса есть настройка и он может аппаратно выравнивать стек при входе в прерывания)
|
|
|
|
|
Mar 5 2009, 14:15
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(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 указывает, что тело функции генерит сам компилятор по месту, код для этого жестко встроен в компилятор.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Mar 5 2009, 16:38
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
Всем спасибо за помощь. Функцию переписал. Результат в симуляторе: Размер блока 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); } Может кому пригодится присоединяю ассемблерный код
|
|
|
|
|
Mar 5 2009, 17:20
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Советую избавиться от этого изврата Код REPTI 1,1,1,1,1,1,1,1,1;дублируем 8 раз Стоило бы написать Код REPT 8;дублируем 8 раз И по правилам хорошего тона для асм вставок/процедур следует сохранять и восстанавливать используемые регистры (кроме параметров процедур), в частности R3 и R12. Это никак не отразится на быстродействии, но избавит от непонятных глюков. Я уже вставал на грабли с R12 в IARе.
Сообщение отредактировал GetSmart - Mar 5 2009, 17:23
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Mar 5 2009, 17:25
|
Знающий
   
Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317

|
из мауала на IAR Цитата Any of the registers R0 to R3, and R12, can be used as a scratch register by the function. вы топик полностью читали ? Цитата REPT 8;дублируем 8 раз можно и так незнаю зачем я сделал так как сделал конец рабюочего дня наверное ....
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|