|
|
  |
Перенос кода из под ИАРа на WinAVR, возникают некоторые вопросы... |
|
|
|
Nov 29 2008, 21:02
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(alx2 @ Nov 29 2008, 15:51)  Поэтому кодеру очень часто пришлось бы писать явное приведение к типу int, например писать (0 + a +  / 2 вместо (a +  / 2. Лично мне это бы не понравилось, т.к. во-первых, больше текста - больше вероятность ошибиться, а во-вторых, ухудшается читаемость кода. Зачем часто писать явное приведение к int? Разумнее сразу иметь хотя-бы одну переменную размерности int, если обработка данных типа char приводит к образованию переполнения В моём случае (применительно к моему проекту) ситуация совсем обратная. Мне частенько приходится делать явное приведение к char Почему? Потому что я резонно предполагал более эффективную работу восьмибитного ядра именно с "родным" типом данных - с char. Поэтому старался иметь максимальное количество переменных такого типа. Цитата Не эквивалентны. В первом случае преобразование к типу char производится перед делением, во втором - после. Например при LCD_WIDTH=96, x=32 и lcdGetStringWidth(text)=0 результат этих выражений будет разным. Ты говоришь про общий случай. Я - про строку кода конкретной функции lcdPrintText, в которой делимое всегда лежит в пределах 0 <= d < 96. Поэтому эти выражения совершенно эквивалентны. Ты можешь возразить - а откуда это может знать компилятор? Я соглашусь - не может он этого знать, он просто "железяка", которой внушили, что она много знает, и которой время от времени приходится "выпрямлять руки". Но продолжим о "выражениях". Благодаря стандарту, первое выражение имеет в два с половиной раза больший объём кода. А если в программе таких выражений десятки? Тогда мы получаем в коде сотни байт ненужного мусора, что для маленьких кристаллов является актуальной проблемой. Что мы делаем? Мы делаем явное приведение типов/разбиваем выражения на несколько частей и т.д. и т.п., что, как ты верно заметил, Цитата лично мне это бы не понравилось, т.к. во-первых, больше текста - больше вероятность ошибиться, а во-вторых, ухудшается читаемость кода в чём я полностью с тобой согласен! Так что это палка о двух концах.  Да бог с этими стандартами. Я попробую компилировать проект сразу в двух компиляторах - IAR и GCC. Хочу сравнить и отписаться об их "узких местах", так как меня это заинтересовало. Может, ещё кому-то это будет интересно...  ЗЫ: вся эта возня с битами снова навела меня на мысль "пощупать" 16-ти битные MSP430. Как-то годик назад я взглянул мельком на несколько мануалов, но показалось, что они послабее периферией универсальных "мег"...
|
|
|
|
|
Nov 29 2008, 21:43
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(AHTOXA @ Nov 29 2008, 21:31)  Но ведь 50% от 0xFFFF - это гораздо больше, чем 50% от 0xFF!  Плохо Вы знаете определение вероятности. Вероятность - это отношение количества интересующих состояний к общему количеству состояний. В рассматриваемом случае вероятность одинакова (мелочь не учитываем). А уж абсолютные количества состояний - это совсем другой вопрос. Если выбирается разрядность 8, значит кодер чтото знает о свойствах своих переменных. А вообще, истоки этого дела (расширение до int) в системе команд PDP-11. Так же, как и описание восьмиричных констант на символ меньше шестнадцатиричных (ребята из DEC'а очень любили восьмиричную систему) С другой стороны лично я выработал некий набор костылей, которые позволяют писать код, хорошо ложащийся как на AVR, так и на ARM (или на другой 32хбитный камень, да и 16тибитный тоже). В частности, это регулярное применение каста (UREG) и (REG), а сами эти типы определяют размер регистра (например, char для AVR, int для архитектур с более высокой разрядностью). Код, конечно, для неподготовленного человека содержит приличное количество странной писанины, но зато с весьма хорошим результатом после компиляции. Еще один финт - минимизация использования знаковых переменных, т.к. это часто приводит к лишним операциям типа расширения знака. Кроме того, лично я, например, против современного игнорирования ключевого слова register. Но это отдельный разговор.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Nov 29 2008, 21:56
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(Rst7 @ Nov 30 2008, 01:43)  С другой стороны лично я выработал некий набор костылей, которые позволяют писать код, хорошо ложащийся как на AVR, так и на ARM (или на другой 32хбитный камень, да и 16тибитный тоже). В частности, это регулярное применение каста (UREG) и (REG), а сами эти типы определяют размер регистра (например, char для AVR, int для архитектур с более высокой разрядностью). Код, конечно, для неподготовленного человека содержит приличное количество странной писанины, но зато с весьма хорошим результатом после компиляции. Еще один финт - минимизация использования знаковых переменных, т.к. это часто приводит к лишним операциям типа расширения знака.
Кроме того, лично я, например, против современного игнорирования ключевого слова register. Но это отдельный разговор. Спасибо за советы Вас, видимо, весьма интересует тема оптимального кода. Наверное, осталась привычка со времён спектрума? Мне кажется, сейчас не каждый заглядывает в "недра" бинарников, особенно программеры PC софта. За отсутствием необходимости?  Раскопал ещё один "пережиток стандарта". Имеем текст: Код typedef unsigned char byte; byte percent; byte maxRPM; byte minRPM;
percent = (maxRPM - minRPM) / 2; и результат: Код percent = (maxRPM - minRPM) / 2; 6c0: 80 85 ldd r24, Z+8; 0x08 6c2: 90 e0 ldi r25, 0x00; 0 6c4: 21 85 ldd r18, Z+9; 0x09 6c6: 82 1b sub r24, r18 6c8: 91 09 sbc r25, r1 6ca: 62 e0 ldi r22, 0x02; 2 6cc: 70 e0 ldi r23, 0x00; 0 6ce: ee d8 rcall .-3620; 0xfffff8ac <__eeprom_end+0xff7ef884> Здесь вроде нет знаковых переменных, и нет сложения. Почему не сработала оптимизация? Разве есть смысл в "запихивании" отрицательного значения в unsigned char? (впрочем, в ИАРе аналогичная фиговина) Также есть проблемы с утилитой создания листинга avr-objdump - как видно, неправильно вычисляется адрес подпрограммы деления... Цитата Цитата За короткое время знакомства с GCC понравилось: удобная реализация атомарности через макросы ATOMIC_BLOCK(), удобная обёртка для обработчиков прерываний вида ISR(vector_name){}. Так это как раз не компилятор, это просто библиотечные макросы. Аналогичные макросы можно сделать для любого минимально вменяемого компилятора. Но разве есть подобные макросы для IAR? Там ведь приходится пользоваться громоздкой конструкцией с pragma и примитивными __disable_interrupt() и __enable_interrupt()...
|
|
|
|
|
Nov 29 2008, 22:00
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(sonycman @ Nov 30 2008, 00:02)  Я попробую компилировать проект сразу в двух компиляторах - IAR и GCC. Хочу сравнить и отписаться об их "узких местах", так как меня это заинтересовало. Может, ещё кому-то это будет интересно...  Мне это будет интересно. Еще интереснее если Вы вооружитесь стандартом на язык С и выступите в качестве третьего компилятора. Еще, GCC в первую очередь компилятор стандартного языка С, во вторую компилятор для нескольких популярных архитектур x86, ARM, 68k и уже в третью - четвертую компилятор для AVR. Для AVR добавлено много оптимизаций, но всегда есть куда совершенствоваться. Да но это не значит что на каждое Ваше хочу ктото кудато побежит чегото делать, какие-то вещи невозможно сделать, какие-то очень трудно, на кикие-то просто нет времени, а какаето просто не интересно делать. Не забывайте, что Вам никто ничего не обязан. Любая конструктивная и обоснованная критика принимается. Не конструктивная, типа "мне ПОФИГ, что стандарт требует приведения выражения к int, я знаю что при моих входных параметрах выражение никогда не даст в результате больше 96, и я ХОЧЮ чтобы компилятор это угадал и использовав при расчетах тип char" меня не интересует. К сожалению в мои таланты не входит просто и доходчиво учить и разъяснять положения стандарта и занимаюсь я этим очень редко и неохотно. Это ссылка на стандарт: www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf С уважением, Анатолий.
|
|
|
|
|
Nov 29 2008, 22:24
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(aesok @ Nov 30 2008, 02:00)  Не забывайте, что Вам никто ничего не обязан. Я разве здесь хоть что-то от кого-то потребовал? Просто привожу вещи, которые мне непонятны/кажутся глупыми/достойными восхищения и т.д. и т.п. И премного благодарен всем, кто наставляет меня "на путь истинный" И, вероятнее всего, не только меня. Цитата мне ПОФИГ, что стандарт требует приведения выражения к int, я знаю что при моих входных параметрах выражение никогда не даст в результате больше 96, и я ХОЧЮ чтобы компилятор это угадал и использовав при расчетах тип char Если вы не поняли, то весь смысл про char был в одном - применительно к AVR это неудобно и неэффективно. С моей точки зрения. Никому её не навязываю и тем более никого не убеждаю изменять стандарты  А вот доводить до ума оптимизацию, думаю, нужно. В частности, по обработке switch?
|
|
|
|
|
Nov 29 2008, 22:36
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Rst7 @ Nov 30 2008, 01:24)  Простите, а Вы участвуете в разработке GCC, в частности для AVR? Да. Цитата(Rst7 @ Nov 30 2008, 01:24)  Если да, то у меня есть конструктивная критика. Изложена она в ветке про сборки klen'а. Это Вас заинтересует? Или обычный ответ - "никто никому ничего не должен?"  К сожалению ответ тоже, да. Идей и багов намного больше чем времени на них. Анатолий.
|
|
|
|
|
Nov 29 2008, 22:53
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(sonycman @ Nov 29 2008, 23:56)  Там ведь приходится пользоваться громоздкой конструкцией с pragma и примитивными __disable_interrupt() и __enable_interrupt()... Дык гдето в соседней ветке (кажется, "За что я не люблю Си") ктото привел макрос критической секции из цикла for, а я дальше выложил его вариант для IAR'а, с учетом его встроенных intrinsinc'ов. Кстати, есть еще в IAR'е всякие полезности типа __monitor, __save_interrupt и __restore_interrupt. Так что все не так плохо  Цитата(aesok @ Nov 30 2008, 00:36)  К сожалению ответ тоже, да. Я так и думал. Очень жаль. На самом деле внесенный баг весьма серьезен. Вынужден констатировать, что многие опенсорсные проекты в конце концов превращаются в "жрите что дают". Да еще и морально подпитываются говнопиаром класса "халява рулит"  За сим откланиваюсь. Было приятно освежить в памяти подзабытые вещи благодаря конструктивной беседе с Вами.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Nov 29 2008, 23:31
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Rst7 @ Nov 30 2008, 01:53)  Вынужден констатировать, что многие опенсорсные проекты в конце концов превращаются в "жрите что дают". Во первых да, Вы правы: Код $ avr-gcc --version avr-gcc (GCC) 4.4.0 20081129 (experimental) Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Дословный перевод этого и есть: "жрите что дают". Во вторых, Вы ничего не платили и поэтому ничего не вправе требовать, только ждать пока сделают что Вам нужно или сделать сам. Я делаю только то что интересно и нужно мне. Цитата(Rst7 @ Nov 30 2008, 01:53)  Да еще и морально подпитываются говнопиаром класса "халява рулит"  Я могу ответить только за себя. Я НИКОГДА не занимался пиаром свободного софта. ВЫ не найдете ни одного моего призыва чем то пользаваться а чем то нет. Мой выбор очень прост, Я пытаюсь решить задачу наиболее простым и эффективным способом, если для этого нужен коммерческий софт, я ипользую его, если лучше подходит свободный софт, я его применяю. Анатолий. PS: Для чего я этим занимаюсь, Вас не касается.
Сообщение отредактировал aesok - Nov 29 2008, 23:59
|
|
|
|
|
Nov 30 2008, 10:23
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Неважнецки получается у GCC работа со структурой в нижеприведённой функции. Обработчик прерывания usart: Код typedef unsigned char byte;
struct usart_rx_status { byte counter; byte mode; volatile bool data_available; bool frame_err; bool ovrun_err; bool parity_err; bool length_err; bool lock_err; bool chksum_err; bool unknown_command; } statusRx;
ISR(USART_RX_vect) { static byte sign[] PROGMEM = {'S','N'}; static byte length; byte data, state;
do { state = UCSR0A; data = UDR0; if (statusRx.data_available) { statusRx.lock_err = TRUE; continue; } if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) { if (state & (1<<FE0)) statusRx.frame_err = TRUE; if (state & (1<<DOR0)) statusRx.ovrun_err = TRUE; if (state & (1<<UPE0)) statusRx.parity_err = TRUE; statusRx.mode = RX_SEEK; statusRx.counter = 0; continue; } else { statusRx.frame_err = 0; statusRx.ovrun_err = 0; statusRx.parity_err = 0; statusRx.length_err = 0; statusRx.lock_err = 0; statusRx.chksum_err = 0; } switch(statusRx.mode) { case RX_SEEK: if (statusRx.counter < sizeof(sign)) { if (data == pgm_read_byte(sign[statusRx.counter])) { statusRx.counter++; } else { statusRx.counter = 0; } } else { statusRx.counter = 0; if (data >= sizeof(rx_buffer) || data == 0) { statusRx.length_err = TRUE; break; } rx_buffer[statusRx.counter++] = data; length = ++data; statusRx.mode = RX_RUNNING; } break; case RX_RUNNING: rx_buffer[statusRx.counter++] = data; length--; if (!length) { statusRx.data_available = TRUE; statusRx.mode = RX_SEEK; statusRx.counter = 0; } break; }
}while(UCSR0A & (1<<RXC0)); } Вот результат: Код ISR(USART_RX_vect) b10: 1f 92 push r1 b12: 0f 92 push r0 b14: 0f b6 in r0, 0x3f; 63 b16: 0f 92 push r0 b18: 11 24 eor r1, r1 b1a: 0f 93 push r16 b1c: 1f 93 push r17 b1e: 2f 93 push r18 b20: 3f 93 push r19 b22: 4f 93 push r20 b24: 5f 93 push r21 b26: 6f 93 push r22 b28: 7f 93 push r23 b2a: 8f 93 push r24 b2c: 9f 93 push r25 b2e: af 93 push r26 b30: bf 93 push r27 b32: ef 93 push r30 b34: ff 93 push r31 b36: 00 91 8d 01 lds r16, 0x018D b3a: b0 91 9b 01 lds r27, 0x019B b3e: f0 91 99 01 lds r31, 0x0199 b42: e0 91 98 01 lds r30, 0x0198 b46: 70 91 97 01 lds r23, 0x0197 b4a: 60 91 96 01 lds r22, 0x0196 b4e: 50 91 93 01 lds r21, 0x0193 b52: 10 91 94 01 lds r17, 0x0194 b56: 40 91 9a 01 lds r20, 0x019A // errorRx.allbits = 0; byte data, state;
do { state = UCSR0A; b5a: 90 91 c0 00 lds r25, 0x00C0 data = UDR0; b5e: a0 91 c6 00 lds r26, 0x00C6 if (statusRx.data_available) b62: 80 91 95 01 lds r24, 0x0195 b66: 88 23 and r24, r24 b68: 11 f0 breq .+4; 0xb6e <__vector_18+0x5e> b6a: 41 e0 ldi r20, 0x01; 1 b6c: 54 c0 rjmp .+168; 0xc16 <__vector_18+0x106> { statusRx.lock_err = TRUE; continue; } if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) b6e: 29 2f mov r18, r25 b70: 30 e0 ldi r19, 0x00; 0 b72: c9 01 movw r24, r18 b74: 8c 71 andi r24, 0x1C; 28 b76: 90 70 andi r25, 0x00; 0 b78: 89 2b or r24, r25 b7a: 49 f0 breq .+18; 0xb8e <__vector_18+0x7e> { if (state & (1<<FE0)) statusRx.frame_err = TRUE; b7c: 24 fd sbrc r18, 4 b7e: 61 e0 ldi r22, 0x01; 1 if (state & (1<<DOR0)) statusRx.ovrun_err = TRUE; b80: 23 fd sbrc r18, 3 b82: 71 e0 ldi r23, 0x01; 1 if (state & (1<<UPE0)) statusRx.parity_err = TRUE; b84: 22 fd sbrc r18, 2 b86: e1 e0 ldi r30, 0x01; 1 b88: 50 e0 ldi r21, 0x00; 0 b8a: 10 e0 ldi r17, 0x00; 0 b8c: 44 c0 rjmp .+136; 0xc16 <__vector_18+0x106> statusRx.length_err = 0; statusRx.lock_err = 0; statusRx.chksum_err = 0; } // lcdPrintByte(data, 0, 0); switch(statusRx.mode) b8e: 11 23 and r17, r17 b90: 19 f0 breq .+6; 0xb98 <__vector_18+0x88> b92: 11 30 cpi r17, 0x01; 1 b94: d1 f5 brne .+116; 0xc0a <__vector_18+0xfa> b96: 27 c0 rjmp .+78; 0xbe6 <__vector_18+0xd6> { case RX_SEEK: if (statusRx.counter < sizeof(sign)) b98: 52 30 cpi r21, 0x02; 2 b9a: 70 f4 brcc .+28; 0xbb8 <__vector_18+0xa8> { if (data == pgm_read_byte(sign[statusRx.counter])) b9c: e5 2f mov r30, r21 b9e: f0 e0 ldi r31, 0x00; 0 ba0: ec 5c subi r30, 0xCC; 204 ba2: ff 4f sbci r31, 0xFF; 255 ba4: e0 81 ld r30, Z ba6: f0 e0 ldi r31, 0x00; 0 ba8: e4 91 lpm r30, Z+ baa: ae 17 cp r26, r30 bac: 19 f0 breq .+6; 0xbb4 <__vector_18+0xa4> bae: b0 e0 ldi r27, 0x00; 0 bb0: f0 e0 ldi r31, 0x00; 0 bb2: 08 c0 rjmp .+16; 0xbc4 <__vector_18+0xb4> { statusRx.counter++; bb4: 5f 5f subi r21, 0xFF; 255 bb6: 29 c0 rjmp .+82; 0xc0a <__vector_18+0xfa> } } else { statusRx.counter = 0; if (data >= sizeof(rx_buffer) || data == 0) bb8: 8a 2f mov r24, r26 bba: 81 50 subi r24, 0x01; 1 bbc: 8f 31 cpi r24, 0x1F; 31 bbe: 38 f0 brcs .+14; 0xbce <__vector_18+0xbe> bc0: b0 e0 ldi r27, 0x00; 0 bc2: f1 e0 ldi r31, 0x01; 1 bc4: e0 e0 ldi r30, 0x00; 0 bc6: 70 e0 ldi r23, 0x00; 0 bc8: 60 e0 ldi r22, 0x00; 0 bca: 50 e0 ldi r21, 0x00; 0 bcc: 23 c0 rjmp .+70; 0xc14 <__vector_18+0x104> { statusRx.length_err = TRUE; break; } rx_buffer[statusRx.counter++] = data; bce: a0 93 a1 01 sts 0x01A1, r26 length = ++data; bd2: 0a 2f mov r16, r26 bd4: 0f 5f subi r16, 0xFF; 255 bd6: b0 e0 ldi r27, 0x00; 0 bd8: f0 e0 ldi r31, 0x00; 0 bda: e0 e0 ldi r30, 0x00; 0 bdc: 70 e0 ldi r23, 0x00; 0 bde: 60 e0 ldi r22, 0x00; 0 be0: 51 e0 ldi r21, 0x01; 1 be2: 11 e0 ldi r17, 0x01; 1 be4: 17 c0 rjmp .+46; 0xc14 <__vector_18+0x104> // lcdPrintByte(data, 0, 1); statusRx.mode = RX_RUNNING; } break; case RX_RUNNING: rx_buffer[statusRx.counter++] = data; be6: e5 2f mov r30, r21 be8: f0 e0 ldi r31, 0x00; 0 bea: ef 55 subi r30, 0x5F; 95 bec: fe 4f sbci r31, 0xFE; 254 bee: a0 83 st Z, r26 bf0: 5f 5f subi r21, 0xFF; 255 length--; bf2: 01 50 subi r16, 0x01; 1 if (!length) bf4: 51 f4 brne .+20; 0xc0a <__vector_18+0xfa> { statusRx.data_available = TRUE; bf6: 10 93 95 01 sts 0x0195, r17 bfa: b0 e0 ldi r27, 0x00; 0 bfc: f0 e0 ldi r31, 0x00; 0 bfe: e0 e0 ldi r30, 0x00; 0 c00: 70 e0 ldi r23, 0x00; 0 c02: 60 e0 ldi r22, 0x00; 0 c04: 50 e0 ldi r21, 0x00; 0 c06: 10 e0 ldi r17, 0x00; 0 c08: 05 c0 rjmp .+10; 0xc14 <__vector_18+0x104> c0a: b0 e0 ldi r27, 0x00; 0 c0c: f0 e0 ldi r31, 0x00; 0 c0e: e0 e0 ldi r30, 0x00; 0 c10: 70 e0 ldi r23, 0x00; 0 c12: 60 e0 ldi r22, 0x00; 0 c14: 40 e0 ldi r20, 0x00; 0 // statusRx.mode = RX_SEEK; // statusRx.data_available = 0; // errorRx.allbits = 0; byte data, state;
do c16: 80 91 c0 00 lds r24, 0x00C0 c1a: 87 fd sbrc r24, 7 c1c: 9e cf rjmp .-196; 0xb5a <__vector_18+0x4a> c1e: 00 93 8d 01 sts 0x018D, r16 c22: b0 93 9b 01 sts 0x019B, r27 c26: f0 93 99 01 sts 0x0199, r31 c2a: e0 93 98 01 sts 0x0198, r30 c2e: 70 93 97 01 sts 0x0197, r23 c32: 60 93 96 01 sts 0x0196, r22 c36: 50 93 93 01 sts 0x0193, r21 c3a: 10 93 94 01 sts 0x0194, r17 c3e: 40 93 9a 01 sts 0x019A, r20 } break; }
}while(UCSR0A & (1<<RXC0)); } c42: ff 91 pop r31 c44: ef 91 pop r30 c46: bf 91 pop r27 c48: af 91 pop r26 c4a: 9f 91 pop r25 c4c: 8f 91 pop r24 c4e: 7f 91 pop r23 c50: 6f 91 pop r22 c52: 5f 91 pop r21 c54: 4f 91 pop r20 c56: 3f 91 pop r19 c58: 2f 91 pop r18 c5a: 1f 91 pop r17 c5c: 0f 91 pop r16 c5e: 0f 90 pop r0 c60: 0f be out 0x3f, r0; 63 c62: 0f 90 pop r0 c64: 1f 90 pop r1 c66: 18 95 reti 344 байта. У ИАРа тот-же код занимает 278 байт...
|
|
|
|
|
Nov 30 2008, 11:09
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Хоть я и откланялся, но господину sonycman'у отвечу, потому как тема имеет тенденцию сдвигаться в немного другую область, нежели IAR vs GCC. Цитата Неважнецки получается у GCC работа со структурой в нижеприведённой функции. Вообщем-то философия оптимизации данной функции гнусем понятна - загрузить в регистры все что можно и на выходе выгрузить. Подход правильный, основанный на общей идеологии RISC и Load-Store. Но в данном случае он немного не оправдывает себя. IAR подходит к проблеме утилизации Load-Store с более сдержанных позиций, он выполняет эти операции в более локальной окрестности действий с полями структуры. С другой стороны, это позволяет кодеру помочь компилятору в ручном указании, какие переменные стоит загрузить в самом начале (и сохранить в самом конце), какие - нет. Я пришел к следующей эмпирической оценке - оцениваю количество обращений к переменной. Если их больше 3, то имеет смысл переносить переменную в регистр. Причем, чем больше обращений (с учетом циклов), тем выше приоритет переменной на перенос в регистр. Ну и не забывать, что операция a=b++ - суть 2 обращения, а иногда и 3. Можно ли так подсказать гнусю - я затрудняюсь ответить, необходимо проверять. Кроме того, я бы флаги ошибок собрал бы в битовой структуре. Так проще. В результате, получился бы примерно следующий код (IAR) Код typedef struct { byte frame_err:1,ovrun_err:1,parity_err:1,length_err:1,lock_err:1,chksum_err:1,unknown_command:1; } USART_ERRORS;
struct usart_rx_status { byte counter; byte mode; volatile byte data_available; USART_ERRORS err; } statusRx;
#pragma vector=USART_RX_vect __interrupt void ISR_USART_RX(void) { static __flash byte sign[] = {'S','N'}; static byte save_length; byte data, state; USART_ERRORS err=statusRx.err; byte length=save_length; byte counter=statusRx.counter; do { state = UCSR0A; data = UDR0; if (statusRx.data_available) { err.lock_err = TRUE; continue; } if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) { if (state & (1<<FE0)) err.frame_err = TRUE; if (state & (1<<DOR0)) err.ovrun_err = TRUE; if (state & (1<<UPE0)) err.parity_err = TRUE; statusRx.mode = RX_SEEK; counter = 0; continue; } else { err.frame_err = 0; err.ovrun_err = 0; err.parity_err = 0; err.length_err = 0; err.lock_err = 0; err.chksum_err = 0; } switch(statusRx.mode) { case RX_SEEK: if (counter < sizeof(sign)) { if (data == sign[counter]) { counter++; } else { counter = 0; } } else { counter = 0; if (data >= sizeof(rx_buffer) || data == 0) { err.length_err = TRUE; break; } rx_buffer[counter++] = data; length = ++data; statusRx.mode = RX_RUNNING; } break; case RX_RUNNING: rx_buffer[counter++] = data; length--; if (!length) { statusRx.data_available = TRUE; statusRx.mode = RX_SEEK; counter = 0; } break; } }while(UCSR0A & (1<<RXC0)); save_length=length; statusRx.err=err; statusRx.counter=counter; } и результат Код // 27 __interrupt void ISR_USART_RX(void) ISR_USART_RX: // 28 { ST -Y, R27 ST -Y, R26 ST -Y, R31 ST -Y, R30 ST -Y, R22 ST -Y, R21 ST -Y, R20 ST -Y, R19 ST -Y, R18 ST -Y, R17 ST -Y, R16 IN R22, 0x3F // 29 static __flash byte sign[] = {'S','N'}; // 30 static byte save_length; // 31 byte data, state; // 32 USART_ERRORS err=statusRx.err; LDI R26, LOW(statusRx) LDI R27, (statusRx) >> 8 MOVW R31:R30, R27:R26 LDD R16, Z+3 // 33 byte length=save_length; LDD R19, Z+4 // 34 byte counter=statusRx.counter; LD R18, X // 35 // 36 do // 37 { // 38 state = UCSR0A; ??ISR_USART_RX_0: LDS R21, 192 // 39 data = UDR0; LDS R17, 198 // 40 if (statusRx.data_available) MOVW R31:R30, R27:R26 LDD R20, Z+2 TST R20 BREQ ??ISR_USART_RX_1 // 41 { // 42 err.lock_err = TRUE; ORI R16, 0x10 // 43 continue; RJMP ??ISR_USART_RX_2 // 44 } // 45 if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0))) ??ISR_USART_RX_1: MOV R20, R21 ANDI R20, 0x1C BREQ ??ISR_USART_RX_3 // 46 { // 47 if (state & (1<<FE0)) err.frame_err = TRUE; BST R21, 4 BRTC ??ISR_USART_RX_4 ORI R16, 0x01 // 48 if (state & (1<<DOR0)) err.ovrun_err = TRUE; ??ISR_USART_RX_4: BST R21, 3 BRTC ??ISR_USART_RX_5 ORI R16, 0x02 // 49 if (state & (1<<UPE0)) err.parity_err = TRUE; ??ISR_USART_RX_5: BST R21, 2 BRTC ??ISR_USART_RX_6 ORI R16, 0x04 // 50 statusRx.mode = RX_SEEK; RJMP ??ISR_USART_RX_6 // 51 counter = 0; // 52 continue; // 53 } // 54 else // 55 { // 56 err.frame_err = 0; // 57 err.ovrun_err = 0; // 58 err.parity_err = 0; // 59 err.length_err = 0; // 60 err.lock_err = 0; // 61 err.chksum_err = 0; ??ISR_USART_RX_3: ANDI R16, 0xC0 // 62 } // 63 switch(statusRx.mode) LDD R20, Z+1 SUBI R20, 0 BREQ ??ISR_USART_RX_7 DEC R20 BREQ ??ISR_USART_RX_8 RJMP ??ISR_USART_RX_2 // 64 { // 65 case RX_SEEK: // 66 if (counter < sizeof(sign)) ??ISR_USART_RX_7: CPI R18, 2 BRCC ??ISR_USART_RX_9 // 67 { // 68 if (data == sign[counter]) LDI R31, 0 MOV R30, R18 SUBI R30, LOW((-(??sign) & 0xFFFF)) SBCI R31, (-(??sign) & 0xFFFF) >> 8 LPM R20, Z CP R17, R20 BRNE ??ISR_USART_RX_10 // 69 { // 70 counter++; INC R18 RJMP ??ISR_USART_RX_2 // 71 } // 72 else // 73 { // 74 counter = 0; // 75 } // 76 } // 77 else // 78 { // 79 counter = 0; ??ISR_USART_RX_9: LDI R18, 0 // 80 if (data >= sizeof(rx_buffer) || data == 0) CPI R17, 100 BRCC ??ISR_USART_RX_11 TST R17 BRNE ??ISR_USART_RX_12 // 81 { // 82 err.length_err = TRUE; ??ISR_USART_RX_11: ORI R16, 0x08 // 83 break; RJMP ??ISR_USART_RX_2 // 84 } // 85 rx_buffer[counter++] = data; ??ISR_USART_RX_12: STS rx_buffer, R17 LDI R18, 1 // 86 length = ++data; MOV R19, R17 INC R19 // 87 statusRx.mode = RX_RUNNING; STD Z+1, R18 RJMP ??ISR_USART_RX_2 // 88 } // 89 break; // 90 case RX_RUNNING: // 91 rx_buffer[counter++] = data; ??ISR_USART_RX_8: LDI R31, 0 MOV R30, R18 SUBI R30, LOW((-(rx_buffer) & 0xFFFF)) SBCI R31, (-(rx_buffer) & 0xFFFF) >> 8 ST Z, R17 INC R18 // 92 length--; DEC R19 // 93 if (!length) TST R19 BRNE ??ISR_USART_RX_2 // 94 { // 95 statusRx.data_available = TRUE; LDI R17, 1 MOVW R31:R30, R27:R26 STD Z+2, R17 // 96 statusRx.mode = RX_SEEK; ??ISR_USART_RX_6: LDI R17, 0 STD Z+1, R17 // 97 counter = 0; ??ISR_USART_RX_10: LDI R18, 0 // 98 } // 99 break; // 100 } // 101 // 102 }while(UCSR0A & (1<<RXC0)); ??ISR_USART_RX_2: LDS R17, 192 SBRC R17, 7 RJMP ??ISR_USART_RX_0 // 103 save_length=length; MOVW R31:R30, R27:R26 STD Z+4, R19 // 104 statusRx.err=err; STD Z+3, R16 // 105 statusRx.counter=counter; ST X, R18 // 106 } OUT 0x3F, R22 LD R16, Y+ LD R17, Y+ LD R18, Y+ LD R19, Y+ LD R20, Y+ LD R21, Y+ LD R22, Y+ LD R30, Y+ LD R31, Y+ LD R26, Y+ LD R27, Y+ RETI
.... // 218 bytes in segment CODE Попробуйте сделать аналогичный финт с гнусем, посмотрим, как он себя поведет.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
  |
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0
|
|
|