Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAVR обновился до 20081118rc2
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
Alex_NEMO
Release Candidate 20081118rc2

File Release Notes and Changelog

Release Name: 20081118rc2

Notes:
Below is just a sample of what's new.

- New version of GNU Binutils: 2.19

- New version of GCC: 4.3.2

- New version of AVR-LibC: 1.6.4

- New version of Programmers Notepad: 2.0.8.718

- New devices supported:
* ATxmega64A3
* ATxmega128A3
* ATxmega256A3
* ATxmega256A3B
* ATmega32U6

- Various bugs fixed.
sonycman
Что то потянуло попробовать этот компилятор.
Хочу посмотреть, не будет ли он лучше ИАРа. А то последний запарил уже глупой работой с указателями. А вчера вообще в куске кода вида:
unsigned char a, b;
if (a > (b +10)) ...
заметил, что байтные переменные обрабатывались как слова... :-(
Спрашивается - какого чёрта? Мне вот эта самодеятельность совершенно не нравится.

Установил WinAVR, в AVRStudio создал проект, добавил файлы. Но как заствить компилятор понимать СИ++? Он упорно ругается на bool и другие фишки плюса...
Пробую этот компилятор впервые...
Непомнящий Евгений
Цитата(sonycman @ Nov 21 2008, 12:02) *
А вчера вообще в куске кода вида:
unsigned char a, b;
if (a > (b +10)) ...
заметил, что байтные переменные обрабатывались как слова... :-(


Все по стандарту - в арифметических выражениях unsigned char продвигается до unsigned int ...
GCC по-идее. так же будет работать.
_Pasha
Цитата(sonycman @ Nov 21 2008, 13:02) *
unsigned char a, b;
if (a > (b +10)) ...

А Вы хотели, чтобы если b=250, а=16, то (b+10) чтоб резко стало меньше а lol.gif
Сергей Борщ
Цитата(sonycman @ Nov 21 2008, 11:02) *
Установил WinAVR, в AVRStudio создал проект, добавил файлы. Но как заствить компилятор понимать СИ++? Он упорно ругается на bool и другие фишки плюса...
он определяет по расширению исходного файла. .cpp компилируется в режиме С++. Будьте готовы в ближайшее время изучать make и язык его makefile, ибо то, что генерит студия вас скоро перестанет устраивать.
demiurg_spb
Цитата(sonycman @ Nov 21 2008, 12:02) *
Установил WinAVR, в AVRStudio создал проект, добавил файлы. Но как заствить компилятор понимать СИ++? Он упорно ругается на bool и другие фишки плюса...
Забудьте про IDE:) FAR+colorer+makefile и в путь!
sonycman
Цитата(Непомнящий Евгений @ Nov 21 2008, 13:12) *
Все по стандарту - в арифметических выражениях unsigned char продвигается до unsigned int ...
GCC по-идее. так же будет работать.

Так и думал, что типа так положено. Кто только не придумывает эти стандарты... cranky.gif

Однако, при максимальной оптимизации по скорости и по размеру кода, это выражение выглядит просто дико - тогда, когда оно могло было быть в два раза быстрее и в два раза меньше 07.gif
Не менее глупо выглядит такое:
unsigned char a, b;
if (a > (byte)(b +10)) ...
но код становится правильным laughing.gif

Цитата(_Pasha @ Nov 21 2008, 13:45) *
А Вы хотели, чтобы если b=250, а=16, то (b+10) чтоб резко стало меньше а lol.gif

Да нет, слава богу, пока такое не задумывал rolleyes.gif

Цитата(Сергей Борщ @ Nov 21 2008, 14:47) *
он определяет по расширению исходного файла. .cpp компилируется в режиме С++. Будьте готовы в ближайшее время изучать make и язык его makefile, ибо то, что генерит студия вас скоро перестанет устраивать.

Хм, да, пошарился тут по сети, и кое-какие заявления о том, что для поддержки С++ нужно что-то там пересобрать (перекомпилировать???) ставят в тупик... б-рр-р, ох уже этот линукс wacko.gif

Цитата(demiurg_spb @ Nov 21 2008, 15:02) *
Забудьте про IDE:) FAR+colorer+makefile и в путь!

Ну, я пока неплохо себя чувствую со SlickEdit и IAR. Хочу просто сравнить компиляторы. Вдруг понравится?

Спасибо всем за помощь! a14.gif
Rst7
Цитата
А то последний запарил уже глупой работой с указателями.


Например?
sonycman
Цитата(Rst7 @ Nov 21 2008, 18:29) *
Например?

А вот эту тему посмотрите: тута.
Вы же тогда сами мне подсказывали smile.gif

ЗЫ: видимо AVR Studio с интегрированным WinAVR никак не заставить компилировать C++.
Среда отказывается компилировать файлы с расширением, отличным от .с...
Через внешний makefile это возможно, но что-то не особо прельщает искать ошибки по номерам строчек в файлах, так как клик по сообщению не работает...
Млин, каменный век какой-то...
Может, когда времени больше будет smile.gif
Сергей Борщ
Цитата(sonycman @ Nov 21 2008, 17:50) *
Через внешний makefile это возможно, но что-то не особо прельщает искать ошибки по номерам строчек в файлах, так как клик по сообщению не работает...
Очень странно. У меня работало. Просто в настройках проекта указать Custom (или External?) Makefile и все. Парсер вывода ведь никуда не денется. А еще можно отказаться от студии и работать в Эклипсе, а студию изредка использовать как симулятор, загружая в нее .elf.
sonycman
Цитата(Сергей Борщ @ Nov 21 2008, 22:11) *
Очень странно. У меня работало. Просто в настройках проекта указать Custom (или External?) Makefile и все. Парсер вывода ведь никуда не денется. А еще можно отказаться от студии и работать в Эклипсе, а студию изредка использовать как симулятор, загружая в нее .elf.

Эклипс? Не юзал пока. А СликЭдит не подойдёт?

Скомпильнул небольшой код, и мне оптимизация ГНУ показалась интересной. Есть некоторые моменты, которые ИАР (5.10) даже не пытался затронуть, в отличие от, так сказать. Правда, очень уж любит ГНУ разворачивать подпрограммы, размерчик в итоге, думаю, получится посолидней... biggrin.gif
Тестил ГНУ на О3 и на Оs, а ИАР на макс. по скорости...

ЗЫ: вот напоследок перл от ИАРА:
Дано:
Код
#define RPM_MIN 0
#define RPM_MED 1
#define RPM_MAX 2

typedef    unsigned char    byte;

struct    frDatatable
{
    byte    min_speed;
    byte    med_speed;
    byte    max_speed;
    byte    min_temp;
    byte    max_temp;
} data;

    byte    RPMval[3];
    byte    minTEMPval;
    byte    maxTEMPval;

void    CFanRegulator::SetData(frDatatable *data)
{
    RPMval[RPM_MIN]    =    data->min_speed;
    RPMval[RPM_MED]    =    data->med_speed;
    RPMval[RPM_MAX]    =    data->max_speed;
    minTEMPval    =    data->min_temp;
    maxTEMPval    =    data->max_temp;
}

Вроде проще некуда. В итоге имеем:
Код
void    CFanRegulator::SetData(frDatatable *data)
   \                     ??SetData:
     15          {
     16              RPMval[RPM_MIN]    =    data->min_speed;
   \   00000000   01F9               MOVW    R31:R30, R19:R18
   \   00000002   8140               LD      R20, Z
   \   00000004   01F8               MOVW    R31:R30, R17:R16
   \   00000006   8345               STD     Z+5, R20
     17              RPMval[RPM_MED]    =    data->med_speed;
   \   00000008   01F9               MOVW    R31:R30, R19:R18
   \   0000000A   8141               LDD     R20, Z+1
   \   0000000C   01F8               MOVW    R31:R30, R17:R16
   \   0000000E   8346               STD     Z+6, R20
     18              RPMval[RPM_MAX]    =    data->max_speed;
   \   00000010   01F9               MOVW    R31:R30, R19:R18
   \   00000012   8142               LDD     R20, Z+2
   \   00000014   01F8               MOVW    R31:R30, R17:R16
   \   00000016   8347               STD     Z+7, R20
     19              minTEMPval    =    data->min_temp;
   \   00000018   01F9               MOVW    R31:R30, R19:R18
   \   0000001A   8143               LDD     R20, Z+3
   \   0000001C   01F8               MOVW    R31:R30, R17:R16
   \   0000001E   8740               STD     Z+8, R20
     20              maxTEMPval    =    data->max_temp;
   \   00000020   01F9               MOVW    R31:R30, R19:R18
   \   00000022   8124               LDD     R18, Z+4
   \   00000024   01F8               MOVW    R31:R30, R17:R16
   \   00000026   8721               STD     Z+9, R18
     21          }
   \   00000028   9508               RET

Просто аццкая куча кода biggrin.gif
Раз указатель грузится каждый раз заново - зачем он здесь вообще нужен?
К чему так заморачиваться - надо было авторам LDS использовать - эффект тот-же cranky.gif
И такое встречается частенько.
Вроде хороший компилер, но работа с указателями похабная.
Из трёх регистровых пар практически используется только одна.

А вот ГНУ такой фигнёй, похоже, не страдает wink.gif
ukpyr
Цитата
А вот ГНУ такой фигнёй, похоже, не страдает

ну дык, зачем тогда платить ?
новые версии выходят регулярно, комьюнити и охват ахитектур огромные.
Сергей Борщ
Цитата(sonycman @ Nov 21 2008, 22:02) *
Эклипс? Не юзал пока. А СликЭдит не подойдёт?
Пойдет. Лично не пользовал, но уважаемые форумчане хвалят.
Цитата(sonycman @ Nov 21 2008, 22:02) *
Тестил ГНУ на О3 и на Оз, а ИАР на макс. по скорости...
Дык... O3 - это для больших машин с кучей памяти. Инлайн и разворот циклов где только можно в погоне за скоростью. Для AVR оптимальным является Os. Кроме того там есть еще куча ключей для тонкой настройки. Ваш код действительно дал какой-то неадекватный результат. Для ИАРа оптимизация по скорости очень часто дает меньший код, чем оптимизация по размеру (парадокс!). Попробуйте включить кластеризацию переменных, и вообще все галочки, которые доступны в дополнительных параметрах оптимизации.
manul78
Цитата(Сергей Борщ @ Nov 21 2008, 21:11) *
А еще можно отказаться от студии и работать в Эклипсе, а студию изредка использовать как симулятор, загружая в нее .elf.


Вот вот, именно так и я делаю. Разделение труда. Пакет ГНУ для кода, а Студия для отладки.

И все работает как часы... yeah.gif
IgorKossak
Цитата(sonycman @ Nov 21 2008, 22:02) *
Просто аццкая куча кода biggrin.gif

Поставьте перед функцией __z, а ещё лучше __x (передавать указатель через регистровую пару весьма разумно) или оптимизацию установите по объёму и будет Вам счастье.
sonycman
Цитата(Сергей Борщ @ Nov 22 2008, 02:29) *
Пойдет. Лично не пользовал, но уважаемые форумчане хвалят.Дык... O3 - это для больших машин с кучей памяти. Инлайн и разворот циклов где только можно в погоне за скоростью. Для AVR оптимальным является Os. Кроме того там есть еще куча ключей для тонкой настройки. Ваш код действительно дал какой-то неадекватный результат. Для ИАРа оптимизация по скорости очень часто дает меньший код, чем оптимизация по размеру (парадокс!). Попробуйте включить кластеризацию переменных, и вообще все галочки, которые доступны в дополнительных параметрах оптимизации.

