Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Соглашения по регистрам
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Genadi Zawidowski
Вижу, что в документе Cortex-M3 programming manual написано - при входе в прерывание сохраняется
Цитата
● R0-R3, R12
● Return address
● PSR
● LR

Добавление __attribute__((__interrupt__)) (как я смог понять из кода) добавляет выравнивание стека на 8. В этом нет необходимости - обработка прерывания процессором это обеспечивает независимо от требования на выравнивание.
А что обеспечивает сохранение остальных регистров? Или эти регистры в gcc 4.7.2 в случае их использования в вычислениях сохраняются автоматически?
Сейчас при невнимательном тестировании на первый взгляд всё работает и без __attribute__((__interrupt__)).

В документе http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gc...tion-Attributes написано только то, что я и понял - на Cortex Mx только выравнивает стэк:
Цитата
On ARMv7-M the interrupt type is ignored, and the attribute means the function may be called with a word aligned stack pointer.

В start-up никаких изменений режима работы процессора не делается.
CODE
static void ResetException( void )
{

uint32_t * pSrc, * pDest ;


/* Low level Initialize */
arm_cpu_initialize(); // watchdog disable, clock initialize

/* Initialize the relocate segment */
pSrc = & _sidata;
pDest = & __data_start;

if ( pSrc != pDest )
{
// compiled for FLASH
for ( ; pDest < & __data_end ; )
{
*pDest++ = *pSrc++ ;
}
}
// Следить, чтобы переменные не оказались в стеке, очищаемом сейчас.
// Для этого, например, использована секция noinit
/* Clear the zero segment */
for ( pDest = & __bss_start; pDest < & __bss_end; )
{
* pDest ++ = 0;
}

/* Branch to main function */
main();

/* Infinite loop */
for (;;)
;
}
_Артём_
Цитата(Genadi Zawidowski @ Feb 12 2013, 20:55) *
Или эти регистры в gcc 4.7.2 в случае их использования в вычислениях сохраняются автоматически.
Сейчас при невнимательном тестировании на первый взгляд всё работает и без __attribute__((__interrupt__)).

Не понял, причём тут gcc? Это аппаратно делается.
Genadi Zawidowski
Цитата(_Артём_ @ Feb 12 2013, 23:10) *
Не понял, причём тут gcc? Это аппаратно делается.


Не все регистры сохраняются. А с остальными (R4..R11) как быть - как обеспечить их сохранение? Или этого нет необходимости делать (они сохраняются при использовании?) В gcc.
VslavX
Цитата(Genadi Zawidowski @ Feb 12 2013, 21:19) *
Не все регистры сохраняются. А с остальными (R4..R11) как быть - как обеспечить их сохранение? В gcc.

Их сохранение должна обеспечить сама вызываемая процедура. То есть - если процедуре надо использовать какой-либо из регистров R4-R11, то она его сама предварительно сохраняет, пользует и потом восстанавливает. Регистры R0-R3 процедура может использовать на свое усмотрение, их сохранять от процедуры не требуется.
Итого - произошло прерывание/исключение - флаги, R0-R3 и прочие сохранились, а остальные регистры R4-R11 вызванная процедура сама не разрушит.
Кстати, это не только к GCC относится, но и ко всем компиляторам, которые следуют APCS - "Procedure Call Standard for the ARM® Architecture" - документ есть на сайте ARM.

_Артём_
Цитата(Genadi Zawidowski @ Feb 12 2013, 21:19) *
Не все регистры сохраняются.

Конечно не все...

Цитата(Genadi Zawidowski @ Feb 12 2013, 21:19) *
А с остальными (R4..R11) как быть - как обеспечить их сохранение?

Вас Си интересует?
Никак не обепечивать. Компилятор знает что делает...

ViKo
Из книжки J. Yiu
Цитата
In many cases, the interrupt handler requires more than R0–R3 and R12 to process the interrupt, so we
might need to save some other registers as well. For C language users, there is no need to worry about this,
as the C function saves additional registers automatically if required. For assembly language users, their
interrupt handlers have to perform stack PUSH and POP to ensure the values of R4–R11 are preserved.
Genadi Zawidowski
Спасибо, значит функции обработчиков перерывания вообще ни в каких особых атрибутах в Cortex не нуждаются...

