demiurg_spb 0 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба Написал макросы для работы со стеком... Но я не являюсь спецом по ASM в AVRGCC. Прошу великих Гуру окинуть сие творчество на передмет косяков... И вообще, можно-ли в GCC использовать стек в таком ключе или есть нюансы? // ============================================================================ #define __avr_stack_pop() \ (__extension__({ \ uint8_t __result; \ __asm__ __volatile__ \ ( \ "pop %0" "\n\t" \ : "=r" (__result) \ : \ ); \ __result; \ })) // ============================================================================ #define __avr_stack_push(value) \ (__extension__({ \ uint8_t __value = (uint8_t)value; \ __asm__ __volatile__ \ ( \ "push %0" "\n\t" \ : \ : "r" (__value) \ ); \ })) Тест: #define stack_push __avr_stack_push #define stack_pop __avr_stack_pop unsigned char i = 0; do { stack_push(i); i = stack_pop(); } while (++i<5); Выход: cabe: 80 e0 ldi r24, 0x00; 0 cac0: 8f 93 push r24 cac2: 8f 91 pop r24 cac4: 8f 5f subi r24, 0xFF; 255 cac6: 85 30 cpi r24, 0x05; 5 cac8: d8 f3 brcs .-10 ; 0xcac0 <main+0x2> Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба а для чего вам это надо? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба Парсить удобно... Да ещё была одна задумка, но она похоже накрылсь... Хотел сохранять номер пункта родительского меню для последующего восстановления при возврате - но пока не работает - MCU ресетится... Разбираюсь в чём дело. Если push и pop в одной процедуре - всё ок.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба Если push и pop в одной процедуре - всё ок....Естественно. Потому что в другой процедуре на стек еще положен адрес возврата, локальные переменные, сохраненный SREG. Даже в одной процедуре в теле компилятор может положить на стек временную переменную и вся ваша стройная система рухнет. По макросу: поскольку push изменяет ОЗУ, совсем честно было бы указать memory в списке clobber Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба Естественно. Потому что в другой процедуре на стек еще положен адрес возврата, локальные переменные, сохраненный SREG. Даже в одной процедуре в теле компилятор может положить на стек временную переменную и вся ваша стройная система рухнет. С адресом возврата я согласен. Из Вашей ремарки можно сделать не совсем правильный вывод о том, что компилятор использует лишь стек, а как же куча? Когда она используется? К слову, бывает, что компиляторы разделяют аппаратный стек и программный ибо он быстрее на некоторых системах... Я думаю что и для AVR архитектуры это тоже м.б. разумно... По макросу: поскольку push изменяет ОЗУ, совсем честно было бы указать memory в списке clobber Доработал. Спасибо за совет! // ============================================================================ #define __avr_stack_pop() \ (__extension__({ \ uint8_t __result; \ __asm__ __volatile__ \ ( \ "pop %0" "\n\t" \ : "=r" (__result) \ : \ : "memory" \ ); \ __result; \ })) // ============================================================================ #define __avr_stack_push(value) \ (__extension__({ \ uint8_t __value = (uint8_t)value; \ __asm__ __volatile__ \ ( \ "push %0" "\n\t" \ : \ : "r" (__value) \ : "memory" \ ); \ })) Ещё раз убеждаюсь, что задавать правильные вопросы очень полезно для здоровья:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба С адресом возврата я согласен. Из Вашей ремарки можно сделать не совсем правильный вывод о том, что компилятор использует лишь стек, а как же куча? Когда она используется? Компилятор "сам" использует кучу только в одном случае - в С++ при создании объектов через new. В С кучу использует программист, через вызов функций malloc/free.К слову, бывает, что компиляторы разделяют аппаратный стек и программный ибо он быстрее на некоторых системах... Я думаю что и для AVR архитектуры это тоже м.б. разумно... Да, есть у такого подхода плюсы, есть минусы. В данном случае вы спрашивали по avr-gcc, а у него всего один стек. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба Спасибо за разъяснение. Буду копать под кучу:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 0 6 августа, 2008 Опубликовано 6 августа, 2008 · Жалоба Компилятор "сам" использует кучу только в одном случае - в С++.... В С кучу использует программист, через вызов функций malloc/free. Не совсем так - компилятор-то "сам" не использует, но некоторые вполне сишные библиотечные функции heap вынуждены пользовать - на вскидку strdup(), time()... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 7 августа, 2008 Опубликовано 7 августа, 2008 · Жалоба Не совсем так - компилятор-то "сам" не использует, но некоторые вполне сишные библиотечные функции heap вынуждены пользовать - на вскидку strdup(), time()...Естественно, но это функции, в исходнике которых явно указаны malloc/free. При использовании new компилятор вставляет malloc/free "от себя". Хотя... new тоже пишет программист. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 8 августа, 2008 Опубликовано 8 августа, 2008 · Жалоба Да ещё была одна задумка, но она похоже накрылсь... Хотел сохранять номер пункта родительского меню для последующего восстановления при возврате - но пока не работает - MCU ресетится... А зачем для этого использовать аппаратный стек контроллера? Сделать свой отдельно. Пусть максимум вложенности меню будет MAX_SUBMENU - тогда по сусекам всё равно придётся выделить столько байт на восстановления. Соберём их в одном месте static uint8_t menu_stack[MAX_SUBMENU]; static uint8_t menu_stack_ptr = 0; void push_index( uint8_t index) { if( menu_stack_ptr < MAX_SUBMENU ) menu_stack[ menu_stack_ptr++ ] = index; } uint8_t pop_index() { return menu_stack_ptr ? menu_stack[--menu_stack_ptr] : 0; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 8 августа, 2008 Опубликовано 8 августа, 2008 · Жалоба Именно так я и сделал. Прежде хотелось выпендриться - не вышло:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться