Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Ошибка при отладке в AVR Studio маленького макроса
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
_Алекс
Была задача получить текущий адрес выполнения программы – программный счетчик PC.
Среда разработки IAR
Запомнить его, сделал вот так, результат, при отладке в AVR STUDIO выдает ошибку с переполнение стека после нескольких прогонах программы, интересно что при вызове rcall L1, стек увеличивается на 2 байта, при pop, pop уменьшается на два, вобщем кажется все правильно.

Макрос взятия адреса и функция в макросе, которая по идеи должна сохранять PC, но просто сделана как тестовая.

#define OutSaveContekst\
{\
asm ("rcall L1\n" "L1: pop r16\n" "pop r17\n");\
SaveContext();\
\
}

Функция SaveContext (по идеи сохранение контекста) ни чего полезного пока
void SaveContext(void){
static int t = 0;
t++;
};

Функция тест в которой применен макрос
void test(void){
static char i;
if (i = = 5){
OutSaveContekst;
i = i + 1;
};
i = i + 1;
};

Главная функция
void main( void )
{
while(1){
test();
}
};
_Bill
Цитата(_Алекс @ Nov 16 2006, 10:56) *
Была задача получить текущий адрес выполнения программы – программный счетчик PC.
Среда разработки IAR
Запомнить его, сделал вот так, результат, при отладке в AVR STUDIO выдает ошибку с переполнение стека после нескольких прогонах программы, интересно что при вызове rcall L1, стек увеличивается на 2 байта, при pop, pop уменьшается на два, вобщем кажется все правильно.

Макрос взятия адреса и функция в макросе, которая по идеи должна сохранять PC, но просто сделана как тестовая.

#define OutSaveContekst\
{\
asm ("rcall L1\n" "L1: pop r16\n" "pop r17\n");\
SaveContext();\
\
}

Функция SaveContext (по идеи сохранение контекста) ни чего полезного пока
void SaveContext(void){
static int t = 0;
t++;
};

Функция тест в которой применен макрос
void test(void){
static char i;
if (i = = 5){
OutSaveContekst;
i = i + 1;
};
i = i + 1;
};

Главная функция
void main( void )
{
while(1){
test();
}
};

Ваша функция L1 баланс стека нарушает, поэтому и происходи переполнение стека.
Если Вы хотите получить доступ к стеку, Вам нужно просто считать данные с порта стека:
Код
        in      r16, SPL
        in      r16, SPH

Или то же самое на Си:
Код
       spl = SPL;
       sph = SPH;
prottoss
Цитата(_Bill @ Nov 16 2006, 16:43) *
Ваша функция L1 баланс стека нарушает, поэтому и происходи переполнение стека. Если Вы хотите получить доступ к стеку, Вам нужно просто считать данные с порта стека:
Код
        in      r16, SPL
        in      r16, SPH

Или то же самое на Си:
Код
       spl = SPL;
       sph = SPH;
Вообще то в первом посте говорилось не о стеке, а об адресе вызываемой фунции

Цитата(_Алекс @ Nov 16 2006, 14:56) *
Была задача получить текущий адрес выполнения программы – программный счетчик PC.
Среда разработки IAR...
Зачем такие извраты? Можно проще:
Код
unsigned int OutSaveContekst(void)
{      return SP;
}
Все))) Вот листинг:

Код
unsigned int OutSaveContekst(void)
   \                     OutSaveContekst:
     20          { return SP;
   \   00000000   B70D               IN      R16, 0x3D
   \   00000002   B71E               IN      R17, 0x3E
   \   00000004   9508               RET
     21          }
