|
|
  |
Ошибка при отладке в AVR Studio маленького макроса |
|
|
|
Nov 16 2006, 07:56
|
Местный
  
Группа: Свой
Сообщений: 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(); } };
|
|
|
|
|
Nov 16 2006, 09:43
|
Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Nov 16 2006, 12:15
|

Гуру
     
Группа: Свой
Сообщений: 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 }
--------------------
|
|
|
|
|
Nov 16 2006, 14:01
|

Гуру
     
Группа: Свой
Сообщений: 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
--------------------
|
|
|
|
|
Nov 16 2006, 14:58
|

Гуру
     
Группа: Свой
Сообщений: 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 }
--------------------
|
|
|
|
|
Nov 16 2006, 17:09
|
Частый гость
 
Группа: Новичок
Сообщений: 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 дома.
|
|
|
|
|
Nov 16 2006, 17:37
|

Гуру
     
Группа: Свой
Сообщений: 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 дома. Не мое, конечно, дело... Но зачем усложнять жизнь себе и другим? Или есть желание пообщаться с самим собой?)))
--------------------
|
|
|
|
|
Nov 16 2006, 18:18
|
Частый гость
 
Группа: Новичок
Сообщений: 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, спросить не у кого пароля нет, вот и зарегистрировался второй раз.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|