Пробовал - не помогает.
Исправляюсь - кроме О3 тестил ещё и на Os. Да, последний режим давал более приемлимые результаты smile.gif

Цитата(IgorKossak @ Nov 22 2008, 02:50) *
Поставьте перед функцией __z, а ещё лучше __x (передавать указатель через регистровую пару весьма разумно) или оптимизацию установите по объёму и будет Вам счастье.

Не всё так просто.
Не спасает ничего, кроме установки перед функцией ключа __x_z. Но почему я должен каждую микроскопическую функцию проверять и персонально настраивать под оптимальную генерацию руками?
На это нужна куча времени!
Rst7
Цитата(sonycman @ Nov 22 2008, 04:01) *
Но почему я должен каждую микроскопическую функцию проверять и персонально настраивать под оптимальную генерацию руками?
На это нужна куча времени!

Плохо. Не спорю. К сожалению, у меня нет официально купленного иара, так бы я конечно с них бы не слез и заставил бы лечить работу с указателями. Если бы кто откликнулся, кто покупал официально и согласился бы на переписку от его имени, я думаю, вопрос можно было бы решить.

Еще хуже другое. Я тут в теме про сборки klen'а отписывал про ахинею с версией 4.4.0 (имеется в виду самописный memcpy с итератором char). Так вот этот предрелиз WinAVR ведет себя также ужасно. Я бы не советовал переходить на него.
AHTOXA
Цитата(Rst7 @ Nov 23 2008, 02:32) *
Еще хуже другое. Я тут в теме про сборки klen'а отписывал про ахинею с версией 4.4.0 (имеется в виду самописный memcpy с итератором char). Так вот этот предрелиз WinAVR ведет себя также ужасно. Я бы не советовал переходить на него.


WinAVR, имхо, всё хужеет и хужеетsad.gif
Rst7
Цитата(AHTOXA @ Nov 22 2008, 23:39) *
WinAVR, имхо, всё хужеет и хужеетsad.gif

Гнусь становится все более гнусным smile.gif

По крайней мере в AVR'овской ипостаси.
NetTracer
Цитата(Alex_NEMO @ Nov 20 2008, 15:22) *
...
- Various bugs fixed.

Вот с ЭТОГО бы места да поподробнее. sad.gif
Alex_NEMO
Цитата(NetTracer @ Nov 23 2008, 11:22) *
Вот с ЭТОГО бы места да поподробнее. sad.gif

Не по адресу вопрос! Когда релиз выйдет, возможно, распишут более подробно!
Но то, что новых добавят - это несомненно! (См. ветку)
sonycman
Портировал я свою программу с IARа на GCC.
Оптимизация максимальная по скорости у первого, и Os с ключами -mcall-prologues -fno-inline-small-functions -fno-threadsafe-statics -ffunction-sections --gc-sections --relax у второго.
В результате код IARа - 6 090 bytes of CODE memory + 493 bytes of DATA memory.
Код GCC - Program: 7120 bytes + Data: 363 bytes.

Код иара компактнее свыше чем на килобайт. Правда, некоторые функции "тюнингованы" специальными ключами (типа __z_x и т.д.) для оптимальной генерации.
Добавление некоторых аттрибутов для функций в GCC в аналогичных целях, к сожалению, не дало абсолютно никакого результата...

На первый взгляд, скомпилированный GCC код весьма красив и аккуратен, за исключением излишней любви к LDS и STS, например:
исходный текст:
Код
    case    USART_SEND_DATA_EX:
        length    =    4 + 4 + 4 + 20;
        *pb++    =    length + 1;
        *pb++    =    command;
        *pb++    =    temperature.cpu;
        *pb++    =    temperature.gpu;
        *pb++    =    temperature.amb;
        *pb++    =    temperature.hdd;
        *pb++   =   fan_speed[0];
        *pb++   =   fan_speed[1];
        *pb++   =   fan_speed[2];
        *pb++   =   fan_speed[3];
        *pb++    =    cpuFan.GetCurrentSpeed();
        *pb++    =    rearFan.GetCurrentSpeed();
        *pb++    =    sideFan.GetCurrentSpeed();
        *pb++    =    frontFan.GetCurrentSpeed();
    *pb++    =    cpuFan.RPMval[RPM_MIN];
    *pb++    =    cpuFan.RPMval[RPM_MED];
    *pb++    =    cpuFan.RPMval[RPM_MAX];
    *pb++    =    cpuFan.minTEMPval;
    *pb++    =    cpuFan.maxTEMPval;
    *pb++    =    rearFan.RPMval[RPM_MIN];
    *pb++    =    rearFan.RPMval[RPM_MED];
    *pb++    =    rearFan.RPMval[RPM_MAX];
    *pb++    =    rearFan.minTEMPval;
    *pb++    =    rearFan.maxTEMPval;
    *pb++    =    sideFan.RPMval[RPM_MIN];
    *pb++    =    sideFan.RPMval[RPM_MED];
    *pb++    =    sideFan.RPMval[RPM_MAX];
    *pb++    =    sideFan.minTEMPval;
    *pb++    =    sideFan.maxTEMPval;
    *pb++    =    frontFan.RPMval[RPM_MIN];
    *pb++    =    frontFan.RPMval[RPM_MED];
    *pb++    =    frontFan.RPMval[RPM_MAX];
    *pb++    =    frontFan.minTEMPval;
    *pb++    =    frontFan.maxTEMPval;
    break;