IgorKossak
prottoss, Вы получили таким образом значение SP, а никак не PC, как требовалось.
Очевидно, что после выталкивания двух байт из стека, их надо затолкать обратно, а копию в r16, r17 вернуть из подпрограммы.
Либо как в Вашем случае привести SP к типу указателя на int и взять по нему значение (с прединкрементом по-моему).
В любом случае эту операцию надо делать атомарно (непрерываемо).
prottoss
Цитата(IgorKossak @ Nov 16 2006, 20:38) *
prottoss, Вы получили таким образом значение SP, а никак не PC, как требовалось.
Очевидно, что после выталкивания двух байт из стека, их надо затолкать обратно, а копию в r16, r17 вернуть из подпрограммы.
Либо как в Вашем случае привести SP к типу указателя на int и взять по нему значение (с прединкрементом по-моему).
В любом случае эту операцию надо делать атомарно (непрерываемо).
Сорри, конечно же надо не было не так - сказал одно, а думал о другом))) Наверное вот так правильнее:

Код
unsigned int OutSaveContekst(void)
{      return *((unsigned int __flash *)SP);
}
Тогда получается в асме:

Код
   19          unsigned int OutSaveContekst(void)
   \                     OutSaveContekst:
     20          {      return *((unsigned int __flash *)SP);
   \   00000000   B7ED               IN      R30, 0x3D
   \   00000002   B7FE               IN      R31, 0x3E
   \   00000004   9105               LPM     R16, Z+
   \   00000006   9114               LPM     R17, Z
   \   00000008   9508               RET
     21          }




Цитата(IgorKossak @ Nov 16 2006, 20:38) *
prottoss, Вы получили таким образом значение SP, а никак не PC, как требовалось.
Очевидно, что после выталкивания двух байт из стека, их надо затолкать обратно, а копию в r16, r17 вернуть из подпрограммы.
Либо как в Вашем случае привести SP к типу указателя на int и взять по нему значение (с прединкрементом по-моему).
В любом случае эту операцию надо делать атомарно (непрерываемо).
Нет, думаю что я правильно привел, то что привел в первом своем посте. Функция возвращает адрес в стеке - а этот адрес и есть функция. Пожалуйста - вот еще один вариант

Код
unsigned int __flash *OutSaveContekst(void)
   \                     OutSaveContekst:
     20          {      return (unsigned int __flash *)SP;
   \   00000000   B70D               IN      R16, 0x3D
   \   00000002   B71E               IN      R17, 0x3E
   \   00000004   9508               RET
     21          }
Абсолютно тоже самое))) А то что я привел в выше в этом же посте (извиняюсь за калабур) возвратит код команды B7ED IN R30, 0x3D
IgorKossak
Цитата
Была задача получить текущий адрес выполнения программы – программный счетчик PC.

SP указывает на место куда в следующий раз будет сохранён байт (pop) или адрес (call).
Поэтому надо модифицировать SP (чтобы он указывал на место в стеке, где лежит сохранённый адрес) и после этого РАЗЫМЕНОВАТЬ его, т. е. взять значение, лежащее в стеке (а не в SP и уж тем более, не во __flash).
prottoss
Цитата(IgorKossak @ Nov 16 2006, 21:39) *
Цитата
Была задача получить текущий адрес выполнения программы – программный счетчик PC.

SP указывает на место куда в следующий раз будет сохранён байт (pop) или адрес (call).
Поэтому надо модифицировать SP (чтобы он указывал на место в стеке, где лежит сохранённый адрес) и после этого РАЗЫМЕНОВАТЬ его, т. е. взять значение, лежащее в стеке (а не в SP и уж тем более, не во __flash).
Да, Вы правы... А что по поводу вот такого варианта?

Код
     19          unsigned int __flash *OutSaveContekst(void)
   \                     OutSaveContekst:
     20          {
     21             return (unsigned int __flash *)(*(unsigned int *)(SP + 2));
   \   00000000   B7ED               IN      R30, 0x3D
   \   00000002   B7FE               IN      R31, 0x3E
   \   00000004   9632               ADIW    R31:R30, 2
   \   00000006   8100               LD      R16, Z
   \   00000008   8111               LDD     R17, Z+1
   \   0000000A   9508               RET
     22          }
