Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

GCC (ARM) инструкции на асемблер в C кода - как?
http://mcu-bg.com/mcu_site/viewtopic.php?f=16&t=6830
Страница 1 от 1

Автор:  Цецо [ Сря Май 20, 2009 10:02 am ]
Заглавие:  GCC (ARM) инструкции на асемблер в C кода - как?

Как се вмъкват асемблерски инструкции в C код под GCC?

Трябва да нахакам едни микрозакъснения, т.е. за няколко NOP-a иде реч.

А пуста документация на GCC.... :(

Автор:  FiTTiLA [ Сря Май 20, 2009 10:20 am ]
Заглавие:  Re: GCC (ARM) инструкции на асемблер в C кода - как?

Цецо написа:
Как се вмъкват асемблерски инструкции в C код под GCC?

Трябва да нахакам едни микрозакъснения, т.е. за няколко NOP-a иде реч.

А пуста документация на GCC.... :(


asm("NOP");

Автор:  Цецо [ Сря Май 20, 2009 10:33 am ]
Заглавие: 

Екстра.

А как да вкарам малко повече инструкции, с някой етикет/джъмп евентуално?

И къде въобще е документирано това? В GCC документацията не го откривам?

Автор:  miro_atc [ Сря Май 20, 2009 10:55 am ]
Заглавие: 

да asm()... но има доста подробности. Имаше документация, ама сега не ми се рови - ще го обясня с пример:

Цитат:
inline static __swi __arm void tsk_send_signal(volatile Task * task, unsigned int signal)
{
volatile register Task *_task asm("r0") = task;
volatile register unsigned int _signal asm("r1") = signal;

asm volatile ("swi %2"
: "=r" (_task), "=r"(_signal)
: "I" (usr_send_signal_swi), "0" (_task), "1"(_signal)
: "r2", "r3", "r12");
}


В случая това е функция дето съм я направил изцяло на асемблер щото GCC няма друг начин за поддръжка на SWI, както и да е асемблер може да се вгражда *навсялъде*...

Първо asm, после volatile за да не си прави шегички при оптимазия, после в кавички колкото на брой искаш асемблерски инструкции и накрая трите реда с ":", които имат следното значение:
Първия ред описва "изхода" на асемблера като променливи и/или регистри. Втория ред описва входните параметри, а третия ред описва обекти дето асемблера може и да омаже...

Ако параметъра е изходен трябва да започва с "=" след това с "r" ако е регистров, ако е типът е imidiate (константа) се описва с "I".
Всички парамтери получават номерца и после с тия номерца се ползват в асемблерския код. Примерно аз ползвам %2 в кода на SWI инструкцията - това е втори номер, т.е. usr_send_signal_swi

Една особеност - ако един параметър е едновременно входен и изходен, първо си се декларира като изходен, а после се изброява номера му. Така са ми _task и _signal - първо ги декларирам с "=r", т.е. като регистър който ще получи стойност, и после ги повтарям и като входни параметри само че без % - деректно номерчето като параметър.

Други особености:
* Пази се много от оптимизациите.... Избягвай да ползваш директно С-променливи, понеже в зависимост от оптимизацията компилатора може да ги разположи в стека или да ги направи регистрови. А в асемблера все пак трябва да знаеш дали е регистър или памет. Затова най-добре да си направиш собствени променливи дето знаеш какви са, както примерно:
Код:
volatile register Task *_task asm("r0") = task;

В случая имам Ц-променлива "task" и за да не завися от това каква е, си правя "копие" на променливата в регистрова и то точно определен регистър. Като volatile е задължителен ако не искаш да гониш духове...
Не се притеснявай за тези междинни присвоявания - компилатора не е толкова глупав и не прави излишен код. Просто ти му казваш да не пипа твойта версия и съптветно той оптимизира "оригинала".


Ето пък пример с повечко инструкции:

Цитат:
static unsigned int get_clocks_per200ms(void)
{
unsigned int res;

asm volatile (
"1: \n\t"
" mov %0, #0 \n\t"
" mov r1, r8 \n\t" //REG_MTASK
" mov r2, #200 \n\t"
" ldr r3, [r1, %1] \n\t"
"2: \n\t"
" add %0, %0, #8 \n\t"
" ldr r4, [r1, %1] \n\t"
" cmp r3, r4 \n\t"
" beq 2b \n\t"
" bhi 1b \n\t"

" add r3, r3, #1 \n\t"
" sub r2, r2, #1 \n\t"
" bne 2b \n\t"

: "=r"(res)
: "I" (tsk_time)
: "r1", "r2", "r3", "r4"
);
return res;
}


Това е код, който обаче няма входни параметри и затова не се налага защита от оптимизациите на компилатора...

Автор:  Цецо [ Сря Май 20, 2009 11:10 am ]
Заглавие: 

Благодарско.

Засега ми трябва съвсем праволинеен код, без предаване на параметри.

Автор:  miro_atc [ Сря Май 20, 2009 11:18 am ]
Заглавие: 

Всъщност малко поизлъгах с входните и изходните параметри...

Като му кажеш, че искаш да ползваш като параметър в регистър някаква променлива с "r"(foo) - компилатора се грижи да намери някой своден регистър и да ти качи стойността на тази променлива в този регистър. Същото е и при изхода, като му кажеш че изкарваш резултат, то ще ти го запише където трябва.

Проблемът в моя случай със SWI функциите е, че по разни причини искам да са static функция, а при static функциите GCC се прави на тарикат и заебава calling конвенцията, т.е. няма гаранция че функцията ще получава параметрите си точно с R0-R3 +стек. Може да си избере други регистри. Но от друга страна аз при SWI викам хендлъри и асемблерски код, който не е inline и ми трябва първия параметър да е в R0, втория в R1 и т.н. както си е по arm calling convention.
Та затова трябваше да минавам с тия междинни volatile register променливи...

Ако на асемблера не му пука кой параметър в кой регистър, май спокойно може да е простичко както във втория пример....

Автор:  Zdrav [ Сря Май 20, 2009 4:42 pm ]
Заглавие: 

http://www.ethernut.de/en/documents/arm-inline-asm.html

Страница 1 от 1 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/