результат IARа:
Код
    105              case    USART_SEND_DATA_EX:
    106                  length    =    4 + 4 + 4 + 20;
   \                     ??usartSendCommand_4:
   \   000000C4   E280               LDI     R24, 32
    107                  *pb++    =    length + 1;
   \   000000C6   E201               LDI     R16, 33
   \   000000C8   930D               ST      X+, R16
    108                  *pb++    =    command;
   \   000000CA   934D               ST      X+, R20
    109                  *pb++    =    temperature.cpu;
   \   000000CC   9100....           LDS     R16, temperature
   \   000000D0   930D               ST      X+, R16
    110                  *pb++    =    temperature.gpu;
   \   000000D2   9100....           LDS     R16, (temperature + 1)
   \   000000D6   930D               ST      X+, R16
    111                  *pb++    =    temperature.amb;        
   \   000000D8   9100....           LDS     R16, (temperature + 2)
   \   000000DC   930D               ST      X+, R16
    112                  *pb++    =    temperature.hdd;        
   \   000000DE   9100....           LDS     R16, (temperature + 3)
   \   000000E2   930D               ST      X+, R16
    113                  *pb++   =   fan_speed[0];
   \   000000E4   9100....           LDS     R16, fan_speed
   \   000000E8   930D               ST      X+, R16
    114                  *pb++   =   fan_speed[1];
   \   000000EA   9100....           LDS     R16, (fan_speed + 1)
   \   000000EE   930D               ST      X+, R16
    115                  *pb++   =   fan_speed[2];
   \   000000F0   9100....           LDS     R16, (fan_speed + 2)
   \   000000F4   930D               ST      X+, R16
    116                  *pb++   =   fan_speed[3];
   \   000000F6   9100....           LDS     R16, (fan_speed + 3)
   \   000000FA   930D               ST      X+, R16
    117                  *pb++    =    cpuFan.GetCurrentSpeed();
   \   000000FC   ....               LDI     R16, LOW(cpuFan)
   \   000000FE   ....               LDI     R17, (cpuFan) >> 8
   \   00000100   ....               RCALL   ??GetCurrentSpeed
   \   00000102   930D               ST      X+, R16
    118                  *pb++    =    rearFan.GetCurrentSpeed();
   \   00000104   ....               LDI     R16, LOW(rearFan)
   \   00000106   ....               LDI     R17, (rearFan) >> 8
   \   00000108   ....               RCALL   ??GetCurrentSpeed
   \   0000010A   930D               ST      X+, R16
    119                  *pb++    =    sideFan.GetCurrentSpeed();
   \   0000010C   ....               LDI     R16, LOW(sideFan)
   \   0000010E   ....               LDI     R17, (sideFan) >> 8
   \   00000110   ....               RCALL   ??GetCurrentSpeed
   \   00000112   930D               ST      X+, R16
    120                  *pb++    =    frontFan.GetCurrentSpeed();
   \   00000114   ....               LDI     R16, LOW(frontFan)
   \   00000116   ....               LDI     R17, (frontFan) >> 8
   \   00000118   ....               RCALL   ??GetCurrentSpeed
   \   0000011A   930D               ST      X+, R16
    121                  *pb++    =    cpuFan.RPMval[RPM_MIN];
   \   0000011C   9100....           LDS     R16, (cpuFan + 5)
   \   00000120   930D               ST      X+, R16
    122                  *pb++    =    cpuFan.RPMval[RPM_MED];
   \   00000122   9100....           LDS     R16, (cpuFan + 6)
   \   00000126   930D               ST      X+, R16
    123                  *pb++    =    cpuFan.RPMval[RPM_MAX];
   \   00000128   9100....           LDS     R16, (cpuFan + 7)
   \   0000012C   930D               ST      X+, R16
    124                  *pb++    =    cpuFan.minTEMPval;
   \   0000012E   9100....           LDS     R16, (cpuFan + 8)
   \   00000132   930D               ST      X+, R16
    125                  *pb++    =    cpuFan.maxTEMPval;
   \   00000134   9100....           LDS     R16, (cpuFan + 9)
   \   00000138   930D               ST      X+, R16
    126                  *pb++    =    rearFan.RPMval[RPM_MIN];
   \   0000013A   9100....           LDS     R16, (rearFan + 5)
   \   0000013E   930D               ST      X+, R16
    127                  *pb++    =    rearFan.RPMval[RPM_MED];
   \   00000140   9100....           LDS     R16, (rearFan + 6)
   \   00000144   930D               ST      X+, R16
    128                  *pb++    =    rearFan.RPMval[RPM_MAX];
   \   00000146   9100....           LDS     R16, (rearFan + 7)
   \   0000014A   930D               ST      X+, R16
    129                  *pb++    =    rearFan.minTEMPval;
   \   0000014C   9100....           LDS     R16, (rearFan + 8)
   \   00000150   930D               ST      X+, R16
    130                  *pb++    =    rearFan.maxTEMPval;
   \   00000152   9100....           LDS     R16, (rearFan + 9)
   \   00000156   930D               ST      X+, R16
    131                  *pb++    =    sideFan.RPMval[RPM_MIN];
   \   00000158   9100....           LDS     R16, (sideFan + 5)
   \   0000015C   930D               ST      X+, R16
    132                  *pb++    =    sideFan.RPMval[RPM_MED];
   \   0000015E   9100....           LDS     R16, (sideFan + 6)
   \   00000162   930D               ST      X+, R16
    133                  *pb++    =    sideFan.RPMval[RPM_MAX];
   \   00000164   9100....           LDS     R16, (sideFan + 7)
   \   00000168   930D               ST      X+, R16
    134                  *pb++    =    sideFan.minTEMPval;
   \   0000016A   9100....           LDS     R16, (sideFan + 8)
   \   0000016E   930D               ST      X+, R16
    135                  *pb++    =    sideFan.maxTEMPval;
   \   00000170   9100....           LDS     R16, (sideFan + 9)
   \   00000174   930D               ST      X+, R16
    136                  *pb++    =    frontFan.RPMval[RPM_MIN];
   \   00000176   9100....           LDS     R16, (frontFan + 5)
   \   0000017A   930D               ST      X+, R16
    137                  *pb++    =    frontFan.RPMval[RPM_MED];
   \   0000017C   9100....           LDS     R16, (frontFan + 6)
   \   00000180   930D               ST      X+, R16
    138                  *pb++    =    frontFan.RPMval[RPM_MAX];
   \   00000182   9100....           LDS     R16, (frontFan + 7)
   \   00000186   930D               ST      X+, R16
    139                  *pb++    =    frontFan.minTEMPval;
   \   00000188   9100....           LDS     R16, (frontFan + 8)
   \   0000018C   930D               ST      X+, R16
    140                  *pb++    =    frontFan.maxTEMPval;
   \   0000018E   9100....           LDS     R16, (frontFan + 9)
   \   00000192   CF96               RJMP    ??usartSendCommand_12
    141                  break;

