Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAVR-20071221 и AVR Studio 4.13 SP2 Final
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Страницы: 1, 2
Alex_NEMO
WinAVR-20071221 hxxp://sourceforge.net/project/showfiles.php?group_id=68108
Что нового:
  • Added support for these devices: AT90PWM216, AT90PWM316, ATtiny43U, ATtiny48, ATtiny88, AT90PWM2B, AT90PWM3B, ATmega48P, ATmega88P, ATmega168P, ATmega328P, ATmega1284P, ATmega32HVB
  • Binutils 2.18 - New version.
  • GCC 4.2.2 - New version.
  • avr-libc 1.6.0 - New version.
  • avrdude 5.5 - New version.
  • GDB / Insight 6.6 - New version.
  • AVaRICE 2.7 - New version.
  • SRecord 1.37 - New version.


AVR Studio 4.13 SP2(b571) hxxp://www.atmel.com/dyn/resources/prod_documents/AVRStudio4.13SP2.exe
  • ATmega32HVB, ATmega1284P, ATtiny48, ATtiny43U.
  • Full support for the new STK600 starter kit, including programming front-end and command line tools.
  • New devices in Simulator V2: ATmega164P, ATmega324P, ATmega644P, ATmega1284P, ATmega48P, ATmega88P, ATmega168P, ATmega328P, ATmega32HVB, ATtiny48 and ATtiny43U.
  • ELF production file format support.
  • Several enhancements in the IO view.
  • and many more...
aesok
В версию avr-gcc из WinAVR-20071221 добавлены два новых атрибута:

Функция с атрибутом 'OS_task' не сохраняет "call-saved" регистры (r2-r15, r28-r29 ), что уменьшает код функции и сокращает использование стека. Эта функция должна вызываться только из aссемблерного кода. Используйте этот атрибут для 'task' функций в RTOS.

Функция с атрибутом 'OS_main' имеет более оптимизированный пролог чем Функция с атрибутом 'OS_task', но накладывает дополнительное ограничение что прерывания должны быть запрещены при вызове этой функции. Используйте этот атрибут для функции 'main'. Но если прерывания разрешены до вызова функции 'main', то используйте с ней атрибут 'OS_task'.

Анатолий.
haker_fox
Судя по дате, продукт недавний. Как у него на счет стабильности?

Цитата(aesok @ Dec 22 2007, 05:07) *
Функция с атрибутом 'OS_task' не сохраняет "call-saved" регистры (r2-r15, r28-r29 ), что уменьшает код функции и сокращает использование стека. Эта функция должна вызываться только из aссемблерного кода. Используйте этот атрибут для 'task' функций в RTOS.

Т.е. если я использую, например scmRTOS, то все функции-процессы можно объявлять с атрибутом OS_task?
sla000
Кроме того добавлена поддержка языка Ада.
Кто шарит, отпишитесь плз работает - нет. А то в комплекте примеров на Аде не поставляется.
ReAl
Цитата(aesok @ Dec 21 2007, 23:07) *
Функция с атрибутом 'OS_task' не сохраняет "call-saved" регистры (r2-r15, r28-r29 ),
Как этот атрибут соотносится с __noreturn__ ? В смысле в чём отличие?
Я в avr-gcc порте scmRTOS для OS_PROCESS и для OS::Run() просто дал атрибут __noretrun__ и вроде бы всё нормально. Регистры не сохраняются, стек даром не расходуется.
Заодно проверка компилятором - сообщение об ощибке, если вдруг нечаянно устроил возврат из главной функции процесса, по кр. мере в scmRTOS это делать нельзя и дополнительная помощь со стороны компилятора не помешает.
aesok
Цитата(haker_fox @ Dec 22 2007, 03:55) *
Судя по дате, продукт недавний. Как у него на счет стабильности?
Т.е. если я использую, например scmRTOS, то все функции-процессы можно объявлять с атрибутом OS_task?


Скорее всего да, но я не работал с scmRTOS, а глянув на исходники не нашeл там порта на GCC. общее правило такое, если код вызывающий функцию-процесс не расчитывает на то что регистры r2-r15, r28-r29 сохранят свое значение после возврата из этой функции, то эту функция можно объявлять с атрибутом 'OS_task'.
ReAl
Цитата(aesok @ Dec 22 2007, 12:32) *
Скорее всего да, но я не работал с scmRTOS, а глянув на исходники не нашeл там порта на GCC.