IgorKossak
Цитата(prottoss @ Nov 16 2006, 16:58) *
А что по поводу вот такого варианта?

Это и имелось в виду, только среды под рукой не было, чтобы проверить.
PS: атомарность всё-таки необходима. Это можно обеспечить словом __monitor перед определением функции.
prottoss
Цитата(IgorKossak @ Nov 16 2006, 22:05) *
Цитата(prottoss @ Nov 16 2006, 16:58) *

А что по поводу вот такого варианта?

Это и имелось в виду, только среды под рукой не было, чтобы проверить.
PS: атомарность всё-таки необходима. Это можно обеспечить словом __monitor перед определением функции.
Зачем защищаться от прерываний? Мы ничего опасного не делаем, и сколько бы прерываний не использовались, ежели они "правильные" (т.е. никаких выкрутасов с памятью данных не выделывают) мы получим то самое значение, которое хотим... Или я опять не догнал чегойто?
IgorKossak
Согласен, сказались предрассудки при работе с другими ресурсами внутренней периферии.
Alex ma
Получилось вот так
unsigned int OutSaveContekst(void){
return (*(unsigned int *)(SP + 2));
};

Возвращает адрес во Flash на оператор после вызова функции

18: it = OutSaveContekst();
+0000002B: D005 RCALL PC+0x0006 Relative call subroutine
+0000002C: EDE4 LDI R30,0xD4 Load immediate
+0000002D: E0F0 LDI R31,0x00 Load immediate
+0000002E: 8300 STD Z+0,R16 Store indirect with displacement
+0000002F: 8311 STD Z+1,R17 Store indirect with displacement
Возвращает 0х002С

Корректно будет если 0х002С + 4, т.е
unsigned int OutSaveContekst(void){
return ((*(unsigned int *)(SP + 2)) + 4);
};
Тогда возвращает 0х0030
18: it = OutSaveContekst();
+0000002B: D005 RCALL PC+0x0006 Relative call subroutine
+0000002C: EDE4 LDI R30,0xD4 Load immediate
+0000002D: E0F0 LDI R31,0x00 Load immediate
+0000002E: 8300 STD Z+0,R16 Store indirect with displacement
+0000002F: 8311 STD Z+1,R17 Store indirect with displacement
@00000030: _..X_RSTACK_BASE
19: };
+00000030: 9508 RET Subroutine return

Будет так работать, указывать на следующий оператор во флеш после вызова функции, затем можно выйти return, а потом вернуться icall, Будет работать?

PS
_Alex на работе,
Alex ma дома.
prottoss
Цитата(Alex ma @ Nov 17 2006, 00:09) *
Будет так работать, указывать на следующий оператор во флеш после вызова функции, затем можно выйти return, а потом вернуться icall, Будет работать?
Данной функцией Вы получили указатель на Память Программ и можете делать с ним все что Вам заблагорассудится - читать данные, прыгнуть по этому адресу и т.п.

Цитата(Alex ma @ Nov 17 2006, 00:09) *
PS
_Alex на работе,
Alex ma дома.
Не мое, конечно, дело... Но зачем усложнять жизнь себе и другим? Или есть желание пообщаться с самим собой?)))
Alex ma
Цитата(prottoss @ Nov 16 2006, 23:37) *
Цитата(Alex ma @ Nov 17 2006, 00:09) *
Будет так работать, указывать на следующий оператор во флеш после вызова функции, затем можно выйти return, а потом вернуться icall, Будет работать?
Данной функцией Вы получили указатель на Память Программ и можете делать с ним все что Вам заблагорассудится - читать данные, прыгнуть по этому адресу и т.п.

Цитата(Alex ma @ Nov 17 2006, 00:09) *
PS
_Alex на работе,
Alex ma дома.
Не мое, конечно, дело... Но зачем усложнять жизнь себе и другим? Или есть желание пообщаться с самим собой?)))


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