вполне прилично.
А вот у GCC:
Код
    case    USART_SEND_DATA_EX:
        length    =    4 + 4 + 4 + 20;
        *pb++    =    length + 1;
    153c:    81 e2           ldi    r24, 0x21; 33
    153e:    80 93 ed 01     sts    0x01ED, r24
        *pb++    =    command;
    1542:    90 93 ee 01     sts    0x01EE, r25
        *pb++    =    temperature.cpu;
    1546:    80 91 34 01     lds    r24, 0x0134
    154a:    80 93 ef 01     sts    0x01EF, r24
        *pb++    =    temperature.gpu;
    154e:    80 91 35 01     lds    r24, 0x0135
    1552:    80 93 f0 01     sts    0x01F0, r24
        *pb++    =    temperature.amb;
    1556:    80 91 36 01     lds    r24, 0x0136
    155a:    80 93 f1 01     sts    0x01F1, r24
        *pb++    =    temperature.hdd;
    155e:    80 91 37 01     lds    r24, 0x0137
    1562:    80 93 f2 01     sts    0x01F2, r24
        *pb++   =   fan_speed[0];
    1566:    80 91 6f 01     lds    r24, 0x016F
    156a:    80 93 f3 01     sts    0x01F3, r24
        *pb++   =   fan_speed[1];
    156e:    80 91 70 01     lds    r24, 0x0170
    1572:    80 93 f4 01     sts    0x01F4, r24
        *pb++   =   fan_speed[2];
    1576:    80 91 71 01     lds    r24, 0x0171
    157a:    80 93 f5 01     sts    0x01F5, r24
        *pb++   =   fan_speed[3];
    157e:    80 91 72 01     lds    r24, 0x0172
    1582:    80 93 f6 01     sts    0x01F6, r24
        *pb++    =    cpuFan.GetCurrentSpeed();
    1586:    87 e3           ldi    r24, 0x37; 55
    1588:    92 e0           ldi    r25, 0x02; 2
    158a:    4c d7           rcall    .+3736  ; 0x2424 <__data_load_end+0x6fe>
    158c:    80 93 f7 01     sts    0x01F7, r24
        *pb++    =    rearFan.GetCurrentSpeed();
    1590:    81 e4           ldi    r24, 0x41; 65
    1592:    92 e0           ldi    r25, 0x02; 2
    1594:    47 d7           rcall    .+3726  ; 0x2424 <__data_load_end+0x6fe>
    1596:    80 93 f8 01     sts    0x01F8, r24
        *pb++    =    sideFan.GetCurrentSpeed();
    159a:    8b e4           ldi    r24, 0x4B; 75
    159c:    92 e0           ldi    r25, 0x02; 2
    159e:    42 d7           rcall    .+3716  ; 0x2424 <__data_load_end+0x6fe>
    15a0:    80 93 f9 01     sts    0x01F9, r24
        *pb++    =    frontFan.GetCurrentSpeed();
    15a4:    85 e5           ldi    r24, 0x55; 85
    15a6:    92 e0           ldi    r25, 0x02; 2
    15a8:    3d d7           rcall    .+3706  ; 0x2424 <__data_load_end+0x6fe>
    15aa:    80 93 fa 01     sts    0x01FA, r24
        *pb++    =    cpuFan.RPMval[RPM_MIN];
    15ae:    80 91 3c 02     lds    r24, 0x023C
    15b2:    80 93 fb 01     sts    0x01FB, r24
        *pb++    =    cpuFan.RPMval[RPM_MED];
    15b6:    80 91 3d 02     lds    r24, 0x023D
    15ba:    80 93 fc 01     sts    0x01FC, r24
        *pb++    =    cpuFan.RPMval[RPM_MAX];
    15be:    80 91 3e 02     lds    r24, 0x023E
    15c2:    80 93 fd 01     sts    0x01FD, r24
        *pb++    =    cpuFan.minTEMPval;
    15c6:    80 91 3f 02     lds    r24, 0x023F
    15ca:    80 93 fe 01     sts    0x01FE, r24
        *pb++    =    cpuFan.maxTEMPval;
    15ce:    80 91 40 02     lds    r24, 0x0240
    15d2:    80 93 ff 01     sts    0x01FF, r24
        *pb++    =    rearFan.RPMval[RPM_MIN];
    15d6:    80 91 46 02     lds    r24, 0x0246
    15da:    80 93 00 02     sts    0x0200, r24
        *pb++    =    rearFan.RPMval[RPM_MED];
    15de:    80 91 47 02     lds    r24, 0x0247
    15e2:    80 93 01 02     sts    0x0201, r24
        *pb++    =    rearFan.RPMval[RPM_MAX];
    15e6:    80 91 48 02     lds    r24, 0x0248
    15ea:    80 93 02 02     sts    0x0202, r24
        *pb++    =    rearFan.minTEMPval;
    15ee:    80 91 49 02     lds    r24, 0x0249
    15f2:    80 93 03 02     sts    0x0203, r24
        *pb++    =    rearFan.maxTEMPval;
    15f6:    80 91 4a 02     lds    r24, 0x024A
    15fa:    80 93 04 02     sts    0x0204, r24
        *pb++    =    sideFan.RPMval[RPM_MIN];
    15fe:    80 91 50 02     lds    r24, 0x0250
    1602:    80 93 05 02     sts    0x0205, r24
        *pb++    =    sideFan.RPMval[RPM_MED];
    1606:    80 91 51 02     lds    r24, 0x0251
    160a:    80 93 06 02     sts    0x0206, r24
        *pb++    =    sideFan.RPMval[RPM_MAX];
    160e:    80 91 52 02     lds    r24, 0x0252
    1612:    80 93 07 02     sts    0x0207, r24
        *pb++    =    sideFan.minTEMPval;
    1616:    80 91 53 02     lds    r24, 0x0253
    161a:    80 93 08 02     sts    0x0208, r24
        *pb++    =    sideFan.maxTEMPval;
    161e:    80 91 54 02     lds    r24, 0x0254
    1622:    80 93 09 02     sts    0x0209, r24
        *pb++    =    frontFan.RPMval[RPM_MIN];
    1626:    80 91 5a 02     lds    r24, 0x025A
    162a:    80 93 0a 02     sts    0x020A, r24
        *pb++    =    frontFan.RPMval[RPM_MED];
    162e:    80 91 5b 02     lds    r24, 0x025B
    1632:    80 93 0b 02     sts    0x020B, r24
        *pb++    =    frontFan.RPMval[RPM_MAX];
    1636:    80 91 5c 02     lds    r24, 0x025C
    163a:    80 93 0c 02     sts    0x020C, r24
        *pb++    =    frontFan.minTEMPval;
    163e:    80 91 5d 02     lds    r24, 0x025D
    1642:    80 93 0d 02     sts    0x020D, r24
        *pb++    =    frontFan.maxTEMPval;
    1646:    80 91 5e 02     lds    r24, 0x025E
    164a:    80 93 0e 02     sts    0x020E, r24
    164e:    10 e2           ldi    r17, 0x20; 32
    1650:    cf e0           ldi    r28, 0x0F; 15
    1652:    d2 e0           ldi    r29, 0x02; 2
    1654:    08 c0           rjmp    .+16    ; 0x1666 <_Z16usartSendCommandhPKvh+0x24e>
        break;