Он там пока в репозитории в branches/avreal лежит. Нужно ещё очень внимательно проверить. Но пользоваться уже можно.
Да её и раньше портировали "частным порядком", там немного работы.

Цитата
общее правило такое, если код вызывающий функцию-процесс не расчитывает на то что регистры r2-r15, r28-r29 сохранят свое значение после возврата из этой функции, то эту функция можно объявлять с атрибутом 'OS_task'.
И всё же как по моему вопросу - соотношению атрибутов OS_task и noreturn ?

Правильно ли я понимаю, что OS_task это старый добрый noreturn минус подавление генерации команды ret и проверка компилятором построения функции как действительно никогад не возвращающей управления?

Похоже, что для процессов scmRTOS правильнее применять noreturn, а OS_task оставить для тех ОС, в которых процесс может прекратить существование путём возврата из основной функции процесса.
aesok
Цитата(ReAl @ Dec 22 2007, 15:00) *
И всё же как по моему вопросу - соотношению атрибутов OS_task и noreturn ?

Правильно ли я понимаю, что OS_task это старый добрый noreturn минус подавление генерации команды ret и проверка компилятором построения функции как действительно никогад не возвращающей управления?


Я перичитал описание атрибута 'noreturn' - основное его предназначение позволить компилятору оптимизировать вызывающию функцию, и не генерировать в ней код после вызова функции с атрибутом 'noreturn'. Как компилятор должен/может оптимизировать саму функцию к которой применен атрибут 'noreturn' надо посмотреть.

Атрибут "OS_task" (OS_main) заставляет компилятор генерировать специальные версии пролога и эпилога для указанной функции. Эта функция перестает соответствовать соглашениям о вызове функций в С, и не должна вызываться из С кода.

Цитата
Похоже, что для процессов scmRTOS правильнее применять noreturn, а OS_task оставить для тех ОС, в которых процесс может прекратить существование путём возврата из основной функции процесса.


'noreturn' ничего не даст кроме предупреждения компилятора, если функция функция всетаки возвращает управление. Компилятор не сможет оптимизировать вызывающий код, он же написан в ассемблере. Для функции с OS_task генерируються более эффективные пролог и эпилог, если функция не не возвращается, то эпилог не генерируеться.

Анатолий.

PS: Для тех кто не знаком с терминами пролог и эпилог:

пролог - код выполняемый до начала тала функции, сохраняет 'call-saved' реистры и выделяет место в стеке для локальных переменных.

эпилог - код выполняемый после тала функции, востанавливает 'call-saved' реистры, освобождает место в стеке выделеное в прологе и выполняет команду 'RET'.


Анатолий.
aesok
Цитата(aesok @ Dec 22 2007, 15:25) *
Цитата

И всё же как по моему вопросу - соотношению атрибутов OS_task и noreturn ?

Правильно ли я понимаю, что OS_task это старый добрый noreturn минус подавление генерации > команды ret и проверка компилятором построения функции как действительно никогад не возвращающей управления?


Я перичитал описание атрибута 'noreturn' - основное его предназначение позволить компилятору оптимизировать вызывающию функцию, и не генерировать в ней код после вызова функции с атрибутом 'noreturn'. Как компилятор должен/может оптимизировать саму функцию к которой применен атрибут 'noreturn' надо посмотреть.



Разница между "noreturn' и 'OS_task' есть: первый предотвращает сохранение регстров r2-r15, второй дополнительно r28-r29. Ну и само сабой 'OS_task' работает для всех функций, вне зависимости от того возвращают они управление или нет.

Анатолий.
Сергей Борщ
Есть еще вопрос по "noreturn" с main() в режиме С++. Как известно, main() в С++ должна быть объявлена как возвращающая int. Если к ней добавить "noreturn", то появляется warning:
main.cpp:68: warning: function declared 'noreturn' has a 'return' statement
хотя никаких return statement в функции нет, из for(;;) {} выхода тоже не сущствует, и никаких ret в листинге нет. Это бага?
ReAl
Цитата(aesok @ Dec 22 2007, 14:25) *
'noreturn' ничего не даст кроме предупреждения компилятора, если функция функция всетаки возвращает управление.
Ну и на том спасибо :-), я стараюсь, чтобы предупреждений не было вообще и при таком подходе даже просто выдать предупреждение - уже помощь компилятора.

