|
"Оптимизация" в WinAVR и как с этим бороться |
|
|
|
Nov 16 2011, 18:07
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Перейдя с ассемблера на WinAVR, невольно стал обращать на размер кода. Когда стал разбираться в конкретике генерируемого кода , хваленный на многих сайтах WinAVR обнажил свое несовершенство. Короче, программка : Код #include <avr/io.h> #include <inttypes.h>
#define Btn1 PB2 #define Btn2 PB3
#define KeyMask (1<<Btn1)|(1<<Btn2) #define sbi(p,b) (p |= (1<<b)) //Установить бит
volatile register int8_t Cnt asm("r19"); // фоновый счетчик volatile register int8_t a asm ("r16");
int main (void) { asm("nop"); a = 1;
while(1) { if (~(PINB)&(KeyMask)) { a |= 0x01; } if ((--Cnt)==0) { if (a==1 ) { a=0; sbi (PINB,PB2); } } } } Соответственно , полученный код: Код a = 1; ldi r16, 0x01
while(1) { [color="#FF00FF"]if (~(PINB)&(KeyMask)) in r24, 0x16 ldi r25, 0x00 com r24 com r25 andi r24, 0x0C andi r25, 0x00 or r24, r25 breq .+2[/color] { a |= 0x01; } ori r16, 0x01
[color="#FF0000"]if ((--Cnt)==0) mov r24, r19 subi r24, 0x01 mov r19, r24[/color] brne .-26 { if (a==1 ) cpi r16, 0x01 brne .-30 { a=0; ldi r16, 0x00
sbi (PINB,PB2); sbi 0x16, 2 rjmp .-36 Конструкцию if ((--Cnt)==0) выделенную крас.цветом может заменить всего одна машинная команда: dec r19! Вопрос: как заставить компилятор это делать ? Во втором случае: if (~(PINB)&(KeyMask)) , невижу смысла во втором парном регистре r25. Можно использовать "tst r24". Можно как нибудь с этим бороться ?! Не хочеться чтобы потом код получался неоправданно раздутым! Может быть стоит подождать другую версию компилятора (пользуюсь WinAVR-20100110) или уже пререходить на совсем другой ?
|
|
|
|
|
 |
Ответов
(1 - 63)
|
Nov 16 2011, 19:19
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Палыч @ Nov 16 2011, 21:45)  А, вот тут - "неча на зеркало пенять..." (т.е. не нужно "мешать" восьми- и шестнадцатибитные операнды). а где вы увидели 16ти битные операнды ? PINB читается как 8ми битные KeyMask тоже 8мь бит !
|
|
|
|
|
Nov 16 2011, 19:58
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(MaxiMuz @ Nov 17 2011, 00:07)  Перейдя с ассемблера на WinAVR, невольно стал обращать на размер кода. И зря. Если код помещается в чип и успевает сделать то, что должен, то какая разница, какого он размера? Цитата(MaxiMuz @ Nov 17 2011, 00:07)  Конструкцию if ((--Cnt)==0) выделенную крас.цветом может заменить всего одна машинная команда: dec r19! Вам же написали, что volatile register писать нельзя. Какие претензии? Что касается второго, то целочисленные константы по умолчанию имеют тип int. Попробуйте написать if (~(PINB)&((unsigned char)KeyMask)). ЗЫ. Выделение цветом не работает в блоке code, если сильно надо, то пользуйтесь блоком codebox - там вроде работает.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 16 2011, 21:06
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Палыч @ Nov 16 2011, 23:10)  Почему? Обоснуйте. смотрите по коду, предпоследния команда: or r24, r25 я не думаю что старший байт с младшим компилятор сталбы склеивать ! Кстати , можно проверить по присваиванию
|
|
|
|
|
Nov 16 2011, 21:53
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(MaxiMuz @ Nov 16 2011, 20:07)  Код #define KeyMask (1<<Btn1)|(1<<Btn2) KeyMask - результат вычисления выражения (пусть и в compile-time). По стандарту языка С имеет тип как минимум int. Дальше у gcc недооптимизация, спору нет. Но он обязан был сначала всё делать в int-ах и только потом натравить оптимизатор.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 17 2011, 08:19
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Мда, можно вытащить ассемблерщика из ассемблера, но... По поводу регистровых переменных. В них практически никогда нет реальной необходимости, особенно в достаточно сложных программах. Мнимая выгода из-за отсутствий-загрузок выгрузок из/в память, с лихвой перекрываются необходимостью тасовать и сохранять регистры, например, для вызова функций и тупяками компилятора из-за того, что он не может использовать регистры, занятые под эти переменные, так как умеет. Модификатор volatile с регистровыми переменными, как уже сказали, не работает. Если возникает реальзая ситуация, когда программа относительно проста и нехватает нескользих тактов для выполнения критического участка, то наверное имеет смысл переписать этот критический участок, а то и всю программу на ассемблере. Код if (~(PINB)&(KeyMask)) В Си есть такая штука - целочисленное расширение называется (integer propagation). Рекомендую погуглить и почитать, что это такое, многоя станет понятно.
|
|
|
|
|
Nov 17 2011, 15:19
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(aaarrr @ Nov 17 2011, 00:19)  Это обычная проверка пары регистров на 0. Как это компилятор резервирует старший байт , а потом проверяет младший со старшим ? Как то не логично получается ! AHTOXA, Пробывал я выражение : if (~(PINB)&((unsigned char)KeyMask)) - Результат абсолютно тот же, и скобки как говорили в #define я поставил, один хрен ! Попробывал предварительное присваивание константы в регистр : Код volatile register int8_t Cnt asm("r19"); // фоновый счетчик volatile register int8_t a asm ("r16"); volatile register int8_t b asm ("r17");
int main (void) { asm("nop"); a = 1; b=KeyMask; while(1) { if (~(PINB)&(b)) { a |= 0x01; } if ((--Cnt)==0) { if (a==1 ) { a=0; b |= 0x08; sbi (PINB,PB2); } } } } Тут Вообще "Оптимизатор" показал чудеса !!!  Цитата(Genadi Zawidowski @ Nov 17 2011, 04:30)  Назначение регистров для переменных ОЧЕНЬ сильно мешает оптимизации. Если рассуждать как вы , то можно сказать и любая программа написанная в Си мешает оптимизации!!! Вы еще бы посоветовали на Ассемблере писать  Цитата(AHTOXA @ Nov 16 2011, 22:58)  И зря. Если код помещается в чип и успевает сделать то, что должен, то какая разница, какого он размера? А если не помещается, и делает с большими задержками по времяни ? Цитата(AHTOXA @ Nov 16 2011, 22:58)  ЗЫ. Выделение цветом не работает в блоке code, если сильно надо, то пользуйтесь блоком codebox - там вроде работает. Кстати , а что за блок codebox ? я про него ничего не слышал Во втором случае, все просто !  Я заранее знал решение, и хотел посмотреть что вы скажите (может чего новое) Проблемка решается заменой конструкции: if (~(PINB)&(KeyMask)) на несколько команд: b=~(PINB); b&=KeyMask; if (  { ......} Код сокращается всего лишь до: Код IN R24,0x16 COM R24 ANDI R24,0x0C BREQ PC+0x02 А вот с первой проблемой мусорных присваиваний , похоже все мрачно !
|
|
|
|
|
Nov 18 2011, 05:25
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Я к чему, тут про целочисленное расширение намекаю? Компилятор в данном случае делает ровно, то, что ему сказано. В вашем выражении нужна не битовая инверсия, а логическая: Код #define KeyMask ((1<<Btn1)|(1<<Btn2)) ... if( ! (PINB & KeyMask) ) { ... } Посмотрите, и почувствуйте разницу.
|
|
|
|
|
Nov 18 2011, 08:44
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Цитата(MaxiMuz @ Nov 18 2011, 12:38)  neiver , _Pasha да действительно, можно и так написать, результат будут тотже что и в моем варианте ! С этим более менее понятно. Неа, результат другой: Код 6c: 86 b3 in r24, 0x16; 22 6e: 8c 70 andi r24, 0x0C; 12 70: 09 f4 brne .+2 ; 0x74 <main+0x8> На ЦЕЛУЮ команду меньше
|
|
|
|
|
Nov 18 2011, 09:00
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(AHTOXA @ Nov 16 2011, 22:58)  Вам же написали, что volatile register писать нельзя. Какие претензии? Это неправильное утверждение! Если из выражения "volatile register int8_t a asm ("r16");" убрать квалификатор volatile, то компилятор воообще обходит использование указанных регистров, используя свои. И хотя код получается короче, неизвестно как дальще поведет себя "оптимизатор" , если программа усложниться ! Цитата(neiver @ Nov 18 2011, 11:44)  Неа, результат другой: Код 6c: 86 b3 in r24, 0x16; 22 6e: 8c 70 andi r24, 0x0C; 12 70: 09 f4 brne .+2 ; 0x74 <main+0x8> На ЦЕЛУЮ команду меньше  На ОДНУ команду не считается  Так исторически сложилось что я проверяю на нулевой рез-т (не нажата не одна кнопка) и зацикливаю в начало
|
|
|
|
|
Nov 18 2011, 10:59
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(MaxiMuz @ Nov 18 2011, 13:00)  На ОДНУ команду не считается Если Вы пытатесь заставить GCC генерить вместо if(!(PINB & KeyMask)) одну команду SBRS (или SBRC), то у Вас ничего не получится. Хотя Atmel и утверждает, что система команд AVR ориентированна на язык Си, то компиляторописатели так не считают... В Вашем первом и втором случаях компилятор действует по шаблону: 1) берёт значение на регистр r24 (то, что Вы расположили некую переменную в регистр - изменит только источник данных: значение будет взято из другого регистра или из ОЗУ): 2) на регистре r24 вычисляет выражение; 3) при необходимости, из регистра r24 сохраняет вычисленное выражение; 4) сравнивает значение выражения (регистр r24) с нулём... Только ну очень хороший оптимизатор заменит эту последовательность одной командой. GCC так сделать не сможет. Для AVR я не знаю компилятора, в который встроен настолько сильный оптимизатор, что сможет повторить Вашу программу на ассемблере. Имхо, если компилятор с ЯВУ генерит код "съедающий" на 10-15% больше ресурсов, чем аналогичная программа на ассемблере, на сегодняшний день - это ОЧЕНЬ хороший компилятор. Заметьте - программа(!!!, причем обычно довольно большая), а не отдельный оператор.
|
|
|
|
|
Nov 18 2011, 11:07
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
GCC прекрасно может сгенерировать одну команду sbis (или sbiс), но не когда в маске установлены два бита: #define KeyMask ((1<<Btn1)|(1<<Btn2)) Оставим обин бит и будет вам счастье: Код if(!(PINB&KeyMask)) 6c: b2 9b sbis 0x16, 2; 22 А если в маске несколько единичных бит, то только честно сравнивать с нулем.
|
|
|
|
|
Nov 18 2011, 11:54
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (MaxiMuz @ Nov 18 2011, 12:00)  Это неправильное утверждение! Вдумайтесь, что вы написали. Авторы компилятора указывают, что использовать volatile и register совместно нельзя. Вы обвиняете их во лжи. Достаточно смело, но бесперспективно - во-первых авторы компилятора не читают этот форум, а во-вторых - ну, продолжайте бороться с ветряными мельницами. Напоминает FAQ про яйцо и микроволновку.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 18 2011, 14:36
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Палыч @ Nov 18 2011, 13:59)  Имхо, если компилятор с ЯВУ генерит код "съедающий" на 10-15% больше ресурсов, чем аналогичная программа на ассемблере, на сегодняшний день - это ОЧЕНЬ хороший компилятор. Заметьте - программа(!!!, причем обычно довольно большая), а не отдельный оператор. ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. Еще - бывают напряги при работе с битовыми полями, сильное юзание регистра Х в адресных выражениях, не использует бит Т и не "подглядывает" за функциями, вызываемыми из прерываний - длинный контекст сохраняется. Больше никаких шероховатостей мною не замечено. А большую программу на асме еще написать надо, чтобы "сделать" современный Си на эти 10-15%.
|
|
|
|
|
Nov 18 2011, 14:45
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Цитата(_Pasha @ Nov 18 2011, 18:36)  и не "подглядывает" за функциями, вызываемыми из прерываний - длинный контекст сохраняется. Подглядывает, еще как если функция inline.
|
|
|
|
|
Nov 18 2011, 16:06
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Палыч @ Nov 18 2011, 13:59)  Если Вы пытатесь заставить GCC генерить вместо if(!(PINB & KeyMask)) одну команду SBRS (или SBRC), то у Вас ничего не получится. ..... с этим место собственно я разобрался. Цитата(_Pasha @ Nov 18 2011, 17:36)  ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. ..... Не понятно о чем вы говорите Цитата(_Pasha @ Nov 18 2011, 17:36)  ...... А большую программу на асме еще написать надо, чтобы "сделать" современный Си на эти 10-15%. большая - маленькая зависит от типа МК. Привожу конкретный пример: Код http://www.radio.ru/archive/2010/07/a19.shtml программка писалась на асме под ATtiny2313, нехватило памяти программ под вторую таблицу мелодий для звонка. Если бы тогда писал на Си то вообще не хватилобы памяти на одну таблицу ! Это при том что я еще проводил оптимизацию программы в ассеблере  Цитата(Палыч @ Nov 18 2011, 14:17)  Да, согласен... Я собирался написать об операторе if ((--Cnt)==0) и команде DEC, но обширное обсуждение в этой теме оператора if(!(PINB & KeyMask)) сбило с мысли... Что хотели написать то ?
|
|
|
|
|
Nov 18 2011, 16:17
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(_Pasha @ Nov 18 2011, 16:36)  ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. Ну, да. Но иногда такие места удаётся оформить в маленькие подпрограмки, которые вызывать в конце (в вумных книгах по программированию давно пишут, что не стоит бояться мелких подпрограмок :-) ). Тогда вкупе с --relax и получается слияние. Цитата(neiver @ Nov 18 2011, 16:45)  Подглядывает, еще как если функция inline. Вот еще до LTO нужно добраться, так там должно за всем подглядывать уметь. Вроде бы к 5-ой аврстудии компилятор идёт уже с LTO. Klen-овые сборки под Linux для ARM дают неплохой эффект. Для AVR у меня не запустились, что-то с библиотеками не срослось. Цитата(MaxiMuz @ Nov 18 2011, 18:06)  Что хотели написать то ? Возможно то, что без зауми с asm("r19") и прочими проявлениями детской болезни левизны dec сам бы появился, и заставлять не пришлось бы (ну тут не dec, но ни по размеру кода, ни по времени выполнения не отличается — возможно, и это сказать хотели): Код #include <avr/io.h> #include <inttypes.h>
#define Btn1 PB2 #define Btn2 PB3
#define KeyMask (1<<Btn1)|(1<<Btn2)
int main (void) { uint8_t Cnt = 0; uint8_t a = 0;
while(1) { if ( !(PINB & (KeyMask)) ) a |= 0x01; if ((--Cnt)==0) { if (a==1 ) { a=0; PINB |= (1 << 2); } } } } Код .global main .type main, @function main: /* prologue: function */ /* frame size = 0 */ ldi r18,lo8(0) .L8: ldi r25,lo8(0) .L7: in r24,54-32 andi r24,lo8(12) brne .L2 ori r25,lo8(1) .L2: subi r18,lo8(-(-1)) brne .L7 cpi r25,lo8(1) brne .L7 sbi 54-32,2 rjmp .L8
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 18 2011, 17:23
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Цитата(ReAl @ Nov 18 2011, 20:17)  Вот еще до LTO нужно добраться, так там должно за всем подглядывать уметь. Вроде бы к 5-ой аврстудии компилятор идёт уже с LTO. Klen-овые сборки под Linux для ARM дают неплохой эффект. Для AVR у меня не запустились, что-то с библиотеками не срослось. К сожалению, в avr-gcc LTO не работает. Компилятор к 5-ой аврстудии скомпилирован без поддержки LTO, я пытался скомпилировать avr-gcc сам со включеной LTO - не собрался, видимо чего-то в в AVR бекэнде не хватает.
|
|
|
|
|
Nov 18 2011, 22:38
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(MaxiMuz @ Nov 18 2011, 18:06)  большая - маленькая зависит от типа МК. Привожу конкретный пример: Код http://www.radio.ru/archive/2010/07/a19.shtml программка писалась на асме под ATtiny2313, нехватило памяти программ под вторую таблицу мелодий для звонка. Если бы тогда писал на Си то вообще не хватилобы памяти на одну таблицу ! Это при том что я еще проводил оптимизацию программы в ассеблере  Поверьте старому С-шнику, избегающему по мере возможности написания программ на асме -- Вам показалось. Что Вы проводили оптимизацию этой ассемблерной программы. Бегло просмотрел программу из архива, даже толком не вникая в алгоритмы. Просто мелкая местная оптимизация — и несколько десятков байт как с куста. А если ещё вникнуть в алгоритмы, то и того более найдётся. Примеры: Код #ifndef OPTIMISED sbrc ModeR,BitModeAlrm rjmp Begin sbrc ModeR,BitModeWtch rjmp Begin #else;;; -2 sbrs ModeR,BitModeAlrm sbrc ModeR,BitModeWtch rjmp Begin #endif Там таких два места. На этой мелочи — уже 4 байта. Любой уважающий себя С-компилятор покраснел бы от стыда за такой код: Код ; Определение интервала 1 #ifndef OPTIMISED ; if ( MemdP <= Thr_AdP ) goto TCAdi11; else goto TCAdi12; cpi MemdPH,Thr_AdPH brcs TCAdi11 brne TCAdi12 cpi MemdPL,Thr_AdPL brcs TCAdi11 brne TCAdi12 #else;;; -4 bytes ; if MemdP >= (Thr_AdP + 1) ) goto TCAdi12 ldi temp, high( Thr_AdP + 1 ) cpi MemdPL, low( Thr_AdP + 1) cpc MemdPH, temp brcc TCAdi12 #endif Код #ifndef OPTIMISED ; if ( MemdP <= DeltaT ) goto TCA12; esle goto TCA11; cp MemdPH,DeltaTH brcs TCA12 brne TCA11 cp MemdPL,DeltaTL brcs TCA12 brne TCA11 #else ;;; -6 ; if ( DeltaT >= MemdP ) goto TCA11; cp DeltaTL,MemdPL cpc DeltaTH,MemdPH brcc TCA11 #endif И таких мест там не одно. Тут вообще что-то странное было. CODE ;_________ Запись таблицы регистрации нажатий в EEPROM ;* ;* CLI push temp2 push ZL push ZH #ifndef OPTIMISED clr ZL clr ZH b4: mov temp,ZL ldi temp2,low(Edata1) add temp,temp2 OUT EEAR,temp ldi temp2,low(data1) add ZL,temp2 LD temp,Z sub ZL,temp2 OUT EEDR,temp SBI EECR,EEMPE; SBI EECR,EEPE b5: sbic EECR,EEPE rjmp b5 cpi ZL,MaxCount*2-1 breq b6 ld temp,Z+ rjmp b4 b6: ldi temp,low(EMrk1) OUT EEAR,temp ldi temp,0xab OUT EEDR,temp SBI EECR,EEMPE; SBI EECR,EEPE
#else ;;; -14b
ldi ZL, low(data1) clr ZH ldi temp2, Edata1 b4: ld temp, Z+ rcall WrEE inc temp2 cpi temp2, MaxCount*2-1 brne b4 b6: ldi temp2,low(EMrk1) ldi temp,0xab rcall WrEE #endif
pop ZH pop ZL pop temp2 SEI
m9: CLR EnGen clr count m11: ;______ Задержка ldi temp,ZDelayL mov CL,temp rcall DelayTime Begin__: rjmp Begin
#ifdef OPTIMISED WrEE: OUT EEAR,temp2 OUT EEDR,tempЯ SBI EECR,EEMPE; SBI EECR,EEPE WrEEw: sbic EECR,EEPE rjmp WrEEw ret #endif Эта запись вообще дважды повторяется, в слегка разном окружении. Её всю в подпрограмму надо пустить. Ещё tiny2313 есть регистры GPIOR, аж три штуки. Все флаги успешно летят туда без увеличения объёма кода с незначителным увеличением времени. Освобождается два регистра, причём "верхних". Явно где-то поможет сократить код. Я бы постарался выделить регистровую пару Y под указатель на блок данных в DSEG, заменив все LDS/STS на LDD/STD. Ещё так на глаз минимум полсотни байт. Напоминаю — это всё не особо вникая в суть кода.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 20 2011, 11:58
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(neiver @ Nov 18 2011, 20:23)  К сожалению, в avr-gcc LTO не работает. Компилятор к 5-ой аврстудии скомпилирован без поддержки LTO, я пытался скомпилировать avr-gcc сам со включеной LTO - не собрался, видимо чего-то в в AVR бекэнде не хватает. У меня к сожелению, не достаточно глубокие познания в тонкостях компиляторов и знания абревиатур, да и практики маловато. Хотел узнать , что такое LTO ? Цитата(ReAl @ Nov 19 2011, 01:38)  Поверьте старому С-шнику, избегающему по мере возможности написания программ на асме -- Вам показалось. Что Вы проводили оптимизацию этой ассемблерной программы. Бегло просмотрел программу из архива, даже толком не вникая в алгоритмы. Просто мелкая местная оптимизация — и несколько десятков байт как с куста. А если ещё вникнуть в алгоритмы, то и того более найдётся. Примеры: Код #ifndef OPTIMISED sbrc ModeR,BitModeAlrm rjmp Begin sbrc ModeR,BitModeWtch rjmp Begin #else;;; -2 sbrs ModeR,BitModeAlrm sbrc ModeR,BitModeWtch rjmp Begin #endif Там таких два места. На этой мелочи — уже 4 байта. Я уважаю людей которые хорошо разбираются в С-ях !  Да, действительно я не достаточно тщательно провел оптимизацию данной программы ! И в приведнном примере , я возможно проглядел, либо просто не стал обращать внимание на эти мелочи ... п.с. а про код "записи в ЕЕПРОМ" я прекрасно знал , просто в этой программе не стал его выделять в отдельную процедуру. Цитата(ReAl @ Nov 19 2011, 01:38)  Любой уважающий себя С-компилятор покраснел бы от стыда за такой код: Код ; Определение интервала 1 #ifndef OPTIMISED ; if ( MemdP <= Thr_AdP ) goto TCAdi11; else goto TCAdi12; cpi MemdPH,Thr_AdPH brcs TCAdi11 brne TCAdi12 cpi MemdPL,Thr_AdPL brcs TCAdi11 brne TCAdi12 #else;;; -4 bytes ; if MemdP >= (Thr_AdP + 1) ) goto TCAdi12 ldi temp, high( Thr_AdP + 1 ) cpi MemdPL, low( Thr_AdP + 1) cpc MemdPH, temp brcc TCAdi12 #endif Код #ifndef OPTIMISED ; if ( MemdP <= DeltaT ) goto TCA12; esle goto TCA11; cp MemdPH,DeltaTH brcs TCA12 brne TCA11 cp MemdPL,DeltaTL brcs TCA12 brne TCA11 #else ;;; -6 ; if ( DeltaT >= MemdP ) goto TCA11; cp DeltaTL,MemdPL cpc DeltaTH,MemdPH brcc TCA11 #endif И таких мест там не одно. Суть правильная, только ваш оптимизатор почемуто в метках переходов ошибся ! при условии С=0 должна выполняться какраз противоположная ветвь ! Вот так доверяй потом оптимизаторам !! И в данном куске, почему я сначала старшие байты решил проверять : хотел ускорить алгоритм проверки. Хотя сейчас понимаю что это не к чему было. И всеже вернусь к использованию регистровых глобальных перемнных. В теме: заголовок"Второй раз повторяю, GCC не поддерживает volatile register переменные. Не поддерживает - это значит что нет гарантии что любой код использующий volatile register переменные будет работать при любом уровне оптимизации. К сожалению варинг сообщающий об этом пропал где-то в 2005 году и если я правильно понял его вернули в феврале 2008. Попробуйте откомпилировать тестовый пример с "volatile register" GCC 4.4 с клюем -Wall. Или с ключом -Wvolatile-register-var на 4.3. Анатолий. " были упомянуты ключики. Я не нашел в дока назначение этих ключей, плохо ориентируюсь описании WinAVR. Есть ли возможность отключить в опциях использование компилятором конкретных регистров ?
Сообщение отредактировал MaxiMuz - Nov 20 2011, 11:15
|
|
|
|
|
Nov 20 2011, 12:23
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(MaxiMuz @ Nov 20 2011, 12:55)  Хотел узнать , что такое LTO ? Link-Time-Optimiser Зачатки его есть и в нынешнем линкере, ключ --relax. Это, например, превращение линкером длинного вызова в короткий. На этапе компиляции ещё неизвестно, насколько близко лягут куски из разных файлов и на больших кристаллах компилятром используется только длинный. LTO делает полную оптимизацию, зная уже всё о линкуемой программе (включая устройство библиотечных функций, если они были скомпилировані с соо-тветствующим ключом). Цитата(MaxiMuz @ Nov 20 2011, 12:55)  Да, действительно я не достаточно тщательно провел оптимизацию данной программы ! И в приведнном примере , я возможно проглядел, либо просто не стал обращать внимание на эти мелочи ... Ну там дальше и не такие мелочи на cp/cpc набегают, как тут на пропусках. Цитата(MaxiMuz @ Nov 20 2011, 12:55)  п.с. а про код "записи в ЕЕПРОМ" я прекрасно знал , просто в этой программе не стал его выделять в отдельную процедуру. И какой смысл после этого было говорить, что "на ассемблере влезла одна мелодия и то после оптимизации, а С и одна не влезла бы" ? ;-) У С по длине выигрывает не любая ассемблерная реализация — только потому, что она ассемблерная  — а только действительно вылизанная. Прикидочно, оценивая возможное ужатие Вашего кода байт на 150-200, — тут и С-шная реализация должна легко влезть. Цитата(MaxiMuz @ Nov 20 2011, 13:58)  Суть правильная, только ваш оптимизатор почемуто в метках переходов ошибся ! при условии С=0 должна выполняться какраз противоположная ветвь ! Ну там в одном из мест я для нужной нестрогости сравнивания поменял порядок операндов, мог забыть про смену полярности перехода. Это не важно, ошибки в коде любой длины бывают. Главное то, что код можно написать короче. Там ещё ошибки есть, например, в одном из мест надо так: Код cpi temp2, Edata1 + MaxCount*2-1 Это до меня уже в субботу утром, в метро по дороге на работу в дрёме дошло. Отмазки: 1) Ну дак в пол второго ночи и наспех (вставать-то в шесть), да копипастом-редактированием (из головы я бы сразу правильно писал) и не такого наворотить можно 2) А С-компилятор и не ошибся бы с "полярностью" перехода. Цитата(MaxiMuz @ Nov 20 2011, 13:58)  Есть ли возможность отключить в опциях использование компилятором конкретных регистров ? -ffixed-reg, например -ffixed-reg=r2 Только нужно быть уверенным, что библиотека тоже этот регистр не использует.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 23 2011, 11:30
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(ReAl @ Nov 20 2011, 15:23)  ........................................ -ffixed-reg, например -ffixed-reg=r2 Только нужно быть уверенным, что библиотека тоже этот регистр не использует. После вставики в Makefile Код CFLAGS += -ffixed-reg=r16 CFLAGS += -ffixed-reg=r18 Компилятор выдал ошибку: Код cc1.exe: warning: unknown register name: reg=r16 cc1.exe: warning: unknown register name: reg=r18 Что я не так делаю ? И где можно найти описание всех ключей компилятора GCC
|
|
|
|
|
Nov 23 2011, 21:19
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Тьху, ну конечно, -ffixed- regЧто-то меня на = потянуло :-) Цитата(demiurg_spb @ Nov 23 2011, 15:39)  Как всегда в гугле, забив в строке поиска: gcc optimization options Если бы гугл умел посылать пользователя на его локальный диск в file:///C:/WinAVR/doc/gcc/HTML/gcc-4.3.2/gcc/index.html в частности, file:///C:/WinAVR/doc/gcc/HTML/gcc-4.3.2/gcc/AVR-options.html file:///C:/WinAVR/doc/gcc/HTML/gcc-4.3.2/gcc/Code-Gen-Options.html а также file:///C:/WinAVR/doc/avr-libc/avr-libc-user-manual/index.html так он ещё бы трафик пользователю сэкономил. ___________________________ — А я так XP-шку до конца и не прошёл... — Так это же не игрушка, а ОС — Откуда инфа 8-O ???
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 25 2011, 08:40
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Спасибо за ответы ! Опять я возвращаюсь к своим любимым регистровым глобальным переменным. Вначале программы обычно происходит инициализация переменных. В моей программе три регистровых глобальных переменных. Одна из них обьявленна как битовая область, и с ней проблем нет. Две других как беззнаковый байт (см. программу). В месте задания им начальных значений, компилятор игнорировал эти операции, чтобы я не делал. Все уровни оптимизации , кроме -O0 исключали эти команды. Но, после перемещения блока инициализации в отдельную подпрограмму , компилятор всеже их заметил, и правильно откомпилировал! У меня возникла мысль, что какието ключи не позволяют оптимизатору игнорировать команды в подпрограммах. Хотел бы услышать ваши предположения. Код #include <avr/io.h> #include <avr/interrupt.h> // задает макросы sei() , cli() #include <inttypes.h>
//===================================================================== // определение регистров: volatile register uint8_t FLCnt asm("r16"); //фоновый счетчик длительности переключения свдиода volatile register uint8_t DBKCnt asm("r18"); //фоновый счетчик для отсчета периода блокировки опроса кнопок volatile register struct { uint8_t bDbRKey : 1; uint8_t bFLed : 1; } RFGP asm ("r17");
//;---------------------------------------------------------------------------------------------------------------------------------------- //=== Определение макросов #define sbi(p,b) (p |= (1<<b)) //Установить бит //;---------------------------------------------------------------------------------------------------------------------------------------- //Определение портов: /* направление для порта В*/ #define DIRB 0b00010001 /* Pull-ups для порта В*/ #define PUPB 0b00000101
//;---------------------------------------------------------------------------------------------------------------------------------------- //Определение контактов #define Control1 PB4 /* линия управления VT (1 - откр; 0 - закр ) */ #define Btn1 PB2 /* линия кнопки (на общ.пров) */ #define Led PB0 /* линия светодиода ("1" - вкл. ч/з резистор на общ.) */
//;---------------------------------------------------------------------------------------------------------------------------------------- /* длительность запрета на опрос клавиш t=(101-1)*0,1=10 sec */ #define Vl_DBKCnt 101
/* t=5*0,1=0,5 sec */ #define Vl_FLCnt 5
// Маска кнопок:"Btn" #define KeyMask (1<<Btn1)|(1<<1)
//===================================================================== //===================================================================== SIGNAL ( SIG_OUTPUT_COMPARE0A) {//______ Моргание светодиода t=5*0,1=0,5 sec if (!(--FLCnt)) {//__ Переключение свдиода FLCnt=Vl_FLCnt;// перезагрузка ф.счетчика !!!! ~(RFGP.bFLed); sbi (PINB,Led);// ________ Переключение свдиода ! }
//______ Формирование запрета на опрос клавиш t=(101-1)*0,1=10 sec if (RFGP.bDbRKey==1) { //__ проверка на первый запуск if (DBKCnt == 0 ) DBKCnt=Vl_DBKCnt; --DBKCnt;//__ продолжение счета if (DBKCnt==0) // checking of =0 { //__ сброс флага RFGP.bDbRKey=0; DBKCnt=Vl_DBKCnt; } } }
//============================================================================= //============================================================================= int main (void) { //_________________________ ИНИЦИАЛИЗАЦИЯ _____________________________ uint8_t temp;
PORTB=PUPB; //иницализация порта B DDRB=DIRB; // задание направления для порта B TIMSK0=(1<<OCIE0A); /* установка разр. прер-ия по совпадению т/сч.0 с регистром OCR0A */ OCR0A=234; //загрузка регистра совпадения OCR0A коэф. деления TCCR0A= (1<<WGM01); //установка режима СТС - обнуление Т/С0 при совпадении с регистром OCR0A TCCR0B=(1<<CS02)|(1<<CS00); // <---- конфигурация и запуск сч-ка в реж. СТС с предделителем ckl/1024 RFGP.bDbRKey=0; RFGP.bFLed=0; [color="#ff0000"]DBKCnt=Vl_DBKCnt; //задание начальных значений для счетчиков FLCnt=(uint8_t)Vl_FLCnt;[/color]
sei (); // Разрешение общего прерывания //____________________ ЦИКЛ РАБОЧЕЙ ПРОГРАММЫ ______________________ while (1) { //____ Считывание кнопки temp=~(PINB); temp &= KeyMask; if (temp) { //______ Обработка нажатия кн."Btn" if ( RFGP.bDbRKey==0)//____ проверка на запрет считывания кнопок { RFGP.bDbRKey=1; // sbr RFGP,(1<<bDbRKey) sbi (PINB,Control1); // ________ Переключение линии Control1 _______________!!!!! } } } }
|
|
|
|
|
Nov 25 2011, 12:07
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(Сергей Борщ @ Nov 25 2011, 12:27)  Прочитайте еще раз про яйцо и микроволновку. Мне лень считать, сколько раз вам писали, что регистровую переменную нельзя делать volatile, о чем прямым текстом пишут создатели компилятора. Вы же с упорством пьяного продолжаете писать register volatile и пенять на компилятор. Извиняюсь что возмутил вас употребением и применением volatile ! Кстати сказать, из ответ на вопрос о использовании Volatile к регистровым глобальным переменным я со своим плохим знанием английского понял что компилятор уже считает регистровые переменные как volatile. Другими словами использование квалификатора бессмысленно. Я убрал в обьявлении переменных FLCnt, DBKCnt volatile, результат тотже ! Вопрос остается открытым
|
|
|
|
|
Nov 25 2011, 14:35
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(AHTOXA @ Nov 25 2011, 16:16)  Какой? Почему регистровые переменную, вне зависимости от наличя слова volatile, компилятор, предупредивший о своём отношении к таким объявлениям, не рассматривает как volatile и выкидывает из main() их инициализацию, так как в этой же main() к переменным больше обращений нет, а про обращение к ним из прерываний компилятор «не знает».
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 25 2011, 20:32
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Провёл маленький эксперимент. Убрал все эти register... asm() Начало файла стало выглядеть так: Код //===================================================================== // определение регистров: volatile uint8_t FLCnt; volatile uint8_t DBKCnt;
#define DbRKey 0x01 #define FLed 0x02 Обработчик прерывания так: Код SIGNAL(SIG_OUTPUT_COMPARE0A) { uint8_t temp;
temp = FLCnt; if (!(--temp)) { temp = Vl_FLCnt; // ~(RFGP.bFLed); Эта штука ничего осмысленного не делает. // и в выходном коде от неё ничего И НЕ БЫЛО PINB |= _BV(Led); } FLCnt = temp;
if ( GPIOR0 & DbRKey ) { temp = DBKCnt; // на мой взгляд странные манипуляции, но оставил как есть if (temp == 0) temp = Vl_DBKCnt; --temp; if (temp == 0){ GPIOR0 &= ~DbRKey; temp = Vl_DBKCnt; } DBKCnt = temp; } } При компиляции для atmega168 количество команд в обработчиках прерывания для старого и нового варианта кода сохранилось. Все push/pop в начале и в конце обработчика совпадают, общий ход практически тот же. Просто несколько команд mov заменилось на lds, sts. В итоге длина в байтах для нового варианта увеличилась на 8 байт и стала 66 байт. Время выполнения увеличилось на 4 такта. Только время тут «абсолютно», а вот освобождение трёх зафиксированных до этого регистров освободит руки компилятору в других местах и общая длина кода всей программы ещё и уменьшиться может. За что боролись? Думаю, сначала нужно научиться просто на С писать, а потом про все эти зафиксированные регистры думать.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 28 2011, 10:59
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
AHTOXA с вами не поспоришь ReAl По сути , кусок из вашего варианта : Код temp = FLCnt; if (!(--temp)) { подобен коду сформированному с использованием регистровых переменных: Код if (!(--FLCnt)) 2e: 80 2f mov r24, r16 30: 81 50 subi r24, 0x01; 1 32: 08 2f mov r16, r24 34: 11 f4 brne .+4 Но даже если закрыть глаза на бессмысленные mov rd,rs , как вы сами признали чуть быстрее и меньше по коду. И в использование возможностей железа по максимуму, даже учитывая корявость компилятора, нет ничего предосудительного  А абстрагирование от железа приводит к появлению таких опусов как Win7 ! с неоправданно раздутым кодом и тормозным ядром ! А если используется мощн.математический аппарат, то как я себе это представляю, здесь полезно оценить что важнее, быстый доступ к регистровым переменным или быстрое выполнение мат.операций. Код if ( GPIOR0 & DbRKey ) кстати в ATtiny13 (под него я пишу код) нет таких регистров вв./выв. которые можно так использовать! Цитата(ReAl @ Nov 25 2011, 23:32)  .......................... Думаю, сначала нужно научиться просто на С писать, а потом про все эти зафиксированные регистры думать. с вами полностью согласен , но гибкое использование железа тоже часть "знания Си"
Сообщение отредактировал MaxiMuz - Nov 28 2011, 10:56
|
|
|
|
|
Nov 28 2011, 14:16
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(MaxiMuz @ Nov 28 2011, 12:59)  подобен коду сформированному с использованием регистровых переменных: Код if (!(--FLCnt)) 2e: 80 2f mov r24, r16 30: 81 50 subi r24, 0x01; 1 32: 08 2f mov r16, r24 34: 11 f4 brne .+4 Но даже если закрыть глаза на бессмысленные mov rd,rs , как вы сами признали чуть быстрее и меньше по коду. Но всё равно проиграет чисто-асмовой реализации гораздо больше, чем выиграет у «универсальной» реализации («универсальной» в том смысле, что точно так же можно написать для IAR/MSP430 и оно тоже будет оптимально в плане работы с volatile-переменными в памяти). Цитата(MaxiMuz @ Nov 28 2011, 12:59)  И в использование возможностей железа по максимуму, даже учитывая корявость компилятора, нет ничего предосудительного  А абстрагирование от железа приводит к появлению таких опусов как Win7 ! с неоправданно раздутым кодом и тормозным ядром! А абстрагирование от языка и компилятора к чему приводит? Сначала нужно навчиться по-максимуму использовать платформенно-независимые возможности языка, а то получается «вперёд к коммунизму минуя феодализм». А уже потом использовать учиться использовать возможности специфического компилятора для доступа к специфическим возможностям железа. Если ставить телегу впереди лошади, то выходит как у Вас — оно-то вроде и короче, но для того, чтобы оно заработало правильно, приходится делать костыли в виде отдельно вызываемой функции инициализации этих переменных (rcall+ret сожрали 4 байта из выигрыша варианта без принудительно-регистровых переменных). А там, глядишь, и в других местах для нормального обращения к этим переменным придётся городить функции. Цитата(MaxiMuz @ Nov 28 2011, 12:59)  Код if ( GPIOR0 & DbRKey ) кстати в ATtiny13 (под него я пишу код) нет таких регистров вв./выв. которые можно так использовать! с вами полностью согласен , но гибкое использование железа тоже часть "знания Си" Нет. Это часть знания аппаратуры, а не языка. Эти же GPIOR можно и из ассемблера использовать, и из бейсика и что там ещё для AVR найдётся. В теме до сих пор упоминался только ATtiny2313, у которого их три, вот я как-то и отнёс всё остальное к нему.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 28 2011, 20:17
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Для этого в AVR-GCC уже давно есть OS_main и OS_task, они что-то там глубже копают. Если main() сама по себе довольно большая, то OS_main даст больше эффекта, чем noreturn. ... Начиная с 4.2.2, если верить мне самому в исходниках порта scmRTOS :-) Код #if GCC_VERSION >= 40202 #define OS_PROCESS __attribute__((OS_task)) #else #define OS_PROCESS __attribute__((__noreturn__)) #endif
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jan 23 2012, 09:15
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(sigmaN @ Nov 28 2011, 22:40)  перед main воткните __attribute__ ((noreturn)); http://www.emerson.emory.edu/services/gcc/...Attributes.htmlэкономит "пару" байт Никакого действия этот предписание на программу не оказало, и я не понял из описания на что оно конкретно делает.
|
|
|
|
|
Jan 23 2012, 09:53
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(ILYAUL @ Nov 29 2011, 08:15)  ИМХО . Для 13 писать на С , можно только в рамках изучения С , там и asm сложно "развернуться", если задействовать все ее ресурсы. не согласен. во-первых, все ресурсы МК вообще сложно задействовать одновременно (в одном проекте то есть), даже если МК "просторнее" тини13. а во-вторых, я лично последние годы пишу только на Си, причем для тини13 сделал несколько разных проектов, часто даже не напрягаясь с оптимизацией. последний проект - RGB-светильник с дистанционным управлением (пульт ДУ тоже на тини13)  на Си пишется достаточно комфортно.
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 2 2012, 11:49
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(sigmaN @ Jan 24 2012, 05:07)  warning это не error и по идее не должен приводить к трудностям с hex файлом. no return statement in function returning non-void подсказывает вам, что функцию вы объявили как возвращающую значение(т.е. не void) а return в теле функции не встречается. Самое простое: добавить в функцию return 0; добавил в конец функции int OS_main (void) оператор return 0; предупреждение пропало, но ошибка линковщика , которую я в начале не заметил осталась : Код inking: copy_reg_struct.elf avr-gcc -mmcu=attiny13a -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=copy_reg_struct.o -std=gnu99 -MMD -MP -MF .dep/copy_reg_struct.elf.d copy_reg_struct.o --output copy_reg_struct.elf -Wl,-Map=copy_reg_struct.map,--cref,-gc-sections -lm c:/program files/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr25/crttn13a.o:(.init9+0x0): undefined reference to `main' make.exe: *** [copy_reg_struct.elf] Error 1
|
|
|
|
|
Feb 3 2012, 10:42
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(_Pasha @ Feb 2 2012, 15:16)  Таварисч не панимаит. Код int main(void) __attribute__((OS_main)) { // blabla return 0; } Да! я не поимаю! в этом случае компил. кажет: Код copy_reg_struct.c:112: error: expected ',' or ';' before '{' token
|
|
|
|
|
Feb 3 2012, 11:08
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (MaxiMuz @ Feb 3 2012, 12:42)  Да! я не поимаю! _Pasha описАлся. CODE __attribute__((OS_main)) int main(void) { // blabla return 0; } или CODE int main(void) __attribute__((OS_main));
int main(void) { // blabla return 0; } И не спрашивайте "почему?". Так есть.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 16 2012, 18:35
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Доброго времяни суток! Не стал создавать отдельной темы. Хочу прояснить для себя такой момент, фрагмент: Код #define Mask (0x07) int main (void) { uint8_t Cnt=0; while (1) { if (Cnt &((unsigned char) Mask)) {Buf1=1; } else { Buf1=2; } Cnt++; } } Где условие компилируется в: Код if (Cnt &((unsigned char) Mask)) 56: 82 2f mov r24, r18 58: 90 e0 ldi r25, 0x00; 0 5a: 87 70 andi r24, 0x07; 7 5c: 90 70 andi r25, 0x00; 0 5e: 89 2b or r24, r25 60: 19 f0 breq .+6 ; 0x68 <main+0x1c> здесь игнорирование (unsigned char) перед Mask это особенности GCC компилятора ? Т.к. AVR 8ми битный, можно ли отключить както 16битное расширение ?
Сообщение отредактировал MaxiMuz - Oct 16 2012, 18:37
|
|
|
|
|
Oct 16 2012, 19:26
|

Профессионал
    
Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634

|
Используйте компилятор поновее (avr-gcc 4.7.2, avr-gcc 4.8) - будет Вам счастье (на моих проектах объём кода на 30% уменьшился): Код 0000007c <main>: 7c: 80 e0 ldi r24, 0x00; 0 7e: 92 e0 ldi r25, 0x02; 2 80: 21 e0 ldi r18, 0x01; 1 82: 37 e0 ldi r19, 0x07; 7 84: 38 23 and r19, r24 86: 19 f0 breq .+6; 0x8e <main+0x12> 88: 20 93 60 00 sts 0x0060, r18 8c: 02 c0 rjmp .+4; 0x92 <main+0x16> 8e: 90 93 60 00 sts 0x0060, r25 92: 8f 5f subi r24, 0xFF; 255 94: f6 cf rjmp .-20; 0x82 <main+0x6> Берётся тут и подключается в AvrStudio 4.19 без проблем.
Сообщение отредактировал Genadi Zawidowski - Oct 16 2012, 19:41
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|