жаль, не догадался компилер использовать указатель 05.gif
А зря. Итог - внушительный, в два раза больший, размер функции.

Также в коде есть одна немаленькая static inline функция, которая используется всего один раз (и то, понятно, инлайнится в тело вызывающей функции), но непонятно, почему остаётся её вторая копия?

За короткое время знакомства с GCC понравилось: удобная реализация атомарности через макросы ATOMIC_BLOCK(), удобная обёртка для обработчиков прерываний вида ISR(vector_name){}.

Что не понравилось: гиморрой с обработкой данных, расположенных во флеш - для их чтения необходимо использовать специальный макрос pgm_read_...(). В ИАРе достаточно объявить указатель типа __flash и можно работать с ним совершенно обычным образом smile.gif
Также не очень удобно каждый раз пользоваться PSTR() для обозначения in-line строк вида: printText(PSTR("some")).
ИАР тут опять на высоте со своим __flash, так как подобная функция в нём декларируется как printText(char const __flash __flash * pointer), и вызов делается просто: printText("that`s cool") smile.gif
ukpyr
хм, а если писать по заранее неизвестному адресу (например который вычисляется в программе), то все работает как надо.
sonycman
Цитата(ukpyr @ Nov 24 2008, 19:42) *
хм, а если писать по заранее неизвестному адресу (например который вычисляется в программе), то все работает как надо.

Хм, перенёс буфер из глобальных в локальные переменные - сработало! Спасибо!
Лишь бы мне это боком потом не вышло... biggrin.gif
IgorKossak
Цитата(sonycman @ Nov 24 2008, 19:19) *
Хм, перенёс буфер из глобальных в локальные переменные - сработало! Спасибо!
Лишь бы мне это боком потом не вышло... biggrin.gif

Боком выйдет то, что локальные переменные располагаются в стеке, что для больших массивов неоправданно расточительно. Смотся сколько для Вас означает слово "больших".

Цитата(ukpyr @ Nov 24 2008, 18:42) *
хм, а если писать по заранее неизвестному адресу (например который вычисляется в программе), то все работает как надо.

Разве в случае известных адресов оптимизация не нужна?
sonycman
Цитата(IgorKossak @ Nov 24 2008, 20:59) *
Боком выйдет то, что локальные переменные располагаются в стеке, что для больших массивов неоправданно расточительно.

Да нет, массив всего 32 байта размером. Самое место на стёке. Лишь бы не уничтожился раньше времени wink.gif
Цитата(IgorKossak @ Nov 24 2008, 20:59) *
Разве в случае известных адресов оптимизация не нужна?

Действительно. При наличии статических данных тупо юзается абсолютная адресация. Никакой толковой оптимизации.

Эх, чем дольше я сравниваю IAR и GCC и чем больше лазию по генерируемому ими коду, тем больше убеждаюсь - не стоит ждать от них хорошего, наиболее приближенного к "ручному" ассемблеру коду.
Косячат оба.

У GCC, также, как и у IAR, часто в циклах попадаются "обёрточные" конструкции:
Код
    movw    r26, r16
    st    X+, r30
    movw    r16, r26

А также гну очень любит юзать в циклах копирования данных в качестве счётчиков итераций 16-ти битные слова (это даже если переменная изначально имеет 8 бит ширины 05.gif ).
Точнее, "счётчика" как такового не создаётся, вычисление окончания идёт путём сравнения адреса одного из указателей.
Это, конечно, универсальное решение, но в случае небольших циклов (до 256 итераций) неоправданно расходуется память и производительность...