Цитата(aesok @ Dec 22 2007, 22:05) *
Разница между "noreturn' и 'OS_task' есть: первый предотвращает сохранение регстров r2-r15, второй дополнительно r28-r29. Ну и само сабой 'OS_task' работает для всех функций, вне зависимости от того возвращают они управление или нет.
Я немного поэкспериментировал, для avr-gcc 4.2.2 (WinAVR-20071221) для функции, помеченной этими атрибутами, различие действительно такое (для noreturn добавляется сохранение r28,r29 в начале пролога, если же организовать возврат из функции, то и в конце эпилога) а вот 4.3.0 (сборка klen http://electronix.ru/forum/index.php?showtopic=38876) генерирует абсолютно одинаковый код для этих двух атрибутов (видать какой-то патч с winavr.cvs.sourceforge... недотащен был).
Более ранние компиляторы, естетсвенно, вообще OS_task не знают. Так что я пока оставлю как есть, с noreturn, а там посмотрим, добавлю проверку версии компилятора и в зависимости от этого изменение #define OS_PROCESS на атрибут noreturn или OS_task.


Цитата(Сергей Борщ @ Dec 23 2007, 00:57) *
Есть еще вопрос по "noreturn" с main() в режиме С++. Как известно, main() в С++ должна быть объявлена как возвращающая int. Если к ней добавить "noreturn", то появляется warning:
main.cpp:68: warning: function declared 'noreturn' has a 'return' statement
хотя никаких return statement в функции нет, из for(;;) {} выхода тоже не сущствует, и никаких ret в листинге нет. Это бага?

return 0; перед закрывающей скобкой '}' в main() в С++ присутствует неявно, если его не написал программист.
В стандарте написано:
Цитата
3.6.1 Main function
...
5 A return statement in main has the effect of leaving the main function (destroying any objects with automatic storage duration) and calling exit with the return value as the argument. If control reaches the end of main without encountering a return statement, the effect is that of executing
return 0;

А в "полновесном" С++ управление на закрывающую скобку main() может перейти и при бесконечном цикле, и при noreturn-функции (о которых стандарт вообще ничего не знает) - за счёт исключения. Поэтому return 0; всегда неявно присутствует для С++ - программы.
Есть ли смысл делать в avr-gcc какой-то особый подход - я не уверен. Да, он всё равно не поддерживает исключения и за бесконечный цикл в main() не попасть никак, но "генерация" неявного retrun 0; и упомянутого предупреждения происходит, как я понимаю, на платформо-независимых этапах компиялции.
А потом оптимизатор выбрасывает это как unreachable code, но это потом :-)
Сергей Борщ
Цитата(ReAl @ Dec 23 2007, 09:13) *
но "генерация" неявного retrun 0; и упомянутого предупреждения происходит, как я понимаю, на платформо-независимых этапах компиялции.
А потом оптимизатор выбрасывает это как unreachable code, но это потом :-)
Я понятия не имею, как оно работает внутри sad.gif . Я снаружи лишь вижу warning, лезу в листинг и не нахожу там никакого ret на который выдано предупреждение. Это несколько, хм... смущает.
_Алекс
Не могу второй день скачать сервис пак AVR Studio 4.13 SP2, это только у меня или у всех
designer
Нормально скачалось.
aesok
Цитата(ReAl @ Dec 23 2007, 10:13) *
Более ранние компиляторы, естетсвенно, вообще OS_task не знают. Так что я пока оставлю как есть, с noreturn, а там посмотрим, добавлю проверку версии компилятора и в зависимости от этого изменение #define OS_PROCESS на атрибут noreturn или OS_task.


Используйте оба этих атрибута: 'noreturn' - для генерации предупреждений а "OS_task" для экономии кода и стека.

Анатолий.
733259
А чем OS_main отличается от __attribute__((naked))? Всегда применяю для main и никаких warning-ов и лишнего кода.
aesok
Цитата(733259 @ Dec 24 2007, 21:49) *
А чем OS_main отличается от __attribute__((naked))? Всегда применяю для main и никаких warning-ов и лишнего кода.


Дело в том что атрибут 'naked' выкидывает не только лишний но и нужный код.

Анатолий.
733259
Цитата(aesok @ Dec 25 2007, 02:39) *
Дело в том что атрибут 'naked' выкидывает не только лишний но и нужный код.
Выкидывает, но только не в main - там пролог и эпилог не нужны.
Qwertty
Цитата(733259 @ Dec 25 2007, 07:29) *
Выкидывает, но только не в main - там пролог и эпилог не нужны.

Я вот тоже попробовал naked, и прошло нормально. Но в мэйне не должно быть локальных переменных.
733259
Цитата
Я вот тоже попробовал naked, и прошло нормально. Но в мэйне не должно быть локальных переменных.
А можно подробнее? У меня постоянно в main локальные переменные, обычно static правда, хотя точно не уверен т.к.