Цитата(ViKo @ Feb 12 2013, 23:33) *
Из книжки J. Yiu

Хотелось прочитать это где-то в документации на компилятор. Например в главе calling conventions или ещё где-то в подобном месте. Для gcc 4.7.2 не нашёл.
demiurg_spb
Цитата(Genadi Zawidowski @ Feb 12 2013, 23:36) *
значит функции обработчиков перерывания вообще ни в каких особых атрибутах в Cortex не нуждаются...
Абсолютно верное заключение.
Но для того чтобы отличить обычную функцию от обработчика я всё равно предваряю её ключевым для кейла словом __irq.
Лишнего самодокументирования не бывает ИМХО.
Код
void __irq EXTI9_5_IRQHandler(void)
{
    EXTI->PR = (1<<9); //сбросили флаг прерывания

    // do something else
}
ReAl
У меня
Код
#ifdef __cplusplus
#  define INTERRUPT extern "C"
#else
#  define INTERRUPT
#endif

// ...

INTERRUPT void UART3_IRQHandler()
{
    // ...
}


Цитата(Genadi Zawidowski @ Feb 12 2013, 21:36) *
Хотелось прочитать это где-то в документации на компилятор. Например в главе calling conventions или ещё где-то в подобном месте. Для gcc 4.7.2 не нашёл.

Уже ж сказано, что это стандартизовано ARM-ом и ссылка на документ дана:
Цитата(VslavX @ Feb 12 2013, 21:29) *
Кстати, это не только к GCC относится, но и ко всем компиляторам, которые следуют APCS - "Procedure Call Standard for the ARM® Architecture" - документ есть на сайте ARM.
Genadi Zawidowski
Пока мне APCS встретилось только в таком контексте:
Цитата
-mapcs-frame
Generate a stack frame that is compliant with the ARM Procedure Call Standard for all functions, even if this is not strictly necessary for correct execution of the code. Specifying -fomit-frame-pointer with this option causes the stack frames not to be generated for leaf functions. The default is -mno-apcs-frame.

Вот помню в Borland-овской документации было написано, в каких регистрах что возвращается (тогда ещё не умели передавать в регистрах), для каких типов что.
Просто меня спрашивают: вот ты сделал такой обработчик - а где гарантия, что регистры не используются? И я кроме честного слова за free software пока ничего не могу ответить...
ViKo
Цитата(Genadi Zawidowski @ Feb 13 2013, 21:49) *
Просто меня спрашивают: вот ты сделал такой обработчик - а где гарантия, что регистры не используются? И я кроме честного слова за free software пока ничего не могу ответить...

Как же, а в ассемблерный листинг посмотреть? Там все регистры видны. sm.gif
VslavX
Цитата(Genadi Zawidowski @ Feb 13 2013, 20:49) *
Вот помню в Borland-овской документации было написано, в каких регистрах что возвращается (тогда ещё не
...
кроме честного слова за free software пока ничего не могу ответить...

GCC следует стандартным соглашениям для архитектуры ARM, поэтому документацию надо смотреть на архитектуру. Упомянутый документ, раздел 5 "THE BASE PROCEDURE CALL STANDARD", там все подробно расписано - и про основные регистры, и про регистры FPU и про флаги.

Genadi Zawidowski
Цитата
GCC следует стандартным соглашениям для архитектуры ARM

Просто, где это сказано? Где написано, что эти соглашения действуют для gcc с ключами "по умолчанию".
Поиск чертырех букв APCS - абревиатуры названия на сайте gnu ничего не даёт (только как часть имени ключа).
Я так понимаю, KEIL следует стандарту своей же фирмы. Но кто декларировал совместимость keil и gcc? Как я знаю, это разные продукты...
Цитата
Как же, а в ассемблерный листинг посмотреть? Там все регистры видны

Ассемблерный листинг зависит от кода... от сложности выражений. Простые функции ничего не используют, только LR.
ViKo
Цитата(Genadi Zawidowski @ Feb 14 2013, 12:31) *
Ассемблерный листинг зависит от кода... от сложности выражений. Простые функции ничего не используют, только LR.

Красота! В качестве гарантии подсунуть листинг тому, кто спрашивает.
В качестве абсолютной гарантии продемонстрировать навороченный обработчик прерывания, чтобы всех имеющихся регистров не хватило.

В принципе, любой компилятор C для любого процессора должен при входе в функцию сохранить в стеке те регистры, которые используются в этой функции. Или переключиться на другой набор регистров.
_Pasha
Цитата(ViKo @ Feb 14 2013, 14:37) *
В качестве абсолютной гарантии продемонстрировать навороченный обработчик прерывания, чтобы всех имеющихся регистров не хватило.

Ага, как тут его заставить... вот есть стейт-машина, вида void *state_mashine(void *pc) и вызывается из нескольких прерываний, вроде бы действий внутри - мама не горюй. А все равно обходится преимущественно r0-r3, сохраняет r7,lr
Genadi Zawidowski
Цитата(ViKo @ Feb 14 2013, 14:37) *
В принципе, любой компилятор C для любого процессора должен при входе в функцию сохранить в стеке те регистры, которые используются в этой функции. Или переключиться на другой набор регистров.

Надеюсь, Вы понимаете, что это зависит от используемого соглашения о вызовах?
ViKo
Цитата(Genadi Zawidowski @ Feb 14 2013, 15:14) *
Надеюсь, Вы понимаете, что это зависит от используемого соглашения о вызовах?

Я считаю, что программист может об этом не думать при создании программы, разве что для расширения кругозора.
Вот единственное, что приходит на ум, когда нужно знать, что куда занеслось при вызове.
Код
__asm void HardFault_Handler(void) {
  TST LR, #4
  ITE EQ
  MRSEQ R0, MSP            ; Main Stack was used, put MSP in R0
  MRSNE R0, PSP            ; Process Stack was used, put PSP in R0
  LDR R0,[R0, #24]        ; Get stacked PC from stack
  B .
}
ReAl
Цитата(Genadi Zawidowski @ Feb 14 2013, 11:31) *
Просто, где это сказано? Где написано, что эти соглашения действуют для gcc с ключами "по умолчанию".
Поиск чертырех букв APCS - абревиатуры названия на сайте gnu ничего не даёт (только как часть имени ключа).
Ленивый поток ассоциаций…
APCS/соглашение о вызовах — часть EABI.
arm-*-eabi-gcc работает по eabi
Genadi Zawidowski
Для примера, как выглядит соответствующая глава документации (цитата НЕ из GCC):
Цитата
9.3 Calling Convention
In order to keep the binary compatibility with gcc and vc, ucc conforms to the calling convention of these compilers.
(1) When calling a function, the actual parameters will be pushed onto stack from right to left. The caller will pop the parameters.
(2) preserve registers:EBX, ESI and EDI which will be saved by the callee.
scratch registers:EAX, ECX and EDX which will be saved by the caller.
(3) function return value:
if the return value is integer type,EAX holds the return value.
if the return value is floating point type,ST(0) holds the return value.
if the return value is struct/union type in size 1, 2 or 4, EAX holds the return value.
if the return value is struct/union type in size 8, (EAX, EDX) holds the return value.
if the return value is struct/union type in other size, the function’s first parameter is implicit
which is the address of the function return value’s receiver, the function’s return type will be void.

AHTOXA
Вот же: Procedure Call Standard for the ARM Architecture.
Genadi Zawidowski
Цитата(AHTOXA @ Feb 15 2013, 11:28) *

Уже указывали... Это документ фирмы под названием ARM Ltd, с гарантией на этом документе базируется компилятор KEIL фирмы ARM Ltd. Если GCC делали применяя этот документ, инфомация исчерпывающая. Просто явного указания на то, что gcc основывается на этом документе, нигде нет.

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