Раз уже сел за Си, то лучше всего взять камень "потолще", побыстрее, и не париться wink.gif
IgorKossak
Цитата(sonycman @ Nov 24 2008, 21:57) *
Раз уже сел за Си, то лучше всего взять камень "потолще", побыстрее, и не париться wink.gif

Это точно. После перехода с AVR на ARM по привычке использовал счётчики циклов в 8 и 16 бит длиной пока не глянул на сгенерированный код. Регистров такой подход не экономит, зато различных масок и преобразований лишних - куча, заметно раздувающая код и гробящая производительность.
_Pasha
Цитата(sonycman @ Nov 24 2008, 23:57) *
Раз уже сел за Си, то лучше всего взять камень "потолще", побыстрее, и не париться wink.gif

Вот так они, эти сишники и зомбируют.
А что мешает узкие места прописывать асмом?
Причем, не просто асмом, а асм+ срр...
sonycman
Цитата(_Pasha @ Nov 25 2008, 01:56) *
Вот так они, эти сишники и зомбируют.
А что мешает узкие места прописывать асмом?
Причем, не просто асмом, а асм+ срр...

Ну если только совсем уж узкие biggrin.gif
Посмотрев как-то на инлайн-ассемблер я просто ужаснулся нагромождению скобок и кавычек:
Код
__asm__ __volatile__ (
        "/* START EEPROM WRITE CRITICAL SECTION */\n\t"
        "in    r0, %[__sreg]        \n\t"
        "cli                \n\t"
        "sbi    %[__eecr], %[__eemwe]    \n\t"
        "sbi    %[__eecr], %[__eewe]    \n\t"
        "out    %[__sreg], r0        \n\t"
        "/* END EEPROM WRITE CRITICAL SECTION */"
        :
        : [__eecr]  "i" (_SFR_IO_ADDR(EECR)),
          [__sreg]  "i" (_SFR_IO_ADDR(SREG)),
          [__eemwe] "i" (EEMWE),
          [__eewe]  "i" (EEWE)
        : "r0"
    );

Это не дело, так мучаться.
А как делать правильно?
singlskv
Цитата(sonycman @ Nov 24 2008, 18:23) *
жаль, не догадался компилер использовать указатель 05.gif
А зря. Итог - внушительный, в два раза больший, размер функции.
А вы попробуйте чуть помочь компилятору примерно в таком ключе:
Код
unsigned char buffer[10];

typedef struct
{
  unsigned char b0;
  unsigned char b1;
} SimpleStruct;

typedef struct
{
  unsigned char b0;
  unsigned char b1;
  unsigned char b2;
  unsigned char b3;
  unsigned char b4;
  SimpleStruct  ss;
  unsigned char b5;
  unsigned char b6;
  unsigned char b7;
  unsigned char b8;
} MyStruct;

MyStruct mystruct;

void copy(unsigned char *pd, MyStruct *ps)
{
  MyStruct *p = ps;
  *pd++ = p->b7;
  *pd++ = p->b1;
  *pd++ = p->b5;
  *pd++ = p->ss.b0;
  *pd++ = p->b2;
  *pd++ = p->b0;
  *pd++ = p->ss.b1;
  *pd++ = p->b1;
  *pd++ = p->b3;
  *pd++ = p->b4;
}

int main()
{
  copy(buffer, &mystruct);

  while (1);
}