int main() __attribute__((naked));
int main(){

у меня вооще везде, стереотип выработался.
Qwertty
Цитата(733259 @ Dec 25 2007, 08:48) *
А можно подробнее? У меня постоянно в main локальные переменные, обычно static правда, хотя точно не уверен т.к.

int main() __attribute__((naked));
int main(){

у меня вооще везде, стереотип выработался.

static - не локальная!! Это глобальная переменная с ограниченной областью видимости.
733259
Цитата(Qwertty @ Dec 25 2007, 10:58) *
static - не локальная!! Это глобальная переменная с ограниченной областью видимости.
Это я знаю, какие траблы с локальными переменными main? Я не заметил никаких, вот и спрашиваю.
Qwertty
Цитата(733259 @ Dec 25 2007, 09:13) *
Это я знаю, какие траблы с локальными переменными main? Я не заметил никаких, вот и спрашиваю.

Так они в прологе создаются и инициализируются. А naked пролог выкидывает
733259
Согласен, только чем отличается переменная static от локальной в main, ведь эта, локальная, всё равно всегда существует вместе с main.

ЗЫ: скачал, под wine работает безупречно. Не заметил разницы между naked и OS_main на примере, специально объявил uint16_t array[64] в main. Бинарник совпадает до байта.
К сожалению реальный код, как и в предыдущих версиях, больше чем у 3.3.6, 3660 байт против 3274 в одном из моих проектов. Жаль.
Qwertty
Цитата(733259 @ Dec 25 2007, 10:09) *
Согласен, только чем отличается переменная static от локальной в main, ведь эта, локальная, всё равно всегда существует вместе с main.

Различие в том, где она создается. Локальная - в прологе мэйна. Static - в секции bss, если не ошибаюсь.
Цитата(733259 @ Dec 25 2007, 10:09) *
ЗЫ: скачал, под wine работает безупречно. Не заметил разницы между naked и OS_main на примере, специально объявил uint16_t array[64] в main. Бинарник совпадает до байта.
К сожалению реальный код, как и в предыдущих версиях, больше чем у 3.3.6, 3660 байт против 3274 в одном из моих проектов. Жаль.

А массивы вроде локальными не бывают, они всегда static, даже если объявлены локальными. Это сразу видно по использованию ОЗУ, массив сразу увеличивает использованное ОЗУ, а простые локальные переменные не увеличивают.
aesok
Цитата(733259 @ Dec 25 2007, 10:09) *
ЗЫ: скачал, под wine работает безупречно. Не заметил разницы между naked и OS_main на примере, специально объявил uint16_t array[64] в main. Бинарник совпадает до байта.
К сожалению реальный код, как и в предыдущих версиях, больше чем у 3.3.6, 3660 байт против 3274 в одном из моих проектов. Жаль.


НУ СКОЛЬКО РАЗ ВАМ МОЖНО ПОВТОРЯТЬ. Что место в для локадьных переменных в стеке выделяеться в прологе функции. Применениие атрибута 'naked' выкидывает код пролога и эпилога из функции! Это значит что место для локальных переменных не будет выделено!!!!

Анатолий.
733259
Цитата
Различие в том, где она создается. Локальная - в прологе мэйна. Static - в секции bss, если не ошибаюсь.
Знаю, я имел в виду их использование в програме (в main) одинаковое, если есть существенные различия, укажите.
Цитата
А массивы вроде локальными не бывают, они всегда static, даже если объявлены локальными.
Но указатель стека в прологе main устанавливается в зависимости от. Правда это в 3.3.6, в 4.2.2 еще не проверил.
Цитата
НУ СКОЛЬКО РАЗ ВАМ МОЖНО ПОВТОРЯТЬ. Что место в для локадьных переменных в стеке выделяеться в прологе функции.
Да ясно всё. Я полагаю, что без пролога в main можно прекрасно обойтись, я всегда обходился, во всяком случае. Локальные переменные в main, не static, какой-то очень частный случай, ИМХО.
aesok
Цитата(733259 @ Dec 25 2007, 13:18) *
Да ясно всё. Я полагаю, что без пролога в main можно прекрасно обойтись, я всегда обходился, во всяком случае. Локальные переменные в main, не static, какой-то очень частный случай, ИМХО.


Компилятор может создать код, которому требуеться место в стеке, даже тогда, когда вы не создавали локальных переменных.

Я постараюсь вечером найти пример.

Анатолий.
ivainc1789
Посмотрите, плиз, во втором сервис-паке Студии переделали окно программатора и по-моему, кнопка "чтение EEPROM в симулятор" не работает. Проверял как с Драконом так и с AvrUSB500. Баг или я что-то делаю не так?
Visor
Беда какая-то, при старте отладки проекта WinAVR, AVR Studio аварийно закрывается.
AVR Studio 4.13.557 SP1 + WinAVR-20071221
В чём может быть причина?
singlskv
Цитата(733259 @ Dec 25 2007, 07:29) *
Выкидывает, но только не в main - там пролог и эпилог не нужны.

Цитата(733259 @ Dec 25 2007, 09:13) *
Это я знаю, какие траблы с локальными переменными main? Я не заметил никаких, вот и спрашиваю.

Перечитайте основы, начать лучше всего с K&R.

Ну а если повторное самообразование не поможет, то ждем от Вас
скомпилированных примеров по таким исходникам:
Код
Ваш вариант:
int main() __attribute__((naked));
int main()
{
  unsigned char arr[10];
  unsigned char i;


  for (i=0;i<10;i++) arr[i]=i;
  
  while (1);
  return 0;
}


Код
Правильный вариант:
int main()
{
  unsigned char arr[10];
  unsigned char i;


  for (i=0;i<10;i++) arr[i]=i;
  
  while (1);
  return 0;
}

Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно...
Сергей Борщ
Цитата(singlskv @ Dec 26 2007, 21:35) *
Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно...
В обоих неправильно biggrin.gif biggrin.gif Значение i не определено в обоих случаях, содержимое массивов будет одинаково-случайным. Ошибка проявится, если после заполнения массива вызвать какую-либо функцию. В этом случае при (naked) содержимое массива (и i) будет испорчено стеком вызванной функции.
singlskv
Цитата(Сергей Борщ @ Dec 26 2007, 22:41) *
В обоих неправильно biggrin.gif biggrin.gif Значение i не определено в обоих случаях,

Я надеюсь что Вы таки пошутили насчет неопределенности i smile.gif
(оно там от 0 до 9 считается)
ну и это всего лишь был минимальный пример приведен, без копирования в память с постоянным
адресом...
Сергей Борщ
Цитата(singlskv @ Dec 26 2007, 21:52) *
Я надеюсь что Вы таки пошутили насчет неопределенности i smile.gif
(оно там от 0 до 9 считается)
Посыпаю голову окурками. Действительно, глаз замылился. Уже привык в плюсах объявлять переменную прямо в цикле. Тогда оба примера будут работать одинаково, ибо указатель стека проинициализирован, и нет ничего, что могло бы содержимое массива испортить. Но первый же вызов функции порушит все.
P.S. Я просто на это уже нарывался - тоже в погоне за кодом сделал main() naked и потом разбирался, почему же все перестало работать.


Для aesok: Наткнулся на такую особенность: если в программе активно используются inline - функции, некоторые из них не встраиваются, даже если просто содержат вызов другой функции (т.е. при встраивании должны соптимизироваться совсем). Добавив -Winline получаю сообщение, что достигнут лимит --param max-inline-insns-single. В документации на gcc сказано, что по умолчанию этот параметр устанавливается в 300 (600/2) "морковок" (неких внутренних единиц измерения). Установка его через командную строку равным хотя бы 30 приводит к встраиванию всех inline функций в моем проекте. Какое же значение этот параметр имеет по умолчанию в действительности? Понимаю, что вопрос скорее не к вам, ибо аналогичное поведение демонстрирует и arm-elf-gcc, но поскольку вы более глубоко "погружены" в это, может подскажете - это я что-то неправильно понял или ошибка в документации?
733259
Цитата
Хотелось бы от Вас услышать в каком варианте массив будет заполнен правильно...
Хотелось бы получать от Вас хотя бы немного проверенный код.
avr-gcc 4.2.2 ( WinAVR 20071221) Ваш цикл массив и пролог полностью выкидывает
Код
int main(){
  62:    ff cf           rjmp    .-2      ; 0x62 <main>

00000064 <_exit>:
  64:    ff cf           rjmp    .-2      ; 0x64 <_exit>
А вообще-то, если бы мне захотелось объявить массив в main я сделал бы его static, пролог в этом случае не нужен. По прежнему жду аргументов в пользу локальных (не static) переменных в main (не в блоке).
А вооще-то если бы мне запонадобилось заполнить Ваш массив, я бы написал
Код
int main() __attribute__((naked));
int main(){

  static unsigned char arr[10];

  {
  unsigned char i;
  unsigned char * point = arr + sizeof(arr);

  for (i = sizeof(arr) - 1; i > 0; i--) *--point = i;
  *--point = i;
  }

  while (1);
  return 0;
}
В случае 4.2.2 naked (как и OS_main)не обязательно, компилер выкидывает пролог самостоятельно.
singlskv
Цитата(Сергей Борщ @ Dec 27 2007, 04:52) *
Тогда оба примера будут работать одинаково, ибо указатель стека проинициализирован, и нет ничего, что могло бы содержимое массива испортить. Но первый же вызов функции порушит все.
Не, не одинаково.
Правда я до сих пор пользуюсь 20060421.
Код с naked:
Код
@00000051: main
6:        {
+00000051:   E080        LDI     R24,0x00         Load immediate
+00000052:   01FE        MOVW    R30,R28          Copy register pair
+00000053:   9631        ADIW    R30,0x01         Add immediate to word
+00000054:   9381        ST      Z+,R24           Store indirect and postincrement
+00000055:   5F8F        SUBI    R24,0xFF         Subtract immediate
+00000056:   308A        CPI     R24,0x0A         Compare with immediate
+00000057:   F3E0        BRCS    PC-0x03          Branch if carry set
13:         while (1);
+00000058:   CFFF        RJMP    PC-0x0000        Relative jump
+00000059:   5F8F        SUBI    R24,0xFF         Subtract immediate
+0000005A:   308A        CPI     R24,0x0A         Compare with immediate
+0000005B:   F3E0        BRCS    PC-0x03          Branch if carry set
+0000005C:   CFFF        RJMP    PC-0x0000        Relative jump

Код без naked:
Код
@00000051: main
6:        {
+00000051:   EFC5        LDI     R28,0xF5         Load immediate
+00000052:   E0D4        LDI     R29,0x04         Load immediate
+00000053:   BFDE        OUT     0x3E,R29         Out to I/O location
+00000054:   BFCD        OUT     0x3D,R28         Out to I/O location
11:         for (i=0;i<10;i++) arr[i]=i;
+00000055:   E080        LDI     R24,0x00         Load immediate
+00000056:   01FE        MOVW    R30,R28          Copy register pair
+00000057:   9631        ADIW    R30,0x01         Add immediate to word
+00000058:   9381        ST      Z+,R24           Store indirect and postincrement
+00000059:   5F8F        SUBI    R24,0xFF         Subtract immediate
+0000005A:   308A        CPI     R24,0x0A         Compare with immediate
+0000005B:   F3E0        BRCS    PC-0x03          Branch if carry set
13:         while (1);
+0000005C:   CFFF        RJMP    PC-0x0000        Relative jump

на входе main r29:r28 содержит адрес стека.
Как видно из рисунка, код одинаков за исключением того, что в коде с
naked забыли отвести память под массив на стеке.
В результате код с naked будет пытаться заполнять несуществующую память.

Цитата(733259 @ Dec 27 2007, 05:03) *
Хотелось бы получать от Вас хотя бы немного проверенный код.
avr-gcc 4.2.2 ( WinAVR 20071221) Ваш цикл массив и пролог полностью выкидывает
Он проверен на 20060421.
На 20071221 добавьте какую-нить глобальную volatile переменную
volatile unsigned char a;
и перед while(1) напишите a=arr[5];
Цитата
По прежнему жду аргументов в пользу локальных (не static) переменных в main (не в блоке).

Вам уже сказали что static это глобальный массив с ограниченной видимостью.
А если Вам будет нужен временный массив для рассчетов, вы его тоже static объявите ?
Наверное в Ваших микроконтроллерах очень много лишней памяти...
Сергей Борщ
Цитата(733259 @ Dec 27 2007, 04:03) *
По прежнему жду аргументов в пользу локальных (не static) переменных в main (не в блоке).
Ну, объявление автоматических локальных переменных в любой функции - наиболее естественное действие. Это дает свободу компилятору размещать их в удобном для него месте - на стеке или в регистрах. Хотелось бы услышать от вас аргументы в пользу объявления локальных переменных статическими именно в main(). Основное отличие статических переменных от автоматических - сохранение их значения между вызовами функций. Но main() вызывается лишь однажды, поэтому сохранение значения _между_ вызовами теряет смысл. Так в чем же смысл делать локальные переменные main() статическими?


Цитата(singlskv @ Dec 27 2007, 13:55) *
Не, не одинаково.
Какая оптимизация используется? Выкидывание кода вполне справедливо. А вы попробуйте в конце цикла суммировать элементы массива и заносить результат в глобальную переменную. И включите какое-нибудь прерывание, например от таймера. Тут-то уж точно глюк будет воспроизведен 100%.
aesok
Цитата(Сергей Борщ @ Dec 27 2007, 04:52) *
Для aesok: Наткнулся на такую особенность: если в программе активно используются inline - функции, некоторые из них не встраиваются, даже если просто содержат вызов другой функции (т.е. при встраивании должны соптимизироваться совсем)....


Я не разбирался с inline подробно.

Анатолий.
733259
Цитата
Он проверен на 20060421.
Мы обсуждаем здесь конкретную версию 20071221 и её фишки и глюки, а не основы C.
Цитата
На 20071221 добавьте какую-нить глобальную volatile переменную
Вообще-то что-то подобное Вам стоило добавить в свой код.
Цитата
Вам уже сказали что static это глобальный массив с ограниченной видимостью.
Так это мне и без того известно.
Цитата
А если Вам будет нужен временный массив для рассчетов, вы его тоже static объявите ?
Нет, но и прямо в main не стану.

Цитата
Но main() вызывается лишь однажды, поэтому сохранение значения _между_ вызовами теряет смысл.
Вот и я про то же, и те и другие используются одинаково.
Цитата
Так в чем же смысл делать локальные переменные main() статическими?
В 3.4.6 - избавится от не нужного пролога. Ну и вооще как правило приходится писать эфективный, а не наглядный код, не гигагерцный пень же.
singlskv
Цитата(Сергей Борщ @ Dec 27 2007, 15:34) *
Какая оптимизация используется?
-Os
Цитата
Выкидывание кода вполне справедливо. А вы попробуйте в конце цикла суммировать элементы массива и заносить результат в глобальную переменную. И включите какое-нибудь прерывание, например от таймера. Тут-то уж точно глюк будет воспроизведен 100%.
Дык в 20060421 оно и так с naked глючит т.к. массив в такой ситуации в нем не выкидывается.


Цитата(733259 @ Dec 27 2007, 16:21) *
Мы обсуждаем здесь конкретную версию 20071221 и её фишки и глюки, а не основы C.

Атлична, вот Вам код написанный по Вашим правилам:
Код
volatile unsigned long a=1;
volatile unsigned long arr[8];

int main() __attribute__((naked));
int main()
{

  {
    unsigned int i;
    unsigned long a1,a2,a3,a4,a5,a6,a7,a8;

    a1 = a + 1;
    a2 = a + 2;
    a3 = a + 3;
    a4 = a + 4;
    a5 = a + 5;
    a6 = a + 6;
    a7 = a + 7;
    a8 = a + 8;

    arr[0] = a1;
    arr[1] = a2;
    arr[2] = a3;
    arr[3] = a4;
    arr[4] = a5;
    arr[5] = a6;
    arr[6] = a7;
    arr[7] = a8;
  
    a = 0;

    for (i=0;i<10;i++) a+=arr[i];
  }

  while (1);
  return 0;

}
Массив вынес в глобальные и сделал volatile, т.к. он будет использоваться в прерывании...
Откомпилируйте его на 20071221 с опцией -Os и расскажите какой будет результат в
переменной "a" когда дойдем до бесконечного цикла.
733259
Цитата
Дык в 20060421 оно и так с naked глючит т.к. массив в такой ситуации в нем не выкидывается.
Вы вместо 20060421 версию скажите - ('avr-gcc -v'), похоже у Вас вооще трёшка.
singlskv
Цитата(733259 @ Dec 27 2007, 19:56) *
Вы вместо 20060421 версию скажите - ('avr-gcc -v'), похоже у Вас вооще трёшка.
это 3.4.6
Жду результата проверки последнего примера на 2007...
733259
Ааа, переменные не влазят. Однозначно признак плохого дизайна. В данном случае легко обходится простой перестановкой строк
Код
    a1 = a + 1;
    arr[0] = a1;
    a2 = a + 2;
    arr[1] = a2;
Но, да готов согласится - еще одна ситуация, где naked не допустим, кроме локальных переменных.
aesok
Вот минимальный нерабочий пример:
Код
__attribute__ ((naked))
int main(void)
{
  volatile int i;

  i++;
}

Перременая 'i' объявлена с модификатором "volatile", для того чтобы запретить оптимизатору разместить ее в регистах.

Вот код который генерируеться для этой функции:
Код
@0000004D: main
---- demo.c ---------------------------------------------------------------------------------------
3:        {
+0000004D:   8189        LDD     R24,Y+1          Load indirect with displacement
+0000004E:   819A        LDD     R25,Y+2          Load indirect with displacement
+0000004F:   9601        ADIW    R24,0x01         Add immediate to word
+00000050:   839A        STD     Y+2,R25          Store indirect with displacement
+00000051:   8389        STD     Y+1,R24          Store indirect with displacement
7:        }
+00000052:   CFFF        RJMP    PC-0x0000        Relative jump

Здесь происходит обращение к памяти по адресам [Y+1..Y+2] (это переменная 'i'), но регистр Y не инициализирован! Регистр Y это frame-pointer (указатель локального фрейма) , или указатель на область памяти где расположены локальные переменные. Выкинув пролог функции, вы выкинули и инициализацию frame-pointer-а.

Еще раз!!! если в вашей функции 'main', для нее задан атрибут 'naked' и в ней есть локальные переменные то она будет работать только в том случае, если оптимизатор разместит все эти перемене в регистрах, и не будет использовать для их хранения локальный фрейм. Деже если сегодня ваша функция 'main' сейчас работает, вы можете гарантировать соблюдения этих условий при развитии проекта и внесении изменений в 'main'? НЕТ!!!

Вы предлагаете объявлять все переменные в 'main' как static, но это тоже не дает вам 100% гарантий. Компилятор может сам создать локальные переменные для личных нужд.


Анатолий.
733259
Цитата
Вы предлагаете объявлять все переменные в 'main' как static, но это тоже не дает вам 100% гарантий. Компилятор может сам создать локальные переменные для личных нужд.
Ничего подобного я не предлагаю.
Я говорю о реальной практике, а не теоретических примерах. Переменная volatile может понадобится, чтобы в нее писали обработчики прерываний и т.п. Стало быть однозначно - глобальная. Мне трудно представить _реальную_ иную ситуацию.
Цитата
Деже если сегодня ваша функция 'main' сейчас работает, вы можете гарантировать соблюдения этих условий при развитии проекта и внесении изменений в 'main'? НЕТ!!!
И что помешает мне поставить // ? Я говорю только, что naked - хорошая практика. На выше перечисленные ситуации не разу не натыкался - если завожу переменную в main, т.е. всё равно всегда существующую, хоть и локальную (теоретически) - static. Переполнять регистры и потом гонять данные в стек и обратно тоже никакого желания, про volatile уже сказал. Так что и дальше буду использовать naked.
aesok
Цитата(733259 @ Dec 27 2007, 22:07) *
И что помешает мне поставить //

Ничего не помешает, только перед тем как вы догадаетесь что это нужно сделать, вы поимеете секса со своей програмой через дебагер. Хотите учиться на своих ошибках учитесь, только ПОЖАЛУЙСТА никому не советуйте использовать "naked" c функцией main.

Анатолий.
singlskv
Цитата(aesok @ Dec 27 2007, 21:47) *
Здесь происходит обращение к памяти по адресам [Y+1..Y+2] (это переменная 'i'), но регистр Y не инициализирован!

ИМХО, все-таки Y инициализирован и именно значением == SP
или я не прав и это не всегда так ?
733259
Цитата
Ничего не помешает, только перед тем как вы догадаетесь что это нужно сделать, вы поимеете секса со своей програмой через дебагер. Хтите учиться на своих ошибках учитесь, только ПОЖАЛУЙСТА никому не советуйте использовать "naked" c функцией main.
Думаю моментально догадаюсь biggrin.gif Гораздо чаще приходится сталкиваться с наездом стека на данные при возникновении прерывания во время вызова вложеных функций.
singlskv
Цитата(733259 @ Dec 27 2007, 22:07) *
Я говорю о реальной практике, а не теоретических примерах.
Так что и дальше буду использовать naked.
В принципе, если у Вас есть разрешение на ношение огнестрельного оружия,
Вы можете поиграть и в "русскую рулетку" и никто Вам не помешает...
Тока имейте в виду что это можно делать только до 11 вечера или после 6 утра
чтобы не мешать соседям...
733259
А по теме - кто нибудь использует avr-gcc четвёрку? А то я как посмотрел во что 20071221 превратил строчку "for (i=0;i<10;i++) a+=arr[i];" (правда и так достаточно безобразную), то прямо ужаснулся. Но может я чо не понимаю?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.