Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR AVR - когда вредна оптимизация...
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Alechin
Убил несколько часов на выключение WDT в Mega88 в программе на Си.
Вот такой код
__watchdog_reset();
MCUSR &= ~(1 << WDRF);
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0x00;
IAR при оптимизации умудрился разбить на процедуры (cross call), в результате чего между последовательными записями в WDTCSR проходило более 4 тактов, и выключенный изначально WDT включался, не давая нормально загрузиться системе.
Побороть смог только вынеся данный код в процедуру с выключением оптимизации для нее (#pragme optimize=none).
Возник вопрос - ни какими ключевыми словами нельзя изменить уровень оптимизации для фрагмента кода С ВОЗВРАТОМ к текущему уровню оптимизации (через #pragma optimize можно только установить требуемый уровень оптимизации, но не вернуться к установленному в свойствах проекта, по крайней мере я не нашел другого)?
scifi
Мне кажется, тут двух мнений быть не может: если нужно гарантировать не более 4-х тактов между инструкциями, то нужно писать на ассемблере. Иначе при каждом апгрейде версии компилятора и смене его настроек придётся проверять, как изменился этот кусок кода.
PSP
И еще не забыть запретить прерывания. Иначе баг изменится с постоянного на случайно возникающий, что гораздо неприятнее.
IgorKossak
Цитата(Alechin @ Oct 15 2007, 16:55) *
Побороть смог только вынеся данный код в процедуру с выключением оптимизации для нее (#pragme optimize=none).
Возник вопрос - ни какими ключевыми словами нельзя изменить уровень оптимизации для фрагмента кода С ВОЗВРАТОМ к текущему уровню оптимизации (через #pragma optimize можно только установить требуемый уровень оптимизации, но не вернуться к установленному в свойствах проекта, по крайней мере я не нашел другого)?

В руководстве сказано:
Цитата
The #pragma optimize directive is used for decreasing the optimization level, or for
turning off some specific optimizations. This pragma directive only affects the function
that follows immediately after the directive.

это означает, что данная директива действует только на одну, непосредственно следующую за ней, функцию.
На все последующие функции распространяется уровень оптимизации по умолчанию (заданный в настройках).

Цитата(scifi @ Oct 15 2007, 20:54) *
Мне кажется, тут двух мнений быть не может: если нужно гарантировать не более 4-х тактов между инструкциями, то нужно писать на ассемблере. Иначе при каждом апгрейде версии компилятора и смене его настроек придётся проверять, как изменился этот кусок кода.

Не стОит быть столь категоричным.
Если программа написана грамотно, то апдейт версии компилятора (по крайней мере в данном случае) к ухудшению ситуации не приведёт.
Alechin
Цитата
В руководстве сказано:
это означает, что данная директива действует только на одну, непосредственно следующую за ней, функцию.
На все последующие функции распространяется уровень оптимизации по умолчанию (заданный в настройках).

Это я знаю, поэтому так и сделал (вынес в функцию, и предварил данной прагмой). Вопрос в другом - не хотелось 3 строчки выносить в функцию. Поэтому хотелось бы написать прагму перед этими строчками, и прагму, возвращающую "взад" уровень оптимизации после этих строк (по-моему, но точно не помню, в Кейле, или в BCPP так можно было сделать).
Ну что-ж: нет так нет.

И еще просто удивила замена ОДНОЙ команды вызовом процедуры с этой-же командой! "Перебдел" компилятор при оптимизации.
xemul
Код
#pragma optimize=none
inline static void foo(void)
{
   __watchdog_reset();
   MCUSR &= ~(1 << WDRF);
   cli();
   WDTCSR |= (1 << WDCE) | (1 << WDE);
   WDTCSR = 0x00;
   sei();
}
Runner
Цитата(xemul @ Oct 16 2007, 18:36) *
Код
#pragma optimize=none
inline static void foo(void)
{
   __watchdog_reset();
   MCUSR &= ~(1 << WDRF);
   cli();
   WDTCSR |= (1 << WDCE) | (1 << WDE);
   WDTCSR = 0x00;
   sei();
}


Вопрос знатокам: в указаном примере функция foo будет встраиваться? Мне inlining удается только когда поставлена опция оптимизации - high, а иначе RCALL foo. Не помогает даже #pragma inline=forced. (IARAVR 5.11B) unsure.gif
IgorMarx
Цитата(Runner @ Apr 23 2009, 19:41) *
Вопрос знатокам: в указаном примере функция foo будет встраиваться? Мне inlining удается только когда поставлена опция оптимизации - high, а иначе RCALL foo. Не помогает даже #pragma inline=forced. (IARAVR 5.11B) unsure.gif


Самая вероятная ситуация: будет в релизе со включенной оптимизацией (а может и нет), в дебажной - будет отдельной процедурой.
sergeeff
Цитата(Runner @ Apr 23 2009, 18:41) *
Вопрос знатокам: в указаном примере функция foo будет встраиваться? Мне inlining удается только когда поставлена опция оптимизации - high, а иначе RCALL foo. Не помогает даже #pragma inline=forced. (IARAVR 5.11B) unsure.gif


В умных книгах написано, что компилятор не обязан встраивать inline функции, если с его точки зрения это хуже, чем вызвать обычную функцию.
См. Герб Саттер. Новые сложные задачи на С++.
Сергей Борщ
Цитата(IgorMarx @ Apr 23 2009, 23:05) *
будет в релизе со включенной оптимизацией (а может и нет), в дебажной - будет отдельной процедурой.
А что, у компилятора или линкера есть какая то магическая опция "релизная версия"?
MrYuran
Цитата(Сергей Борщ @ Apr 24 2009, 10:53) *
А что, у компилятора или линкера есть какая то магическая опция "релизная версия"?

Есть переключение target-а на release/debug
Это опция не компилятора/линкера, а такой жёлтенькой оболочки IAR EWB
Причём и в том, и в другом можно задать любой уровень оптимизации, но по умолчанию в дебаге включен по-моему, "Best debug support", который отключает оптимизацию вообще
Dog Pawlowa
Цитата(Runner @ Apr 23 2009, 18:41) *
Вопрос знатокам: в указаном примере функция foo будет встраиваться?

Поскольку может быть встроена функция только в том же файле, где определена, встает вопрос вообще о правильности пути для более-менее серьезного проекта.
Может быть, макрос? Оптимизатор не увидит смысла экономить на эпилогах - их просто не будет.
Сергей Борщ
Цитата(MrYuran @ Apr 24 2009, 10:06) *
Это опция не компилятора/линкера, а такой жёлтенькой оболочки IAR EWB
В том то и дело. Это название совокупности галочек в настройках, расставленных оболочкой по умолчанию. Т.е. нельзя говорить о том, что поведение будет зависеть от выбора в оболочке target release или target debug. Поведение будет полностью определяться положением галочек, расставленных в оболочке, но никак не названием этого target.


Цитата(Dog Pawlowa @ Apr 24 2009, 11:38) *
Поскольку может быть встроена функция только в том же файле, где определена, встает вопрос вообще о правильности пути для более-менее серьезного проекта.
Путь однозначно правильный. Если нужно, функции с квалификатором inline, также как и static, могут быть вынесены в заголовочный файл. Объявление в виде функции (в отличие от макроса) возлагает на компилятор заботу о контроле правильности типов, а также о создании временных переменных для хранения параметров. Просто надо разобраться, почему не работает #pragma inline=forced. Возможно, они перешли на _Pragma("inline = forced"). И зачем вообще компилировать с оптимизацией, отличной от high - тоже совсем другой разговор.
Dog Pawlowa
Цитата(Сергей Борщ @ Apr 24 2009, 13:00) *
Объявление в виде функции (в отличие от макроса) возлагает на компилятор заботу о контроле правильности типов, а также о создании временных переменных для хранения параметров.

В общем случае все это так, но если глянуть, с чего все начиналось у топикстартера, и какие же там переменные используются, то лично у меня вопрос остается.
Это просто разный инструмент, как вилка и ложка. Ложкой безопаснее, но вилкой в умелых то руках можно за два удара восемь дырок.... biggrin.gif
tourist
Цитата(Dog Pawlowa @ Apr 24 2009, 14:50) *
В общем случае все это так, но если глянуть, с чего все начиналось у топикстартера, и какие же там переменные используются, то лично у меня вопрос остается.

При записи вида:
Код
WDTCSR |= (1 << WDCE) | (1 << WDE);

Компилятор действительно генерит код не укладывающийся в 4 такта...
Я решал проблему, описываемую автором темы, записью нужного числа непосредственно в регистр, типа того:
Код
WDTCSR |= 0x01;

При этом (как ни странно) код получается нормальный, даже с полной оптимизацией, и число попадает в регистр без лишних тедлодвижений...
ИМХО автор перемудрил с отключением оптимизации для функции...
Dog Pawlowa
Вот, наткнулся на свои макросы...
Хм, запрета прерывания нет, но работает... Ах, да... Я же WDT никогда не отключаю.
Вот таким косвенным путем происходит обучение правильному использованию ресурсов контроллера smile.gif

Код
#define WDT_OFF        {    __watchdog_reset(void); WDTCR |= (1<<WDTOE) | (1<<WDE);    WDTCR=0; }
#define WDT_ON        {    WDTCR=(1<<WDE);}
#define WDT_RESET    {    __watchdog_reset(); }
Dir
Цитата(tourist @ Apr 24 2009, 15:08) *
При записи вида:
Код
WDTCSR |= (1 << WDCE) | (1 << WDE);

Компилятор действительно генерит код не укладывающийся в 4 такта...
Я решал проблему, описываемую автором темы, записью нужного числа непосредственно в регистр, типа того:
Код
WDTCSR |= 0x01;

При этом (как ни странно) код получается нормальный, даже с полной оптимизацией, и число попадает в регистр без лишних тедлодвижений...
ИМХО автор перемудрил с отключением оптимизации для функции...


Вот именно, что все это очень странно. Насколько меня учили, порты в МК - это volatile-переменные, поэтому компилятор при оптимизации должен позаботиться о всех сторонних эффектах, если он претендует на совместимость со стандартом "С". Т.е. явное игнорирование разработчиками компилятора стандарта. Попросту говоря, баг. Или не так?
Сергей Борщ
Цитата(Dir @ May 5 2009, 15:01) *
Т.е. явное игнорирование разработчиками компилятора стандарта. Попросту говоря, баг. Или не так?
В чем тут игнорирование стандарта?
Dog Pawlowa
Я бы сформулировал по другому:
Имеет ли право Атмел приводить пример сишного текста программы работы с WDT, если конкретная реализация в машинных кодах зависит от компилятора.

Короче, так - если у автора текст не совпадает полностью с примером в даташит - не прав автор.
Если текст совпадает - не прав Атмел.
Dir
Цитата(Сергей Борщ @ May 5 2009, 15:03) *
В чем тут игнорирование стандарта?

Есть там глава про сторонние эффекты и volatile-переменные. Нужно, конечно, рыться и внимательно читать, но, по памяти, стандарт прямо запрещает оптимизацию ДАЖЕ по времени, если в этом принимают участие volatile-переменные. А тут работу препроцессора взял на себя компилятор и оптимизировал как хотел... Компилятор НЕ ИМЕЛ ПРАВА на такие вольности.
Сергей Борщ
Цитата(Dir @ May 5 2009, 15:21) *
но, по памяти, стандарт прямо запрещает оптимизацию ДАЖЕ по времени, если в этом принимают участие volatile-переменные.
Освежите. В стандарте нет ни слова о времени. Компилятор обязан выполнить все указанные в программе обращения (на чтения и запись) к volatile-переменным и не имеет права нарушить их последовательность. Все. НА этом обязанности компилятора заканчиваются.
Цитата(Dir @ May 5 2009, 15:21) *
А тут работу препроцессора взял на себя компилятор и оптимизировал как хотел... Компилятор НЕ ИМЕЛ ПРАВА на такие вольности.
Где оптимизация? Где работа препроцессора? Где вольности в конце концов? Компилятор сделал чтение-наложение маски-запись. Все как заказывали. С точки зрения стандарта никаких нарушений.
Dir
Цитата(Сергей Борщ @ May 5 2009, 16:07) *
Освежите. В стандарте нет ни слова о времени. Компилятор обязан выполнить все указанные в программе обращения (на чтения и запись) к volatile-переменным и не имеет права нарушить их последовательность. Все. НА этом обязанности компилятора заканчиваются.Где оптимизация? Где работа препроцессора? Где вольности в конце концов? Компилятор сделал чтение-наложение маски-запись. Все как заказывали. С точки зрения стандарта никаких нарушений.

Тогда вообще ничего не понятно.
Почему, как указывалось в http://electronix.ru/forum/index.php?showt...st&p=583723

"Код
WDTCSR |= (1 << WDCE) | (1 << WDE);
Компилятор действительно генерит код не укладывающийся в 4 такта...
Я решал проблему, описываемую автором темы, записью нужного числа непосредственно в регистр, типа того:
Код
WDTCSR |= 0x01;
При этом (как ни странно) код получается нормальный, даже с полной оптимизацией, и число попадает в регистр без лишних тедлодвижений..."

Ведь после препроцессора компилятору попадает один и тот же код! Понятно, что препроцессор в стандарт не входит, но ведь получается, что "с точки зрения стандарта" компилятор вполне может разбить константное выражение и использовать его часть для своих оптимизационных ухищрений.
Сергей Борщ
Цитата(Dir @ May 5 2009, 17:12) *
Ведь после препроцессора компилятору попадает один и тот же код!
Нет, разный. В одном случае установлен 1 бит, и компилятор генерит инструкцию sbi, во втором случае 2 бита, и иначе как через in, or, out не получится. А еще проще не использовать в этой конструкции "или" вообще - сразу писать нужное число. Потому что состояние остальных битов, как правило, известно заранее:
Код
    WDTCR = (1<<WDCE)|(1<<WDE);
    WDTCR = (1<<WDP2)|(1<<WDP1);
Dir
Цитата(Сергей Борщ @ May 5 2009, 19:12) *
Нет, разный. В одном случае установлен 1 бит, и компилятор генерит инструкцию sbi, во втором случае 2 бита, и иначе как через in, or, out не получится. А еще проще не использовать в этой конструкции "или" вообще - сразу писать нужное число. Потому что состояние остальных битов, как правило, известно заранее:
Код
    WDTCR = (1<<WDCE)|(1<<WDE);
    WDTCR = (1<<WDP2)|(1<<WDP1);


Ну, я воспринял это просто как пример. Типа автору стало лень считать HEX-содержание своего кода.... и понесся обосновывать smile.gif
А вот сейчас в спокойной обстановке дома решил исследовать что же на самом деле происходит и ... чешу затылок. Мне никак не удается при любых уровнях оптимизации и вообще без нее добиться того, чтобы компилятор по разному оттранслировал процедуру инициализации WDT.
Т.е. вот такой код независимо от того стоит перед ним #pragma optimize=none или нет, написаны команды инициализации в виде команд препроцессору или в виде чисел (закоментарено) все равно транслируются одинаково.
Код
void test_WDT(void)
{
    __watchdog_reset();
    WDTCSR=(1<<WDCE)|(1<<WDE)|(1<<WDP0);
    WDTCSR=(1<<WDE)|(1<<WDP0);
//    WDTCSR=0x19;
//    WDTCSR=0x09;
}


ассемблерный код
Код
      7              __watchdog_reset();
   \   00000000   95A8               WDR
      8              WDTCSR=(1<<WDCE)|(1<<WDE)|(1<<WDP0);
   \   00000002   E109               LDI     R16, 25
   \   00000004   93000060           STS     96, R16
      9              WDTCSR=(1<<WDE)|(1<<WDP0);
   \   00000008   E009               LDI     R16, 9
   \   0000000A   93000060           STS     96, R16

Наверное поэтому никогда раньше не задумывался над этим вопросом, хотя по привычке всегда использовал #pragma optimize=none
Может быть с оптимизацией таки можно заставить компилятор генерировать вызовы функций посредине двух WDTCSR = ..., но надо таки постараться не по детски smile.gif
PS. Компилятор последний, 5.20, для примера взята mega48
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.