И получите код ну никак не хуже IAR:
Код
void copy(unsigned char *pd, MyStruct *ps)
{
  5c:    cf 93           push    r28
  5e:    df 93           push    r29
  60:    fc 01           movw    r30, r24
  62:    db 01           movw    r26, r22
  MyStruct *p = ps;
  *pd++ = p->b7;
  64:    eb 01           movw    r28, r22
  66:    89 85           ldd    r24, Y+9; 0x09
  68:    81 93           st    Z+, r24
  *pd++ = p->b1;
  6a:    89 81           ldd    r24, Y+1; 0x01
  6c:    81 93           st    Z+, r24
  *pd++ = p->b5;
  6e:    8f 81           ldd    r24, Y+7; 0x07
  70:    81 93           st    Z+, r24
  *pd++ = p->ss.b0;
  72:    8d 81           ldd    r24, Y+5; 0x05
  74:    81 93           st    Z+, r24
  *pd++ = p->b2;
  76:    8a 81           ldd    r24, Y+2; 0x02
  78:    81 93           st    Z+, r24
  *pd++ = p->b0;
  7a:    8c 91           ld    r24, X
  7c:    81 93           st    Z+, r24
  *pd++ = p->ss.b1;
  7e:    8e 81           ldd    r24, Y+6; 0x06
  80:    81 93           st    Z+, r24
  *pd++ = p->b1;
  82:    89 81           ldd    r24, Y+1; 0x01
  84:    81 93           st    Z+, r24
  *pd++ = p->b3;
  86:    8b 81           ldd    r24, Y+3; 0x03
  88:    81 93           st    Z+, r24
  *pd++ = p->b4;
  8a:    8c 81           ldd    r24, Y+4; 0x04
  8c:    80 83           st    Z, r24
  8e:    df 91           pop    r29
  90:    cf 91           pop    r28
  92:    08 95           ret


Увы, у каждого компилятора свои фенечки... smile.gif
sonycman
Цитата(singlskv @ Nov 25 2008, 03:49) *
Увы, у каждого компилятора свои фенечки... smile.gif

Да, можно попробовать копировать структуры/массивы циклом, а не передавать их по одному...

Скажите, а можно-ли копировать структуры таким образом:
Код
struct somestruct
{
    byte a;
    byte b;
    byte c;
    byte d;
    byte e;
    byte f;
} some;

byte size = sizeof(some);
byte * ps = (byte*)&some;
byte * pd = ...
while (size--) *pd++ = *ps++;

Или правильнее будет юзать массивы?
Непомнящий Евгений
Цитата(sonycman @ Nov 25 2008, 12:51) *
Скажите, а можно-ли копировать структуры таким образом:
...

Дык а чем стандартный memcpy не устраивает?
sonycman
Цитата(Непомнящий Евгений @ Nov 25 2008, 14:12) *
Дык а чем стандартный memcpy не устраивает?

Можно и memcpy. Вопрос не в том - правильно ли копировать структуры таким образом? С точки зрения языка С?
demiurg_spb
Цитата(sonycman @ Nov 25 2008, 13:38) *
Можно и memcpy. Вопрос не в том - правильно ли копировать структуры таким образом? С точки зрения языка С?

Следует уяснить себе раз и навсегда, что структура или какой-либо иной объект не является таким уж абстрактным, а занимает конкретный блок той или иной памяти размером sizeof(object) выделенный под её хранение (представление). И если Вы осуществите перенос/копирование этого блока памяти любым алгоритмом - Вы скопируете/перенесёте и это нечто... А как копировать блок памяти на С не мне Вам объяснятьsmile.gif
while (size--) *dst++ = *src++; - тоже правильно
singlskv
Цитата(sonycman @ Nov 25 2008, 12:51) *
Да, можно попробовать копировать структуры/массивы циклом, а не передавать их по одному...

Скажите, а можно-ли копировать структуры таким образом:
Или правильнее будет юзать массивы?
Можно по любому, я в своем примере просто показал что если сделать
внешнюю функцию копирования и передавать указатель на буфер и на структуру,
то gcc даже при перемешивании полей структуры в буфере будет делать
компактный код:
Код
*pd++ = p->b1;
  6a:    89 81           ldd    r24, Y+1; 0x01
  6c:    81 93           st    Z+, r24
  *pd++ = p->b5;
  6e:    8f 81           ldd    r24, Y+7; 0x07
  70:    81 93           st    Z+, r24

то есть вобще без LDS и STS и с использованием 2x указателей.
Сергей Борщ
Цитата(demiurg_spb @ Nov 25 2008, 12:51) *
while (size--) *dst++ = *src++; - тоже правильно
А если быть точно уверенным, что размер структуры никогда не будет равным нулю, то можно и do *dst++ = *src++; while (--size); - код должен быть еще компактнее.
Rst7
Цитата(Сергей Борщ @ Nov 25 2008, 17:40) *
А если быть точно уверенным, что размер структуры никогда не будет равным нулю, то можно и do *dst++ = *src++; while (--size); - код должен быть еще компактнее.

Все хорошо, только если size типа char, то в этом гнусе все ломается (подробности в теме про сборки klen'а, этот гнусь тоже поломатый sad.gif ). К циклу с итератором размером 2 байта тоже есть вопросы.
sonycman
Цитата(demiurg_spb @ Nov 25 2008, 14:51) *
Следует уяснить себе раз и навсегда, что структура или какой-либо иной объект не является таким уж абстрактным, а занимает конкретный блок той или иной памяти размером sizeof(object) выделенный под её хранение (представление).

Это всё понятно. Но дело в том, что эти данные будут копироваться на PC в подобные им структуры.
Есть-ли гарантия того, что размер этих структур будет одинаков?
Особенно, если в структуре будут различные размеру данные?
И особенно, если учесть, что программы написаны в разных компиляторах...
demiurg_spb
Цитата(sonycman @ Nov 25 2008, 20:27) *
Это всё понятно. Но дело в том, что эти данные будут копироваться на PC в подобные им структуры.
Есть-ли гарантия того, что размер этих структур будет одинаков?
Особенно, если в структуре будут различные размеру данные?
И особенно, если учесть, что программы написаны в разных компиляторах...
Совершенно неважно какой компилятор Вы используете.
В каждом из них имеются свои средства задающие размер блока на который происходит выравнивание полей структуры.
К примеру для borland'a можно использовать прагмы или задавать через параметры проекта.
Код
#pragma pack(push,1)  // Выравнивание полей структур = 1 байт.

typedef struct
{
    float Amplifier[3];
    float Bias[3];
} TInputConfig;

#pragma pack(pop) // возврат к выравниванию "по умолчанию"

Цитата(Сергей Борщ @ Nov 25 2008, 18:40) *
А если быть точно уверенным, что размер структуры никогда не будет равным нулю, то можно и do *dst++ = *src++; while (--size); - код должен быть еще компактнее.
Но быть точно уверенным не всегда получается, а так я с Вами полностью согласен.
Непомнящий Евгений
Цитата(Сергей Борщ @ Nov 25 2008, 18:40) *
А если быть точно уверенным, что размер структуры никогда не будет равным нулю ...


Насколько я понимаю, размер структуры никогда не будет равен 0.
Размер пустой структуры struct A {}; - 1 байт. Сделано для того, чтобы не порушить операции с указателями на массиве таких структур.

Оптимизация пустых структур идет в некоторых случаях в С++ при наследовании.
например,
struct A {};
struct B : A {};
обычно за счет такой оптимизации sizeof( B )==sizeof( A ).
Serjio
Зарелизили http://sourceforge.net/projects/winavr/
defunct
Цитата(sonycman @ Nov 25 2008, 19:27) *
Есть-ли гарантия того, что размер этих структур будет одинаков?

Размер одной и той же структуры может изменяться взависимости от правил выравнивания (Alignment). Для 8-ми битных процов каковым есть AVR - выравнивание обычно - 1 (на границу байта).
А вот на PC выравнивание может быть 4 (на границу DWORD, Win32), 2 (WORD под DOS), 8 (QWORD под Win64).
В многих компиляторах (не только C и C++) выравнивание полей на границу байта задается ключевым словом packed/__packed. например:

__packed struct tagSOME_STRUCT
{
....
} ...;

Но может задаваться и по-другому, см. описание конкретного компилятора на тему как задать выравнивание струтуры (ключевые слова для поиска "Alignment/Align/Pack/Packed").
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.