реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Ошибка при отладке в AVR Studio маленького макроса
_Алекс
сообщение Nov 16 2006, 07:56
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 252
Регистрация: 14-09-06
Пользователь №: 20 377



Была задача получить текущий адрес выполнения программы – программный счетчик 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();
}
};
Go to the top of the page
 
+Quote Post
_Bill
сообщение Nov 16 2006, 09:43
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(_Алекс @ 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;


Сообщение отредактировал _Bill - Nov 16 2006, 09:47
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 16 2006, 12:15
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(_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          }


--------------------
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 16 2006, 13:38
Сообщение #4


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



prottoss, Вы получили таким образом значение SP, а никак не PC, как требовалось.
Очевидно, что после выталкивания двух байт из стека, их надо затолкать обратно, а копию в r16, r17 вернуть из подпрограммы.
Либо как в Вашем случае привести SP к типу указателя на int и взять по нему значение (с прединкрементом по-моему).
В любом случае эту операцию надо делать атомарно (непрерываемо).
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 16 2006, 14:01
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(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


--------------------
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 16 2006, 14:39
Сообщение #6


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата
Была задача получить текущий адрес выполнения программы – программный счетчик PC.

SP указывает на место куда в следующий раз будет сохранён байт (pop) или адрес (call).
Поэтому надо модифицировать SP (чтобы он указывал на место в стеке, где лежит сохранённый адрес) и после этого РАЗЫМЕНОВАТЬ его, т. е. взять значение, лежащее в стеке (а не в SP и уж тем более, не во __flash).
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 16 2006, 14:58
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(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          }


--------------------
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 16 2006, 15:05
Сообщение #8


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(prottoss @ Nov 16 2006, 16:58) *
А что по поводу вот такого варианта?

Это и имелось в виду, только среды под рукой не было, чтобы проверить.
PS: атомарность всё-таки необходима. Это можно обеспечить словом __monitor перед определением функции.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 16 2006, 15:13
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(IgorKossak @ Nov 16 2006, 22:05) *
Цитата(prottoss @ Nov 16 2006, 16:58) *

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

Это и имелось в виду, только среды под рукой не было, чтобы проверить.
PS: атомарность всё-таки необходима. Это можно обеспечить словом __monitor перед определением функции.
Зачем защищаться от прерываний? Мы ничего опасного не делаем, и сколько бы прерываний не использовались, ежели они "правильные" (т.е. никаких выкрутасов с памятью данных не выделывают) мы получим то самое значение, которое хотим... Или я опять не догнал чегойто?


--------------------
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 16 2006, 15:19
Сообщение #10


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Согласен, сказались предрассудки при работе с другими ресурсами внутренней периферии.
Go to the top of the page
 
+Quote Post
Alex ma
сообщение Nov 16 2006, 17:09
Сообщение #11


Частый гость
**

Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445



Получилось вот так
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 дома.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Nov 16 2006, 17:37
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



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

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


--------------------
Go to the top of the page
 
+Quote Post
Alex ma
сообщение Nov 16 2006, 18:18
Сообщение #13


Частый гость
**

Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445



Цитата(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, спросить не у кого пароля нет, вот и зарегистрировался второй раз.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 16:43
Рейтинг@Mail.ru


Страница сгенерированна за 0.01484 секунд с 7
ELECTRONIX ©2004-2016