реклама на сайте
подробности

 
 
10 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Перенос кода из под ИАРа на WinAVR, возникают некоторые вопросы...
sonycman
сообщение Nov 22 2008, 19:39
Сообщение #1


Любитель
*****

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



Сейчас пытаюсь подогнать ИАРовский проект на меге88 под ВинАВР 4.3.2.
Чувствую, помучаться придётся немало smile3046.gif

Пока не могу разобраться, как красиво прочитать/записать 16-ти битный таймер, обеспечив атомарность операции.
Аналога иаровского __monitor не нашёл.
Существуют ли подобные макросы? Или надо писать самому?
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 22 2008, 20:04
Сообщение #2


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Поможет WinAVR\avr\include\util\atomic.h


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 22 2008, 21:17
Сообщение #3


Любитель
*****

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



Цитата(demiurg_spb @ Nov 23 2008, 00:04) *
Поможет WinAVR\avr\include\util\atomic.h

Уря, разобрался! a14.gif
С меня beer.gif

Я то пытался накропать код и заюзать что-то типа cli() и sei() своими корявенькими ручонками, а тут уже готовое решение, такое компактное и мощное одновременно!
Разрабы туда, наверное, тонну хитрости запихали! Учитывать все выходы из секции для восстановления прерываний... бла, как они это осуществили?

Всё, пошёл спать. С утра буду невыспавшийся - зато довольный laughing.gif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Nov 23 2008, 08:24
Сообщение #4


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Насколько я помню, у WinAVR имеется отличная документация, включающая в том числе раздел "Porting Code From IAR"


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 23 2008, 14:33
Сообщение #5


Любитель
*****

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



Цитата(MrYuran @ Nov 23 2008, 12:24) *
Насколько я помню, у WinAVR имеется отличная документация, включающая в том числе раздел "Porting Code From IAR"

Спасибо, теперь всё понятно и с прерываниями biggrin.gif
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 23 2008, 17:09
Сообщение #6


Любитель
*****

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



Цитата(MrYuran @ Nov 23 2008, 12:24) *
Насколько я помню, у WinAVR имеется отличная документация, включающая в том числе раздел "Porting Code From IAR"

А может кто подскажет, где поискать документацию по AVR GCC в виде PDF?
А то не очень удобно пользоваться html версией... 07.gif
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 23 2008, 17:23
Сообщение #7


Профессионал
*****

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



Цитата(sonycman @ Nov 23 2008, 20:09) *
А может кто подскажет, где поискать документацию по AVR GCC в виде PDF?
А то не очень удобно пользоваться html версией... 07.gif

как правило, она находится в папке WinAVR\doc\avr-libc - я ведь верно понял, что интересует документация на avr-libc?


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 23 2008, 18:03
Сообщение #8


Нечётный пользователь.
******

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



Цитата(sonycman @ Nov 22 2008, 23:17) *
Разрабы туда, наверное, тонну хитрости запихали! Учитывать все выходы из секции для восстановления прерываний... бла, как они это осуществили?
У gcc есть довольно мощная штука - атрибуты. Куча разных.
Например, атрибутом можно сказать, что результат, возвращаемый данной функцией, зависит только от передаваемых ей параметров и она сама вовне ничего не меняет, т.е. не имеет "побочных эффектов".
Вся математика типа sqrt() такая.
Тогда если её вызывать с одними и теми же неизменными аргументами (константами либо переменными, про которые компилятор знает, что они не менялись) несколько раз - компилятор вызовет одитн раз, запомнит значение и подставит где нужно сам.

Для переменных можно задать аттрибутами функции создания и очистки, при создании переменной будет вызвана одна функция, при уничтожении (при выходе из окружающего её блока { } ) - другая. Это что-то типа конструкторов-деструкторов в C++. Вот они и спрятали в макросах переменную, при создании которой в неё копируется SREG и прерывания запрещаются/разрешаются, в зависимости от типа блока, а при удалении она переписывается назад в SREG, таким образом состояние прерываний восстанавливается.
Чтобы созданная как бы до блока переменная была привязана к блоку, т.е. чтобы можно было писать
Код
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
   ...
}

А не
Код
{
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
   ...
}
макросы оформили в виде заголовка цикла for(;;) - переменная, которая объявлена в заголовке (for( unsigned char u; ...; ... ) ) имеет время жизни в пределах цикла, создаётся до первого входа в тело и уничтожается после выхода из цикла.

Очень симпатично сделано... Учтено всё.

Вот тут ещё на эту тему было, только "наоборот" - нужно на время разрешить прерывания:
http://electronix.ru/forum/index.php?showt...mp;#entry487831
в примере макрос из atomic.h и С++ класс дали при компиляции тождественный код.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 23 2008, 19:09
Сообщение #9


Любитель
*****

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



Цитата(ARV @ Nov 23 2008, 21:23) *
как правило, она находится в папке WinAVR\doc\avr-libc - я ведь верно понял, что интересует документация на avr-libc?

Нет, на библиотеку как раз pdf есть. Мне бы на компилятор, со всеми его ключевыми словами, аттрибутами и т.д...
Она там только в формате html... в принципе, сойдёт, если нет лучшего smile.gif

Цитата(ReAl @ Nov 23 2008, 22:03) *
Очень симпатично сделано... Учтено всё.

Спасибо за разъяснение, стало понятнее!
Сам только недавно начал осваивать С++, и имею небольшое представление о классах.
Очень интересная штука wink.gif

У меня возникла очередная проблема в портировании проекта IAR на WinAVR.
Есть класс таймеров:
Код
#include    <util/atomic.h>

typedef    unsigned long    dword;
typedef    unsigned short    word;
typedef    unsigned char    byte;

extern volatile    word    tcounter;       //hardware timer

class    CTimer    {
private:
    word    interval;
    word    counter;

public:
    CTimer (word timeout    =    0) {    Set(timeout);    }
    void    operator =    (word    timeout);
    void    Set (word timeout);
    bool    operator ! ();
    operator    bool ();
};

        CTimer::operator    bool()
{
    if (!interval) return TRUE;
    if ((tcounter - counter) >= interval)
    {
        interval    =    0;
        return    TRUE;
    }
    return    FALSE;
}

bool    CTimer::operator !    ()
{
    return    !operator bool();
}

void    CTimer::operator =    (word    timeout)
{
    Set(timeout);
}

void    CTimer::Set(word timeout)
{
    if (timeout)
    {
        interval    =    timeout    /    10;            //interrupts timer resolution is 10ms
        counter    =    tcounter;
    }
    else
    {
        interval    =    0;
    }
}

Этот файл компилируется нормально.
Но при компиляции таких строк:
Код
static CTimer tmrSpinup;

то есть при создании объекта класса выдаётся ошибка: undefined reference to `__cxa_guard_release'

Что-то я пока что в тупике.
Описания такой функции нет в исходниках компилятора.
Что делать? Почему так получилось? wacko.gif
Go to the top of the page
 
+Quote Post
Petka
сообщение Nov 23 2008, 20:38
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886



Цитата(ReAl @ Nov 23 2008, 21:03) *
У gcc есть довольно мощная штука - атрибуты. Куча разных.
....
Для переменных можно задать аттрибутами функции создания и очистки, при создании переменной будет вызвана одна функция, при уничтожении (при выходе из окружающего её блока { } ) - другая. Это что-то типа конструкторов-деструкторов в C++. Вот они и спрятали в макросах переменную, при создании которой в неё копируется SREG и прерывания запрещаются/разрешаются, в зависимости от типа блока, а при удалении она переписывается назад в SREG, таким образом состояние прерываний восстанавливается.
Чтобы созданная как бы до блока переменная была привязана к блоку, т.е. чтобы можно было писать
Код
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
   ...
}

А не
Код
{
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE);
   ...
}
макросы оформили в виде заголовка цикла for(;;) - переменная, которая объявлена в заголовке (for( unsigned char u; ...; ... ) ) имеет время жизни в пределах цикла, создаётся до первого входа в тело и уничтожается после выхода из цикла.

Очень симпатично сделано... Учтено всё.
....

В принципе понятно как они сделали. но во зачем - непонятно. зачем такой хитрый выверт с непереносимыми атрибутами, когда аналогичную штуку можно проделать без них? например:
Код
#define ATOMIC_BLOCK()   for(U8 __temp=get_SREG_and_CLI(),iter=0;iter<1;i++,SREG=__temp)

И переносимо, и без хитрых атрибутов? Может я чего-то не понял. Или есть какой-то потаёный от меня смысл?
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 23 2008, 21:37
Сообщение #11


Нечётный пользователь.
******

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



Цитата(sonycman @ Nov 23 2008, 21:09) *
то есть при создании объекта класса выдаётся ошибка: undefined reference to `__cxa_guard_release'

Что-то я пока что в тупике.
Описания такой функции нет в исходниках компилятора.
Что делать? Почему так получилось? wacko.gif
Странно. К тому коду было добавлено
Код
static CTimer tmrSpinup;

int main()
{
    tmrSpinup.Set(10);
    while( !tmrSpinup );
    for(;;);
}
и всё собралось-слинковалось несколькими версиями от 3.4.6 (WinAVR-20060421) до 4.4.0 (Klen-20080530), более свежих нет на компе.
Это функция, похоже, должна была бы быть в libstdc++, если бы она для AVR была. Там же __cxa_pure_virtual и т.д., т.е. поддержка для более "взрослого" применения С++ с исключениями и т.д.
Почему вдруг в данном случае компилятор решил, что нужна помощь зала библиотеки поддержки - неясно. Иногда такое бывает и иногда при этом помогает добавление ключей
Код
    CFLAGS += -ffunction-sections #-fdata-sections
    LDFLAGS += -Wl,--gc-sections
Это предназначено для итеративного выбрасывания кода и данных, которые никогда не вызывается/не используются.
За компанию стоит добавить
Код
    LDFLAGS += -Wl,--relax

поиском по разделу AVR можно найти объяснения.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 23 2008, 21:37
Сообщение #12


Любитель
*****

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



Цитата(Petka @ Nov 24 2008, 00:38) *
В принципе понятно как они сделали. но во зачем - непонятно. зачем такой хитрый выверт с непереносимыми атрибутами, когда аналогичную штуку можно проделать без них? например:
Код
#define ATOMIC_BLOCK()   for(U8 __temp=get_SREG_and_CLI(),iter=0;iter<1;i++,SREG=__temp)

И переносимо, и без хитрых атрибутов? Может я чего-то не понял. Или есть какой-то потаёный от меня смысл?

А если внутри блока будет break или return? Выполнится ли тогда SREG=__temp?

Цитата(ReAl @ Nov 24 2008, 01:37) *
Странно. К тому коду было добавлено
Код
static CTimer tmrSpinup;

int main()
{
    tmrSpinup.Set(10);
    while( !tmrSpinup );
    for(;;);
}
и всё собралось-слинковалось несколькими версиями от 3.4.6 (WinAVR-20060421) до 4.4.0 (Klen-20080530), более свежих нет на компе.

Есть информация, что некоторые статические объекты вызывают такую ошибку в новых версиях компилятора, так как отсутствует какая-то библиотека...
Решилось добавлением ключа -fno-threadsafe-statics
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 23 2008, 21:43
Сообщение #13


Нечётный пользователь.
******

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



Цитата(Petka @ Nov 23 2008, 22:38) *
В принципе понятно как они сделали. но во зачем - непонятно. зачем такой хитрый выверт с непереносимыми атрибутами, когда аналогичную штуку можно проделать без них? например:
Код
#define ATOMIC_BLOCK()   for(U8 __temp=get_SREG_and_CLI(),iter=0;iter<1;i++,SREG=__temp)
И переносимо, и без хитрых атрибутов? Может я чего-то не понял. Или есть какой-то потаёный от меня смысл?
Это НЕ аналогичная штука. По ссылке, там где я пример с классом приводил, достаточно полный пример зачем это надо (конструкторы-деструкторы, пусть даже в виде прицепленных атрибутами функций).
Может быть выход из середины блока, простой "переносимый" вариант при этом не отработает освобождение (у вcякой задачи есть два решения - простое и правильное ;-) )
Код
#include <avr/interrupt.h>
#include <util/atomic.h>

uint8_t get_SREG_and_CLI() { uint8_t s = SREG; cli(); return s; }

#define ATOM()   for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp)


volatile uint8_t v;

void foo(uint8_t z)
{
    ATOM() {
        ++v;
        if(z) return;
        ++v;
    }    
}


void moo(uint8_t z)
{
    ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
        ++v;
        if(z) return;
        ++v;
    }    
}
Код
.global    foo
    .type    foo, @function
foo:
    in r18,95-0x20
/* #APP */
    cli
/* #NOAPP */
    lds r25,v
    subi r25,lo8(-(1))
    sts v,r25
    tst r24
    brne .L10
    lds r24,v
    subi r24,lo8(-(1))
    sts v,r24
    out 95-0x20,r18
.L10:                           ; <--- а кто прерывания взад вернёт???
    ret

.global    moo
    .type    moo, @function
moo:
    in r18,95-0x20
/* #APP */
    cli
/* #NOAPP */
    lds r25,v
    subi r25,lo8(-(1))
    sts v,r25
    tst r24
    brne .L4
    lds r24,v
    subi r24,lo8(-(1))
    sts v,r24
.L4:                            ; <--- вот это другое дело!
    out 95-0x20,r18
    ret


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 23 2008, 21:45
Сообщение #14


Гуру
******

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



Цитата(sonycman @ Nov 23 2008, 21:09) *
то есть при создании объекта класса выдаётся ошибка: undefined reference to `__cxa_guard_release'
Полный ответ здесь. Но я на это не нарывался, видимо потому, что использую --ffunction-section и --gc-sections. Я и узнал-то об этих функциях только из статьи по ссылке.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 23 2008, 21:51
Сообщение #15


Нечётный пользователь.
******

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



Цитата(sonycman @ Nov 23 2008, 23:37) *
А если объявить tmrSpinup как static?
Есть информация, что некоторые статические объекты вызывают такую ошибку в новых версиях компилятора, так как отсутствует какая-то библиотека...
Решилось добавлением ключа -fno-threadsafe-statics
Так у меня она static и объявлена, вероятно, у меня достаточно старые версии :-)
За ключик спасибо, добавлю как упреждающий манёвр.



Цитата(Сергей Борщ @ Nov 23 2008, 23:45) *
Полный ответ здесь.

У меня из дому какие-то проблемы именно с этим сайтом :-(
По прямому линку заходит, но страшно медленно, а вот на вторую страницу какой-то темы зайти уже нереально.
Поэтому я его практически не смотрю, на работе как правило не до интернета.
При этом всё остальное дома "летает", как и положено adsl2+, многое быстрее, чем на работе.
Так что гляну уже после "типоотпуска".


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 23 2008, 21:54
Сообщение #16


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 23 2008, 22:09) *
А может кто подскажет, где поискать документацию по AVR GCC в виде PDF?
А то не очень удобно пользоваться html версией... 07.gif
А на родной страничке http://gcc.gnu.org/onlinedocs/ ссылки "also in PDF" - это разве не оно?


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Petka
сообщение Nov 24 2008, 07:35
Сообщение #17


Профессионал
*****

Группа: Свой
Сообщений: 1 453
Регистрация: 23-08-05
Пользователь №: 7 886



Цитата(ReAl @ Nov 24 2008, 00:43) *
Это НЕ аналогичная штука. По ссылке, там где я пример с классом приводил, достаточно полный пример зачем это надо (конструкторы-деструкторы, пусть даже в виде прицепленных атрибутами функций).
Может быть выход из середины блока, простой "переносимый" вариант при этом не отработает освобождение (у вcякой задачи есть два решения - простое и правильное ;-) )
Код
#include <avr/interrupt.h>
#include <util/atomic.h>

uint8_t get_SREG_and_CLI() { uint8_t s = SREG; cli(); return s; }

#define ATOM()   for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp)
volatile uint8_t v;

Мысль понял.
а если так:
Код
define ATOM()   for(uint8_t __temp=get_SREG_and_CLI(),iter=0; iter<1; iter++,SREG=__temp) for(int iter2=0; iter2 < 1; iter2++)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 11:05
Сообщение #18


Любитель
*****

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



Портировал я свою программу с IARа на GCC.
Оптимизация максимальная по скорости у первого, и Os с ключами -mcall-prologues -fno-threadsafe-statics -ffunction-sections --gc-sections --relax у второго.
В результате код IARа - 6 090 bytes of CODE memory + 493 bytes of DATA memory.
Код GCC - Program: 7462 bytes + Data: 363 bytes.

Код иара компактнее почти на 1,5 килобайта. Правда, некоторые функции "тюнингованы" специальными ключами (типа __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
А зря. Итог - внушительный, в два раза больший, размер функции.

Также в коде есть одна немаленькая 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
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 24 2008, 11:35
Сообщение #19


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 24 2008, 14:05) *
Также в коде есть одна немаленькая inline функция, которая используется всего один раз (и то, понятно, инлайнится в тело вызывающей функции), но непонятно, почему остаётся её вторая копия?


Добавте при обьявлении этой функции static.

Анатолий.
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 24 2008, 11:56
Сообщение #20


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(sonycman @ Nov 24 2008, 14:05) *
и вызов делается просто: printText("that`s cool") smile.gif
Я уже описал как добиться того же результата и в GCC (правда через макрос)...
Повторяю:
Код
void lcd_print_str  (unsigned char x, unsigned char y, char* p);          // print RAM str
void lcd_print_cstr (unsigned char x, unsigned char y, const char* p);    // print FLASH str

#define  lcd_print_PSTR(X,Y,LCDPSTR)   lcd_print_cstr(X,Y,PSTR(LCDPSTR))  // put str in to FLASH and then print


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 11:57
Сообщение #21


Любитель
*****

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



Цитата(aesok @ Nov 24 2008, 15:35) *
Добавте при обьявлении этой функции static.

Анатолий.

У меня она так и объявлена:
Код
static inline void    ReadButtons(void) __attribute__ ((always_inline));

static inline void    ReadButtons(void)
{}


Результата нет - всё равно две копии sad.gif
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 14:15
Сообщение #22


Любитель
*****

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



Интересно, почему при делении на два не всегда используются оптимизации?
Например:
Код
else if    (percent == MED_AVAIL) percent = (RPMval[RPM_MAX] - RPMval[RPM_MIN]) / 2;
     68c:    61 38           cpi    r22, 0x81; 129
     68e:    49 f4           brne    .+18     ; 0x6a2 <_ZN13CFanRegulator8SetSpeedEhh+0x44>
     690:    87 81           ldd    r24, Z+7; 0x07
     692:    90 e0           ldi    r25, 0x00; 0
     694:    25 81           ldd    r18, Z+5; 0x05
     696:    82 1b           sub    r24, r18
     698:    91 09           sbc    r25, r1
     69a:    62 e0           ldi    r22, 0x02; 2
     69c:    70 e0           ldi    r23, 0x00; 0
     69e:    52 da           rcall    .-2908   ; 0xfffffb44 <__eeprom_end+0xff7efb1c>

Видно, что для деления вызывается подпрограмма библиотеки.
Почему не используется простой сдвиг? 07.gif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Nov 24 2008, 14:22
Сообщение #23


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(sonycman @ Nov 24 2008, 17:15) *
Интересно, почему при делении на два не всегда используются оптимизации?
Видно, что для деления вызывается подпрограмма библиотеки.
Почему не используется простой сдвиг? 07.gif

Я обычно ручками пишу <<1 (2,3,etc) или >>1, не надеясь на компилятор.
А вообще от флагов оптимизации зависит.


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 14:46
Сообщение #24


Любитель
*****

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



Цитата(MrYuran @ Nov 24 2008, 18:22) *
Я обычно ручками пишу <<1 (2,3,etc) или >>1, не надеясь на компилятор.
А вообще от флагов оптимизации зависит.

Точно, надо попробовать.
С другой стороны, приятнее читать программу с обычными символами /, чем сдвигами.

А где можно почитать про флаги для оптимизации?
Я уже кучу флагов надобавлял (в сети понаходил).
Вот они:
-ffunction-sections -fno-inline-small-functions -fno-tree-scev-cprop
-mcall-prologues

и ключ -fno-inline-small-functions помог уменьшить размер кода на 400 байт (итого получилось 7110 байт).

Ещё непонятно, почему компилер выдаёт предупреждения типа:
only initialized variables can be placed into program memory area
на все строки, подобные:
Код
static prog_char  fntable[]    PROGMEM    = "!%`()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^";
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 24 2008, 15:58
Сообщение #25


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(sonycman @ Nov 24 2008, 17:46) *
Ещё непонятно, почему компилер выдаёт предупреждения типа:
only initialized variables can be placed into program memory area
на все строки, подобные:
Код
static prog_char  fntable[]    PROGMEM    = "!%`()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^";

prog_char ведь это уже:
Код
typedef char PROGMEM prog_char;
для prog_char уже PROGMEM не требуется.
Тут c С++ и prog_char какие-то нюансы всплывали...
Попробуйте так:
Код
const char PROGMEM Vasja[] = "Vasja";


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 16:05
Сообщение #26


Любитель
*****

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



Цитата(demiurg_spb @ Nov 24 2008, 19:58) *
prog_char ведь это уже:
Код
typedef char PROGMEM prog_char;
второй раз после prog_char PROGMEM уже не требуется.
Тут c С++ и prog_char какие-то нюансы всплывали...
Попробуйте так:
Код
const char PROGMEM Vasja[] = "Vasja";


Спасибо, попробовал. Но всё осталось по прежнему...
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 24 2008, 16:40
Сообщение #27


Профессионал
*****

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



смутил ключик --gc-sections я всегда использую -Wl,-gc-sections возможно, это одно и то же, но на всякий случай обращу ваше внимание...

кстати, результат оптимизации сильно зависит от не сразу заметных моментов, например, локальная static переменная и глобальная static переменная для тех же целей может дать разный размер кода. та же песня и с указателями - далеко не всегда они приводят к уменьшению размера... строгих закономерностей я не обнаружил, но сказанное имеет место...


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 24 2008, 19:07
Сообщение #28


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 24 2008, 14:57) *
У меня она так и объявлена:
Код
static inline void    ReadButtons(void) __attribute__ ((always_inline));

static inline void    ReadButtons(void)
{}


Результата нет - всё равно две копии sad.gif


Почитайте про static inline функции здесь:
http://www.greenend.org.uk/rjk/2003/03/inline.html

С ними есть какието тонкости, у меня сейчас нет времени вникать.

Анатолий.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 19:26
Сообщение #29


Любитель
*****

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



Цитата(ARV @ Nov 24 2008, 20:40) *
смутил ключик --gc-sections я всегда использую -Wl,-gc-sections возможно, это одно и то же, но на всякий случай обращу ваше внимание...

Попробовал и с -gc-sections. Вроде без разницы.
Полный текст командной строки линкера:
Код
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref --gc-sections --relax -mmcu=atmega88


Цитата(aesok @ Nov 24 2008, 23:07) *
Почитайте про static inline функции здесь:
http://www.greenend.org.uk/rjk/2003/03/inline.html

С ними есть какието тонкости, у меня сейчас нет времени вникать.

Анатолий.

Спасибо, ознакомлюсь. smile.gif

ЗЫ: Хм, написано, что инлайн функция не должна иметь статических переменных или обращаться к таковым... а у меня внутри есть статическая переменная.
Может, дело в этом?
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 24 2008, 20:00
Сообщение #30


Профессионал
*****

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



Цитата(sonycman @ Nov 24 2008, 22:26) *
Попробовал и с -gc-sections. Вроде без разницы.
Полный текст командной строки линкера:
Код
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref --gc-sections --relax -mmcu=atmega88
если уж вы передаете разные параметры компоновщику, то указывайте тогда их все через запятую
Код
avr-g++ -Wl,-Map,FanController.map,--cref,-gc-sections --relax -mmcu=atmega88

и снова: почему у вас 2 минуса перед gc-sections? разве 2 или 1 - это все равно? и, при всем при том, где -ffunction-sections? они же в паре должны быть. я так понимаю:
Код
avr-g++ -ffunction-sections -Wl,-gc-sections,-Map,FanController.map,--cref --relax -mmcu=atmega88


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 20:23
Сообщение #31


Любитель
*****

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



Цитата(ARV @ Nov 25 2008, 00:00) *
Код
avr-g++ -ffunction-sections -Wl,-gc-sections,-Map,FanController.map,--cref --relax -mmcu=atmega88

Дело в том, что я компилирую через Эклипс Ганимед.
И там доп. опции куда хочешь не добавить - только в специально отведённую для этого строку.

Есть там вот что:
Код
Expert settings.
Command line pattern:
${COMMAND} ${FLAGS} ${OUTPUT_FLAG}${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Может, это и есть очерёдность ввода параметров?

Вот что у меня теперь:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -ffunction-sections -gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
Finished building target: FanController.elf
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 24 2008, 21:14
Сообщение #32


Гуру
******

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



Цитата(sonycman @ Nov 24 2008, 22:23) *
Вот что у меня теперь:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -ffunction-sections -gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
Finished building target: FanController.elf
Добавьте -Wl, перед -gc-sections. Странно, что для линковки вызывается avr-g++ а не avr-gcc или avr-ld


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 24 2008, 23:36
Сообщение #33


Любитель
*****

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



Цитата(Сергей Борщ @ Nov 25 2008, 01:14) *
Добавьте -Wl, перед -gc-sections. Странно, что для линковки вызывается avr-g++ а не avr-gcc или avr-ld

Так выдаёт ошибку:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -ffunction-sections Wl,-gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
avr-g++.exe: Wl,-gc-sections: No such file or directory
make: *** [FanController.elf] Error 1

А что вообще означают опции Wl и -gc-sections? rolleyes.gif
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 25 2008, 05:56
Сообщение #34


Профессионал
*****

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



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

для Eclipse Ganimed (которым я и сам пользуюсь) имеется плагин, специально предназначенный для работы с AVR, по-моему, он называется avreclipse. Этот плагин имеет "очеловеченный" интерфейс к avr-gcc, который позволяет большинство опций задавать "галочками", а для остальных есть поля ручного ввода. При ручном вводе опции просто добавляются, проблем не возникает. И никаких заморочек с make-файлами, все автоматически делается. Рекомендую.

P.S. по непонятным причинам, результат компиляции одного и того же проекта с одинаковыми (во всяком случае, с моей точки зрения) опциями в AVR Studio и Eclipse получается (у меня) разным! Второй - меньшего размера smile.gif подозреваю, что дело в том, в каком порядке компилируются файлы проекта (порядок реально разный получается)...

Сообщение отредактировал ARV - Nov 25 2008, 06:02


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
msalov
сообщение Nov 25 2008, 07:39
Сообщение #35


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(sonycman @ Nov 25 2008, 01:36) *
Так выдаёт ошибку:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -ffunction-sections Wl,-gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
avr-g++.exe: Wl,-gc-sections: No such file or directory
make: *** [FanController.elf] Error 1

А что вообще означают опции Wl и -gc-sections? rolleyes.gif

Для того, что бы удалялись неиспользуемые функции -ffunction-sections надо передавать компилятору, а --gc-sections -- линкеру/компоновщику.
А ошибка в том, что вы забыли "-" перед Wl,-gc-sections
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 25 2008, 09:41
Сообщение #36


Любитель
*****

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



Цитата(gotty @ Nov 25 2008, 11:39) *
Для того, что бы удалялись неиспользуемые функции -ffunction-sections надо передавать компилятору, а --gc-sections -- линкеру/компоновщику.
А ошибка в том, что вы забыли "-" перед Wl,-gc-sections


Спасибо. Просто мне посоветовали -ffunction-sections тоже передать линкеру smile.gif

В общем - сделал вот так:
Компилятор:
Код
Invoking: AVR C++ Compiler
avr-g++ -I"F:\Electronics\Projects\GNU\FanController\Headers" -Wall -g2 -gdwarf-2 -Os -fpack-struct -fshort-enums -mcall-prologues -std=gnu++98 -funsigned-char -funsigned-bitfields -fno-exceptions -fno-threadsafe-statics -fno-inline-small-functions -ffunction-sections -mmcu=atmega88 -DF_CPU=10000000UL -MMD -MP -MF"Sources/pwm.d" -MT"Sources/pwm.d" -c -o"Sources/pwm.o" "../Sources/pwm.cpp"
Finished building: ../Sources/pwm.cpp

Линкер:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -Wl,-gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
Finished building target: FanController.elf

Код проекта сразу уменьшился на 600 байт!
Надо проверить, что он там повыкидывал... yeah.gif

ЗЫ: а ничего, что --relax передаётся без запятой?

Цитата(ARV @ Nov 25 2008, 09:56) *
-ff-sections заставляет компилятор размещать код каждой функции в отдельной секции памяти.
-gc-sections заставляет компоновщик удалять все секции кода, на которые нет ссылок из других секций.
в итоге все функции, которые в тексте определены, но ни разу не вызваны, удаляются из результирующего кода, чем уменьшается его размер.
-Wl, - это опция, которая указывает, что компоновщику надо передать список следующих опций (список разделяется запятыми). При этом в списке недопустимы пробелы, которые обозначают конец списка. Именно по этому лучше тупо писать -Wl,-gc-sections , чем добавлять опции к командной строке иными способами.

для Eclipse Ganimed (которым я и сам пользуюсь) имеется плагин, специально предназначенный для работы с AVR, по-моему, он называется avreclipse. Этот плагин имеет "очеловеченный" интерфейс к avr-gcc, который позволяет большинство опций задавать "галочками", а для остальных есть поля ручного ввода. При ручном вводе опции просто добавляются, проблем не возникает. И никаких заморочек с make-файлами, все автоматически делается. Рекомендую.


Спасибо за разъяснение.
У меня установлен именно avreclipse плагин, версии 2.3.0.
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 25 2008, 09:52
Сообщение #37


Профессионал
*****

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



Цитата(sonycman @ Nov 25 2008, 12:41) *
Надо проверить, что он там повыкидывал... yeah.gif
практика показывает, что ничего полезного не выкидывает smile.gif


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
msalov
сообщение Nov 25 2008, 10:01
Сообщение #38


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(sonycman @ Nov 25 2008, 11:41) *
Линкер:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -Wl,-gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
Finished building target: FanController.elf

Код проекта сразу уменьшился на 600 байт!
Надо проверить, что он там повыкидывал... yeah.gif

ЗЫ: а ничего, что --relax передаётся без запятой?

Ничего страшного, по моим представлениям запись вида -Wl,--gc-sections вместо --gc-sections используется лиш в случае совмещения компиляции и скомпоновки, аналогично и --relax, и -Map и все остальные параметры компоновщика.
Что бы проверить, какие секции были выкинуты сборщиком мусора, можно добавить параметр --print-gc-sections
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 25 2008, 10:42
Сообщение #39


Любитель
*****

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



Цитата(ARV @ Nov 25 2008, 13:52) *
практика показывает, что ничего полезного не выкидывает smile.gif

Проверил - всё в порядке, выкинул только не используемые функции smile.gif
Прекрасно!

Цитата(gotty @ Nov 25 2008, 14:01) *
Ничего страшного, по моим представлениям запись вида -Wl,--gc-sections вместо --gc-sections используется лиш в случае совмещения компиляции и скомпоновки, аналогично и --relax, и -Map и все остальные параметры компоновщика.
Что бы проверить, какие секции были выкинуты сборщиком мусора, можно добавить параметр --print-gc-sections

А я уже листинги сравнил тотал коммандером laughing.gif
Понятно, значит, --relax оставляю как есть.
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 25 2008, 21:58
Сообщение #40


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Привет, sonycman!
Цитата(sonycman @ Nov 24 2008, 16:05) *
Также в коде есть одна немаленькая inline функция, которая используется всего один раз (и то, понятно, инлайнится в тело вызывающей функции), но непонятно, почему остаётся её вторая копия?
Можно тестовый пример с версией и опциями компилятора?

Цитата(sonycman @ Nov 24 2008, 16:05) *
За короткое время знакомства с GCC понравилось: удобная реализация атомарности через макросы ATOMIC_BLOCK(), удобная обёртка для обработчиков прерываний вида ISR(vector_name){}.
Так это как раз не компилятор, это просто библиотечные макросы. Аналогичные макросы можно сделать для любого минимально вменяемого компилятора.

Цитата(sonycman @ Nov 24 2008, 16:05) *
Видно, что для деления вызывается подпрограмма библиотеки.
Почему не используется простой сдвиг?
Видимо, потому что простой сдвиг не умещается в три процессорные инструкции. При отличной от -Os оптимизации генерится именно сдвиг.

Цитата(sonycman @ Nov 24 2008, 16:05) *
А где можно почитать про флаги для оптимизации?
В документации, естественно: http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gc...ptimize-Options

Цитата(sonycman @ Nov 24 2008, 16:05) *
А что вообще означают опции Wl и -gc-sections?
Все описано в мануалах. Про эти две тебе уже ответили, но в мануалах есть еще не один десяток опций, о которых полезно знать...

Цитата(MrYuran @ Nov 24 2008, 19:22) *
Я обычно ручками пишу <<1 (2,3,etc) или >>1, не надеясь на компилятор.
И зря. "x / 2" и "x >> 1" - не эквивалентные операции. Они дают гарантированно одинаковый результат только для положительного x. Но в этом случае (если x имеет тип unsigned) gcc и код генерит одинаковый (со сдвигом), и нет никакого смысла писать одно вместо другого. У sonycman же, судя по приведенному им примеру, левый операнд имеет знаковый тип.

Сообщение отредактировал alx2 - Nov 25 2008, 21:47


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 26 2008, 07:22
Сообщение #41


Профессионал
*****

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



Цитата(sonycman @ Nov 25 2008, 13:42) *
Понятно, значит, --relax оставляю как есть.
на сколько я смог понять их документации, --relax для платформы AVR смысла не имеет. экспериментальная проверка на своем проекте подтвердила - 0 байт изменений с и без --relax


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 26 2008, 09:39
Сообщение #42


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(ARV @ Nov 26 2008, 10:22) *
на сколько я смог понять их документации, --relax для платформы AVR смысла не имеет. экспериментальная проверка на своем проекте подтвердила - 0 байт изменений с и без --relax


На каком контроллере Вы проверяли, размер программы?

Анатолий.
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 26 2008, 09:50
Сообщение #43


Профессионал
*****

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



Цитата(aesok @ Nov 26 2008, 12:39) *
На каком контроллере Вы проверяли, размер программы?

Анатолий.

проверял на контроллере AT90CAN128, программа в итоге получается 14606 байт. всего линкуется почти десяток объектников.


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 26 2008, 10:17
Сообщение #44


Любитель
*****

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



Цитата(alx2 @ Nov 26 2008, 01:58) *
Привет, sonycman!
Можно тестовый пример с версией и опциями компилятора?

Привет smile.gif
Сейчас у меня вот такие опции:
Компилятор:
Код
Building file: ../Sources/main.cpp
Invoking: AVR C++ Compiler
avr-g++ -I"F:\Electronics\Projects\GNU\FanController\Headers" -Wall -g2 -gdwarf-2 -Os -fpack-struct -fshort-enums -mcall-prologues -std=gnu++98 -funsigned-char -funsigned-bitfields -fno-exceptions -fno-threadsafe-statics -fno-inline-small-functions -ffunction-sections -mmcu=atmega88 -DF_CPU=10000000UL -MMD -MP -MF"Sources/main.d" -MT"Sources/main.d" -c -o"Sources/main.o" "../Sources/main.cpp"

и линкер:
Код
Building target: FanController.elf
Invoking: AVR C++ Linker
avr-g++ -Wl,-Map,FanController.map,--cref -Wl,-gc-sections --relax -mmcu=atmega88 -o"FanController.elf"  ./Sources/CFanRegulator.o ./Sources/CTimer.o ./Sources/DS18S20.o ./Sources/Interrupts.o ./Sources/LCD.o ./Sources/USART.o ./Sources/debug.o ./Sources/generic.o ./Sources/main.o ./Sources/pwm.o  
Finished building target: FanController.elf

С включением опции -Wl,-gc-sections неиспользуемая копия встраиваемой функции исчезла.
Всё заработало правильно!

Цитата
Видимо, потому что простой сдвиг не умещается в три процессорные инструкции. При отличной от -Os оптимизации генерится именно сдвиг.

И зря. "x / 2" и "x >> 1" - не эквивалентные операции. Они дают гарантированно одинаковый результат только для положительного x. Но в этом случае (если x имеет тип unsigned) gcc и код генерит одинаковый (со сдвигом), и нет никакого смысла писать одно вместо другого. У sonycman же, судя по приведенному им примеру, левый операнд имеет знаковый тип.

Да. Операнд имеет тип signed char. Именно в этом, видимо, и вся проблема. Спасибо, теперь я понял smile.gif
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 26 2008, 12:46
Сообщение #45


Йа моск ;)
******

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



Цитата(alx2 @ Nov 25 2008, 23:58) *
И зря. "x / 2" и "x >> 1" - не эквивалентные операции. Они дают гарантированно одинаковый результат только для положительного x.

Да ну? Где Вы это вычитали? Сдвиг в Си для знаковых операндов всю жизнь был арифметический, с учетом знака.

А вот то, что гнусь не поставил команду ASR, а позвал деление - это непонятно.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 26 2008, 20:20
Сообщение #46


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 26 2008, 15:17) *
Сейчас у меня вот такие опции:
Хм. Странно. Ничего подозрительного не вижу, и на простых примерах воспроизвести не могу. Не генерится у меня код для таких функций...


Цитата(Rst7 @ Nov 26 2008, 17:46) *
Да ну? Где Вы это вычитали? Сдвиг в Си для знаковых операндов всю жизнь был арифметический, с учетом знака.
Читаем первоисточник:
Цитата
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has
an unsigned type or if E1 has a signed type and a nonnegative value, the value of the
result is the integral part of the quotient of E1 / 2^E2. If E1 has a signed type and a
negative value, the resulting value is implementation-defined.

Цитата
When integers are divided, the result of the / operator is the
algebraic quotient with any fractional part discarded. 87)
.....
87) This is often called ``truncation toward zero''.
Обрати внимание, что результат оператора / - не есть целая часть арифметического частного.
И в качестве упражнения тестовый пример:
Код
alx2% cat test.c
#include <stdio.h>
int main(void)
{
    int x = -5;
    return printf("%d, %d\n", x / 2, x >> 1);
}
alx2% gcc -O2 -o t test.c
alx2% ./t
-2, -3


Цитата(Rst7 @ Nov 26 2008, 17:46) *
А вот то, что гнусь не поставил команду ASR, а позвал деление - это непонятно.
Попробуй привести код со сдвигами, выполняющий деление значения типа int (уже находящегося в регистрах) на 2, который был бы не длиннее трех машинных инструкций (напоминаю, что sonycman просил оптимизировать по размеру кода).

Сообщение отредактировал alx2 - Nov 26 2008, 21:00


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 26 2008, 20:45
Сообщение #47


Йа моск ;)
******

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



Цитата(alx2 @ Nov 26 2008, 22:20) *
-2, -3

Однако, сдвиг действительно арифметический. Более подробно посмотрю этот момент, когда попаду за комп, потому как с трубы лень искать. Возможно, я и не прав.

Цитата
Попробуй привести код со сдвигами, выполняющий деление значения типа int (уже находящегося в регистрах) на 2, который был бы не длиннее трех машинных инструкций (напоминаю, что sonycman просил оптимизировать по размеру кода).

Если уж быть точным, там тип signed char у sonycman, так что inc rx, asr rx вполне бы прошло.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 26 2008, 21:35
Сообщение #48


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(Rst7 @ Nov 27 2008, 01:45) *
Если уж быть точным, там тип signed char у sonycman, так что inc rx, asr rx вполне бы прошло.
Если быть совсем точным, smile.gif во-первых, sonycman, к сожалению, не привел деклараций переменных. Во-вторых, там на два делилась разность двух целых значений, которая уже в один байт не помещается. В-третьих, даже если бы не было разности, простого inc rx, asr rx недостаточно: оно дает неверные значения для нечетных положительных чисел. Например, 1/2 даст 1, тогда как должно быть 0. Как минимум, требуется еще sbrs rx,7 в начале, что дает все те же три инструкции...


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 26 2008, 21:56
Сообщение #49


Йа моск ;)
******

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



Цитата(alx2 @ Nov 26 2008, 23:35) *
оно дает неверные значения для нечетных положительных чисел. Например, 1/2 даст 1, тогда как должно быть 0. Как минимум, требуется еще sbrs rx,7 в начале, что дает все те же три инструкции...

Да. Согласен. Чтото я погорячился.

Правда про signed char упомянуто. На предыдущей странице.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 26 2008, 22:02
Сообщение #50


Любитель
*****

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



Цитата(Rst7 @ Nov 27 2008, 00:45) *
Однако, сдвиг действительно арифметический. Более подробно посмотрю этот момент, когда попаду за комп, потому как с трубы лень искать. Возможно, я и не прав.
Если уж быть точным, там тип signed char у sonycman, так что inc rx, asr rx вполне бы прошло.

Да, там у меня char:
Код
#define    LCD_WIDTH 96
byte  lcdGetStringWidth(PGM_P text);

void  lcdPrintText(PGM_P text, byte flags, signed char x, signed char y)
  switch(flags & 0xe0)
  {
  case  TXT_CENTERED:
    if (x < 0)
    {
      x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;
    }
...

Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит crying.gif ... даже switch:
Код
{
  switch(flags & 0xe0)
     e3a:    70 e0           ldi    r23, 0x00; 0
     e3c:    60 7e           andi    r22, 0xE0; 224
     e3e:    70 70           andi    r23, 0x00; 0
     e40:    60 38           cpi    r22, 0x80; 128
     e42:    71 05           cpc    r23, r1
     e44:    21 f0           breq    .+8      ; 0xe4e <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x26>
     e46:    60 3c           cpi    r22, 0xC0; 192
     e48:    71 05           cpc    r23, r1
     e4a:    11 f5           brne    .+68     ; 0xe90 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x68>
     e4c:    1d c0           rjmp    .+58     ; 0xe88 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x60>
     e4e:    c4 2f           mov    r28, r20
     e50:    dd 27           eor    r29, r29
     e52:    c7 fd           sbrc    r28, 7
     e54:    d0 95           com    r29
  {
  case  TXT_CENTERED:
    if (x < 0)
     e56:    47 ff           sbrs    r20, 7
     e58:    0c c0           rjmp    .+24     ; 0xe72 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x4a>
    {
      x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;
     e5a:    da df           rcall    .-76     ; 0xe10 <lcdGetStringWidth(char const*)>
     e5c:    c0 5a           subi    r28, 0xA0; 160
     e5e:    df 4f           sbci    r29, 0xFF; 255
     e60:    9e 01           movw    r18, r28
     e62:    28 1b           sub    r18, r24
     e64:    31 09           sbc    r19, r1
     e66:    c9 01           movw    r24, r18
     e68:    62 e0           ldi    r22, 0x02; 2
     e6a:    70 e0           ldi    r23, 0x00; 0
     e6c:    17 d5           rcall    .+2606   ; 0x189c <__divmodhi4>
     e6e:    16 2f           mov    r17, r22
     e70:    0f c0           rjmp    .+30     ; 0xe90 <lcdPrintText(char const*, unsigned char, signed char, signed char)+0x68>
    }

Одно хоть радует - при вызове функции есть хоть какая-то польза от восьмибитных параметров - их быстрее загружать smile.gif
А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш.
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 27 2008, 04:14
Сообщение #51


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 27 2008, 01:02) *
Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит crying.gif ... даже switch:



6.8.4.2 The switch statement
Constraints
1 The controlling expression of a switch statement shall have integer type.

Цитата(sonycman @ Nov 27 2008, 01:02) *
А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш.



x = (unsigned char )(LCD_WIDTH + x - lcdGetStringWidth(text)) / 2

Код
  31 000a 4983              std Y+1,r20
  32                   .LVL1:
  33 000c 0E94 0000         call lcdGetStringWidth
  34                   .LVL2:
  35 0010 4981              ldd r20,Y+1
  36 0012 405A              subi r20,lo8(-(96))
  37                   .LVL3:
  38 0014 481B              sub r20,r24
  39 0016 4695              lsr r20
  40 0018 4093 0000         sts xx,r20



Анатолий.

Сообщение отредактировал aesok - Nov 27 2008, 04:15
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 27 2008, 07:56
Сообщение #52


Йа моск ;)
******

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



Цитата(sonycman @ Nov 27 2008, 00:02) *
А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш.

Вот именно. switch - хоть и int по стандарту, но если у него аргумент прямо в скобках &0xE0, то никаким стандартом не прикрыть недоточенность компилятора.


Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
msalov
сообщение Nov 27 2008, 08:51
Сообщение #53


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(Rst7 @ Nov 27 2008, 09:56) *
Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так.
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 27 2008, 09:08
Сообщение #54


Йа моск ;)
******

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



Цитата(gotty @ Nov 27 2008, 10:51) *
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

Ссылку. Чтото я совсем потерялся.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
msalov
сообщение Nov 27 2008, 09:24
Сообщение #55


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(Rst7 @ Nov 27 2008, 11:08) *
Ссылку. Чтото я совсем потерялся.


ISO/IEC 9899:1999

5.1.2.3 пункт 10
Цитата
EXAMPLE 2 In executing the fragment
Код
char c1, c2;
/* ...  */
c1 = c1 + c2;

the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size
and then add the two ints and truncate the sum. Provided the addition of two chars can be done without
overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only
produce the same result, possibly omitting the promotions.


6.3.1.1 пункт 2
Цитата
If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions.48) All other types are unchanged by the integer promotions.

48) The integer promotions are applied only: as part of the usual arithmetic conversions, to certain
argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the
shift operators, as specified by their respective subclauses.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 09:28
Сообщение #56


Любитель
*****

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



Цитата(gotty @ Nov 27 2008, 12:51) *
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

Но неужели слепое следование стандартам больших машин - это абсолютно правильно и на AVR?
Неужели в вышеприведённом примере столь необходимо было следовать такому стандарту?

А может существует какая-то опция, позволяющая отключать эту фичу?
Go to the top of the page
 
+Quote Post
zltigo
сообщение Nov 27 2008, 09:45
Сообщение #57


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(sonycman @ Nov 27 2008, 12:28) *
Но неужели слепое следование стандартам больших машин - это абсолютно правильно и на AVR?

Следование стандартам ВСЕГДА правильно, а вот то, что int на восьмибитовике 1бит - вот это уже НЕ ПРАВИЛЬНОЕ (хотя не противоречащее стандарту) решение принятое когда-то производителями восьмибитовых компиляторов sad.gif, полагаю для тупой совместимости с массовыми на тот момент 16bit-овиками, дабы _бездумно_ sad.gif портировать исходники с 16bit интами. Если int действительно имел максимально естественую для 8bit контроллера разрядность 8bit, то и проблем c этитм не было-бы, как их нет не 16/32bit платформах.
Цитата
А может существует какая-то опция, позволяющая отключать эту фичу?

Гипотетически изменить размерность int в хидерах на 8bit и пресобрать все, включая библиотеки. Если авторы компилятора все делали правильно, то должно получиться. А вообще пора завязывать с 8bit smile.gif smile.gif smile.gif


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 10:04
Сообщение #58


Любитель
*****

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



Цитата(zltigo @ Nov 27 2008, 13:45) *
Следование стандартам ВСЕГДА правильно, а вот то, что int на восьмибитовике 1бит - вот это уже НЕ ПРАВИЛЬНОЕ (хотя не противоречащее стандарту) решение принятое когда-то производителями восьмибитовых компиляторов sad.gif, полагаю для тупой совместимости с массовыми на тот момент 16bit-овиками, дабы _бездумно_ sad.gif портировать исходники с 16bit интами. Если int действительно имел максимально естественую для 8bit контроллера разрядность 8bit, то и проблем c этитм не было-бы, как их нет не 16/32bit платформах.

Гипотетически изменить размерность int в хидерах на 8bit и пресобрать все, включая библиотеки. Если авторы компилятора все делали правильно, то должно получиться. А вообще пора завязывать с 8bit smile.gif smile.gif smile.gif

Понятно, спасибо smile.gif
Оставим это как дань стандартам и одновременно лень производителей smile.gif

Почти во всём при компиляции своего проекта уже разобрался.
Ещё вот беспокоят такие ворнинги:
Код
only initialized variables can be placed into program memory area

на стоки, подобные вот этим:
Код
if (statusRx.lock_err) usartSendString(PSTR("Receiver LOCKED!"));

const char PROGMEM fntable[]    = "!\"%`()*+,-./0123456789:;<=>?ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^";

то есть ругается на все PSTR() и на все PROGMEM.
Чего такого неправильного я там сделал? 07.gif
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 27 2008, 11:29
Сообщение #59


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 27 2008, 03:02) *
Код
void  lcdPrintText(PGM_P text, byte flags, signed char x, signed char y)
  switch(flags & 0xe0)
  {
...

Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит crying.gif ... даже switch:
Код
{
  switch(flags & 0xe0)
     e3a:    70 e0           ldi    r23, 0x00; 0
     e3c:    60 7e           andi    r22, 0xE0; 224
     e3e:    70 70           andi    r23, 0x00; 0
     e40:    60 38           cpi    r22, 0x80; 128
     e42:    71 05           cpc    r23, r1
Как ты получил такой код??? =8-( )
Вот такой тестовый пример:
Код
int do_something(void);

void fff(char flags)
{
    switch(flags & 0xe0)
    {
        case 0x80:
            do_something();
    }
}
у меня компилируется вот в такой код:
Код
fff:
/* prologue: function */
/* frame size = 0 */
        andi r24,lo8(-32)
        cpi r24,lo8(-128)
        brne .L4
        rcall do_something
.L4:
        ret
при любой -O отличной от -O0. gcc-4.3.1.
Скажи, пожалуйста, версию своего компилятора, с какой оптимизацией компилировался код и как определено byte.


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 27 2008, 11:35
Сообщение #60


Гуру
******

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



Цитата(sonycman @ Nov 27 2008, 12:04) *
Понятно, спасибо smile.gif
Оставим это как дань стандартам и одновременно лень производителей smile.gif
Стандарт не запрещает оптимизатору не расширять char до int если результат останется одинаковым. Или расширить, но потом все лишнее выкинуть.

Цитата(sonycman @ Nov 27 2008, 12:04) *
то есть ругается на все PSTR() и на все PROGMEM.
Чего такого неправильного я там сделал? 07.gif
Это не вы, это они намудрили в компиляторе.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 27 2008, 11:50
Сообщение #61


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(aesok @ Nov 27 2008, 09:14) *
The controlling expression of a switch statement shall have integer type.
И что? Тип char - тоже integer type, что не мешает ему иметь размер 8 бит...
Тут проблема совсем в другом: результат выражения (flags & 0xe0) всегда дает нули во всех байтах кроме младшего. Поэтому вменяемый оптимизатор должен выкинуть их вычисление из генерируемого кода. У меня так и происходит (см. выше). Почему этого не происходит у sonycman, непонятно...

Цитата(sonycman @ Nov 27 2008, 14:28) *
Но неужели слепое следование стандартам больших машин - это абсолютно правильно и на AVR? Неужели в вышеприведённом примере столь необходимо было следовать такому стандарту?
не "стандартам больших машин", а правилам языка C.
Цитата(sonycman @ Nov 27 2008, 14:28) *
А может существует какая-то опция, позволяющая отключать эту фичу?
Поверь, тебе это не нужно. Я слышал о компиляторах, у которых такая опция есть. Но писать программы с рассчетом на такую опцию - значит писать их не на языке C. То есть сразу теряется совместимость с любыми другими C компиляторами, у которых такой опции нет. Плюс периодически ломать голову над тем, почему результат выражения получился вот такой, а не такой, какой ожидался. Ты хочешь, чтобы у тебя (127 + 127) / 2 давало -1? smile.gif И все ради чего? Ради экономии пары процентов машинного кода?


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 13:35
Сообщение #62


Любитель
*****

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



Цитата(alx2 @ Nov 27 2008, 15:29) *
Как ты получил такой код??? =8-( )
Скажи, пожалуйста, версию своего компилятора, с какой оптимизацией компилировался код и как определено byte.

byte определён как unsigned char.
Версия компилятора - 4.3.2 - последний релиз кандидат.
Оптимизациия Оs.
Полностью командные строки компилятора и линкера я приводил немного ранее.

Странно всё это...
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 27 2008, 16:52
Сообщение #63


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(Rst7 @ Nov 27 2008, 10:56) *
вычисляется через 16 бит. Чтото не так.


Расмотрим пример (x = 20):
#define LCD_WIDTH 240

void lcdPrintText(PGM_P text, byte flags, unsigned char x, signed char y)
{
x = (LCD_WIDTH + x ) / 2;
}

Если расчеты выполняються в 16-битном виде то:
x = (240 + 20) / 2 = 260 /2 = 130.

Если в 8-битной то:
x = (240 + 20) / 2 = 4 /2 = 2.

Вы все еще хотите такую оптимизацию?

Анатолий.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 17:03
Сообщение #64


Любитель
*****

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



2aesok
Если у меня в программе операнд имеет тип char, то это значит, что ни при каких условиях не будет достигнуто переполнение.
Следуя вашей логике, можно и операнды типа word обрабатывать, расширяя до double word...
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 27 2008, 17:08
Сообщение #65


Йа моск ;)
******

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



Цитата(aesok @ Nov 27 2008, 18:52) *
Расмотрим пример

Все понятно. Просто я немного в другом стиле пишу, посему стараюсь ручками прикручивать в нужных местах принудительные касты. Давно это делаю на автоматизме, посему малость торможу.

Только не надо спрашивать, как это - "в другом стиле", на форуме выложенно достаточно, чтобы оценить кривость моих рук smile.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 27 2008, 17:18
Сообщение #66


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 27 2008, 20:03) *
2aesok
Если у меня в программе операнд имеет тип char, то это значит, что ни при каких условиях не будет достигнуто переполнение.

Я вам привел пример когда оба операнда имеют тип char, и происходит переполнение.

Цитата(sonycman @ Nov 27 2008, 20:03) *
Следуя вашей логике, можно и операнды типа word обрабатывать, расширяя до double word...


Компилятор это за вас не сделает, но если Вы не хотите получит ошибку переполнения, то Вы проанализируете исходные данные и формулы, и возжможно, да будете выполнять промежуточные расчеты с 32-битными числами, даже если операнды и результат 16-битные.

Анатолий.

Цитата(Rst7 @ Nov 27 2008, 20:08) *
Только не надо спрашивать, как это - "в другом стиле", на форуме выложенно достаточно, чтобы оценить кривость моих рук smile.gif


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

Анатолий.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 18:22
Сообщение #67


Любитель
*****

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



Цитата(aesok @ Nov 27 2008, 21:18) *
Я вам привел пример когда оба операнда имеют тип char, и происходит переполнение.

Этот пример не имеет ничего общего с моим приложением.
Как не трудно было заметить из моего примера, константа LCD_WIDTH всегда складывается с отрицательным числом. Плюс операнды имеют значения, не допускающие переполнения.

Насчёт кривости рук - что вы скажете про то, откуда берутся странные предупреждения об обязательной инициализации и так инициализированных строковых массивов, расположенных в памяти программ?
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 27 2008, 19:49
Сообщение #68


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата
Этот пример не имеет ничего общего с моим приложением.
Как не трудно было заметить из моего примера, константа LCD_WIDTH всегда складывается с отрицательным числом. Плюс операнды имеют значения, не допускающие переполнения.



Это Ваш пример?
Код
#define    LCD_WIDTH 96
byte  lcdGetStringWidth(PGM_P text);

void  lcdPrintText(PGM_P text, byte flags, signed char x, signed char y)
  switch(flags & 0xe0)
  {
  case  TXT_CENTERED:
    if (x < 0)
    {
      x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;
    }


(LCD_WIDTH + x - lcdGetStringWidth(text)) = 96 + [-128..-1] - [0..255] = [95..-287]

Это чисто попещаеться в signed char? В unsigned char?

Цитата
Насчёт кривости рук - что вы скажете про то, откуда берутся странные предупреждения об обязательной инициализации и так инициализированных строковых массивов, расположенных в памяти программ?


Исходники GCC находяться здесь http://gcc.gnu.org/viewcvs/ Вы можете убрать мешающие Вам предупреждения сами.

Анатолий.

Сообщение отредактировал aesok - Nov 27 2008, 19:54
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 21:52
Сообщение #69


Любитель
*****

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



Цитата(aesok @ Nov 27 2008, 23:49) *
Это Ваш пример?
Код
#define    LCD_WIDTH 96
byte  lcdGetStringWidth(PGM_P text);

void  lcdPrintText(PGM_P text, byte flags, signed char x, signed char y)
  switch(flags & 0xe0)
  {
  case  TXT_CENTERED:
    if (x < 0)
    {
      x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;
    }


(LCD_WIDTH + x - lcdGetStringWidth(text)) = 96 + [-128..-1] - [0..255] = [95..-287]

Это чисто попещаеться в signed char? В unsigned char?

Нет. Но такие величины никогда не будут получены, так как операнды имеют значения, не допускающие переполнения. Не надо выдёргивать из контекста.
Цитата
Исходники GCC находяться здесь http://gcc.gnu.org/viewcvs/ Вы можете убрать мешающие Вам предупреждения сами.

Как? Я, у которого в программе переполнения на каждом шагу, должен исправлять глюки "умного" компилятора, который стараеться генерировать правильный код в не зависимости от кривости рук програмиста?
biggrin.gif

Что-то мне кажется, что мы ведём непродуктивный диалог.

После того, как было установлено, что приведение операндов к 16-ти битам делается для того, чтобы просто удовлетворять стандарту, вы хотите сказать, что это не так?
Что на самом деле этот шаг направлен на предотвращение переполнения?



Цитата(alx2 @ Nov 27 2008, 15:29) *
Как ты получил такой код??? =8-( )
Вот такой тестовый пример:
Код
int do_something(void);

void fff(char flags)
{
    switch(flags & 0xe0)
    {
        case 0x80:
            do_something();
    }
}
у меня компилируется вот в такой код:
Код
fff:
/* prologue: function */
/* frame size = 0 */
        andi r24,lo8(-32)
        cpi r24,lo8(-128)
        brne .L4
        rcall do_something
.L4:
        ret
при любой -O отличной от -O0. gcc-4.3.1.
Скажи, пожалуйста, версию своего компилятора, с какой оптимизацией компилировался код и как определено byte.

Добрался до компа. На всякий случай повторю повнятнее:
У меня WinAVR 20081118rc2 с компилятором GCC 4.3.2.
Оптимизация Os плюс ещё несколько "фишек".
Командная строка компилятора:
Код
avr-g++ -I"F:\Electronics\Projects\GNU\FanController\Headers" -Wall -g2 -gdwarf-2 -Os -fpack-struct -fshort-enums -mcall-prologues -funsigned-char -funsigned-bitfields -fno-exceptions -fno-threadsafe-statics -fno-inline-small-functions -ffunction-sections -mmcu=atmega88 -DF_CPU=10000000UL -MMD -MP -MF"Sources/main.d" -MT"Sources/main.d" -c -o"Sources/main.o" "../Sources/main.cpp"

Скомпилировал твой пример, вот что получилось:
Код
void do_something(char b)
{
    volatile static char a = b;
}

void fff(char flags)
{
    switch(flags & 0xe0)
    {
        case 0x80:
            do_something(0);
        case 0xc0:
            do_something(1);
    }
}


int main( void )
{


    fff(128);
...

и листинг:
Код
void fff(char flags)
{
    switch(flags & 0xe0)
    15be:    90 e0           ldi    r25, 0x00; 0
    15c0:    80 7e           andi    r24, 0xE0; 224
    15c2:    90 70           andi    r25, 0x00; 0
    15c4:    80 38           cpi    r24, 0x80; 128
    15c6:    91 05           cpc    r25, r1
    15c8:    21 f0           breq    .+8      ; 0x15d2 <fff(char)+0x14>
    15ca:    80 3c           cpi    r24, 0xC0; 192
    15cc:    91 05           cpc    r25, r1
    15ce:    29 f4           brne    .+10     ; 0x15da <fff(char)+0x1c>
    15d0:    02 c0           rjmp    .+4      ; 0x15d6 <fff(char)+0x18>
    {
        case 0x80:
            do_something(0);
    15d2:    80 e0           ldi    r24, 0x00; 0
    15d4:    e9 df           rcall    .-46     ; 0x15a8 <do_something(char)>
        case 0xc0:
            do_something(1);
    15d6:    81 e0           ldi    r24, 0x01; 1
    15d8:    e7 df           rcall    .-50     ; 0x15a8 <do_something(char)>
    15da:    08 95           ret

laughing.gif
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 27 2008, 22:22
Сообщение #70


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 28 2008, 00:52) *
Нет. Но такие величины никогда не будут получены, так как операнды имеют значения, не допускающие переполнения. Не надо выдёргивать из контекста.


Причем тут я? Я человек я мог бы Вас и понять. Я Вам показываю как думает тупая железка, тоесть компилятор. Где Вы ему сказали что " операнды имеют значения, не допускающие переполнения"?

Я Вам показывал вариант как это ему сказать:
x = (byte) (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;

И компилятор начал вычислять выражение как 8-битное.

Цитата(sonycman @ Nov 28 2008, 00:52) *
Как? Я, у которого в программе переполнения на каждом шагу, должен исправлять глюки "умного" компилятора, который стараеться генерировать правильный код в не зависимости от кривости рук програмиста?
biggrin.gif


Я не говорил что у Вас кривые руки, Я говорил что компилятор должен компилировать программу написанную даже кривыми руками, при этом программа должна работать в соответствии со стандартом, а в стандарте никаких указазий о скорости выполнения программы нет. Это оставленно на осмотрение разработчика компилятора.

Цитата(sonycman @ Nov 28 2008, 00:52) *
После того, как было установлено, что приведение операндов к 16-ти битам делается для того, чтобы просто удовлетворять стандарту, вы хотите сказать, что это не так?
Что на самом деле этот шаг направлен на предотвращение переполнения?


Я попытался на примере Вам показать почему так написан стандарт.


Цитата(sonycman @ Nov 28 2008, 00:52) *
Добрался до компа. На всякий случай повторю повнятнее:


Пока не знаю.

Анатолий.

Сообщение отредактировал aesok - Nov 27 2008, 22:28
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 27 2008, 22:46
Сообщение #71


Любитель
*****

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



Цитата(aesok @ Nov 28 2008, 02:22) *
Я попытался на примере Вам показать почему так написан стандарт.
Анатолий.

Хм... то есть, разработчики стандарта таким образом подстраховали все вычисления с операндами типа char? 07.gif
Мне всё равно трудно понять рациональность этого хода.
Потому, что ошибка с переполнением может возникнуть с любым по размеру операндом: 8, 16, 32, 64 и так далее бит.
Почему для 8-ми бит сделали исключение?

Цитата
(LCD_WIDTH + x - lcdGetStringWidth(text)) = 96 + [-128..-1] - [0..255] = [95..-287]

Зачем "правильно" считать результат на 16-ти битах, если в конце концов он будет разрушен, будучи "обрезанным" и "запиханным" в signed char?
Если программист не продумал все варианты - ошибка обязательно вылезет всё равно.

Да... 05.gif
Но всё-же, спасибо за попытку всё объяснить. Извиняюсь за некоторое раздражение в моём тоне. beer.gif
В любом случае, стандарты придумывают весьма умные дядьки, не чета таким, как я 01.gif
Порой трудно бывает понять их мотивы. Воистину, пути их неисповедимы smile.gif
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 27 2008, 23:20
Сообщение #72


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 28 2008, 01:46) *
Хм... то есть, разработчики стандарта таким образом подстраховали все вычисления с операндами типа char? 07.gif
Мне всё равно трудно понять рациональность этого хода.
Потому, что ошибка с переполнением может возникнуть с любым по размеру операндом: 8, 16, 32, 64 и так далее бит.
Почему для 8-ми бит сделали исключение?


На самом деле исключение сделано для int. Это как бы тип по умолчанию,
разрядность int обычно равна разрядности регистров общего
назначения, что гарантирует максимальную производительность для этого типа.
Для AVR разрядность int больше разрядности регистра. Сделать int 8-битным
нельзя, в стандарте требуется - размерность указателя равна размерности int,
а 8-битный указатель это слишком мало.


Если быть совсем точным то avr-gcc имеет ключ:
-mint8 Use an 8-bit 'int' type

Его практическая ценность его мала, avr-libc не совместима с этим ключом, и
никогда не будет. Но если будете писать что нибудь маленькое, можете с ним
поиграться.

Цитата
Зачем "правильно" считать результат на 16-ти битах, если в конце концов он будет разрушен, будучи "обрезанным" и "запиханным" в signed char?
Если программист не продумал все варианты - ошибка обязательно вылезет всё равно.


Потому что в вашем примере обрезание рузультата до char произойдеи уже после деления, а для того чтобы результат деления на 2 влез в char делимое может иметь значение до char * 2, и для его хранения нужен int.

Цитата
Порой трудно бывает понять их мотивы. Воистину, пути их неисповедимы


На самом деле все очень просто, отладив несколько своих проектов Вы начнете думать как они...

Анатолий.

Сообщение отредактировал aesok - Nov 27 2008, 23:26
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 28 2008, 00:34
Сообщение #73


Любитель
*****

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



Цитата(aesok @ Nov 28 2008, 03:20) *
Потому что в вашем примере обрезание рузультата до char произойдеи уже после деления, а для того чтобы результат деления на 2 влез в char делимое может иметь значение до char * 2, и для его хранения нужен int.

Ну, не думаю, что компилер будет строить такие предположения.
Исходное положение:
Код
      x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;
     e54:    e0 df           rcall    .-64; 0xe16 <lcdGetStringWidth(char const*)>
     e56:    21 2f           mov    r18, r17
     e58:    33 27           eor    r19, r19
     e5a:    27 fd           sbrc    r18, 7
     e5c:    30 95           com    r19
     e5e:    20 5a           subi    r18, 0xA0; 160
     e60:    3f 4f           sbci    r19, 0xFF; 255
     e62:    a9 01           movw    r20, r18
     e64:    48 1b           sub    r20, r24
     e66:    51 09           sbc    r21, r1
     e68:    ca 01           movw    r24, r20
     e6a:    62 e0           ldi    r22, 0x02; 2
     e6c:    70 e0           ldi    r23, 0x00; 0
     e6e:    17 d5           rcall    .+2606; 0x189e <__divmodhi4>

Смотрите, я убираю деление совсем, и вот что имеем:
Код
  x = (LCD_WIDTH + x - lcdGetStringWidth(text));
     e54:    e0 df           rcall    .-64; 0xe16 <lcdGetStringWidth(char const*)>
     e56:    0a c0           rjmp    .+20; 0xe6c <lcdPrintText(char const*, unsigned char, signed char,      
...
     e6c:    10 5a           subi    r17, 0xA0; 160
     e6e:    18 1b           sub    r17, r24

то есть весь код сводится к простым операциям. Заметьте - результат выражения по-прежнему будет:
Код
(LCD_WIDTH + x - lcdGetStringWidth(text)) = 96 + [-128..-1] - [0..255] = [95..-287]

"невлезающим" в char, и "простая железка" может это просчитать как два пальца...
Но не хочет smile.gif

То же самое будет, если вывести деление во вторую строку:
Код
      x = (LCD_WIDTH + x - lcdGetStringWidth(text));
     e54:    e0 df           rcall    .-64; 0xe16 <lcdGetStringWidth(char const*)>
     e56:    10 5a           subi    r17, 0xA0; 160
      x /= 2;
     e58:    18 1b           sub    r17, r24
     e5a:    81 2f           mov    r24, r17
     e5c:    62 e0           ldi    r22, 0x02; 2
     e5e:    03 d5           rcall    .+2566; 0x1866 <__divmodqi4>

Первое и последнее выражения абсолютно эквивалентны по результату! Зато какие разные по размеру кода?
Тут явно что-то в этом делении... wacko.gif

Не первый раз замечаю, что, чем проще и короче строка программы в си, тем лучше получается у компилятора код.
Лучше разбивать одно длинное выражение на несколько простых. А так хочется извратиться позаковыристее, так, чтобы самому потом полчаса глаза таращить biggrin.gif
Задумывались бы чаще над этой проблемой те умные дядьки, которые всякие хитрые стандарты придумывают.
Уже 21 век на дворе, а мы всё плюсик на одной строке, а минусик - только на следующей, а то ещё у железки голова закружится... rolleyes.gif

Цитата(aesok @ Nov 28 2008, 03:20) *
На самом деле все очень просто, отладив несколько своих проектов Вы начнете думать как они...

Ну дай-то бог! cool.gif

ЗЫ: Всем спокойной ночи!
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 28 2008, 01:08
Сообщение #74


Гуру
******

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



Цитата(sonycman @ Nov 28 2008, 02:34) *
То же самое будет, если вывести деление во вторую строку:
Код
  x = (LCD_WIDTH + x - lcdGetStringWidth(text));
тем самым в процессе присваивания неявно приводя результат типа int к типу x, т.е. signed char, что и советовал вам aesok:
Цитата(aesok @ Nov 28 2008, 00:22) *
x = (byte) (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;
Так что, как видите, никаких чудес.
Цитата(sonycman @ Nov 28 2008, 02:34) *
Код
      x /= 2;
А тут деление signed char x на int 2 тоже с приведением результата. Tут компилятор смог сообразить и отбросить расширение.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 29 2008, 11:51
Сообщение #75


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 28 2008, 02:52) *
Код
    switch(flags & 0xe0)
    {
        case 0x80:
            do_something(0);
        case 0xc0:
            do_something(1);
    }
как показали эксперименты, как только в switch появляется второй case, в ассемблерном коде появляется вычисление незначащего старшего байта. Склоняюсь к выводу о недостатке оптимизатора в данном случае.

Цитата(sonycman @ Nov 28 2008, 03:46) *
Мне всё равно трудно понять рациональность этого хода.
Потому, что ошибка с переполнением может возникнуть с любым по размеру операндом: 8, 16, 32, 64 и так далее бит.
Почему для 8-ми бит сделали исключение?
Зачем "правильно" считать результат на 16-ти битах, если в конце концов он будет разрушен, будучи "обрезанным" и "запиханным" в signed char?
Если программист не продумал все варианты - ошибка обязательно вылезет всё равно.
Я не знаю точно, из каких соображений язык C сделан именно так, но выскажу свои соображения по этом поводу.
Во-первых, с последним утверждением согласен. Исходим из предположения, что кодер подумал, и ошибок в коде нет.

Во-вторых, я подозреваю, что вероятность выхода результата неких вычислений за границы диапазона (-128...127) намного выше чем диапазона (-32768...32767). Поэтому кодеру очень часто пришлось бы писать явное приведение к типу int, например писать (0 + a + b) / 2 вместо (a + b) / 2. Лично мне это бы не понравилось, т.к. во-первых, больше текста - больше вероятность ошибиться, а во-вторых, ухудшается читаемость кода. Почему тип приводится к int, а не к long или long long - я думаю, это компромисс между удобством и эффективностью. Случаи, когда диапазон значений int для вычислений недостаточен - достаточно редки чтобы явное приведение к long (long) не доставляло больших неудобств.

Наконец, что результат "в конце концов будет разрушен, будучи "обрезанным" и "запиханным" в signed char" - просто неверно, об этом aesok уже сказал.

Цитата(sonycman @ Nov 28 2008, 05:34) *
Код
      x = (LCD_WIDTH + x - lcdGetStringWidth(text)) / 2;

Код
      x = (LCD_WIDTH + x - lcdGetStringWidth(text));
      x /= 2;

Первое и последнее выражения абсолютно эквивалентны по результату!
Не эквивалентны. В первом случае преобразование к типу char производится перед делением, во втором - после. Например при LCD_WIDTH=96, x=32 и lcdGetStringWidth(text)=0 результат этих выражений будет разным.

Сообщение отредактировал alx2 - Nov 29 2008, 11:53


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 29 2008, 12:53
Сообщение #76


Йа моск ;)
******

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



Цитата
Во-вторых, я подозреваю, что вероятность выхода результата неких вычислений за границы диапазона (-128...127) намного выше чем диапазона (-32768...32767).


Да ну? Рассмотрим операцию сложения. Независимо от размера - char или int - половина возможных операндов (немного меньше, без 2n, где n - количество разрядов) приведет к переполнению. А значит - вероятность почти 50% и не зависит от размерности smile.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 29 2008, 19:31
Сообщение #77


фанат дивана
******

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



Цитата(Rst7 @ Nov 29 2008, 17:53) *
А значит - вероятность почти 50% и не зависит от размерности smile.gif

Но ведь 50% от 0xFFFF - это гораздо больше, чем 50% от 0xFF! smile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 29 2008, 21:02
Сообщение #78


Любитель
*****

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



Цитата(alx2 @ Nov 29 2008, 15:51) *
Поэтому кодеру очень часто пришлось бы писать явное приведение к типу int, например писать (0 + a + cool.gif / 2 вместо (a + cool.gif / 2. Лично мне это бы не понравилось, т.к. во-первых, больше текста - больше вероятность ошибиться, а во-вторых, ухудшается читаемость кода.

Зачем часто писать явное приведение к int? Разумнее сразу иметь хотя-бы одну переменную размерности int, если обработка данных типа char приводит к образованию переполнения smile.gif
В моём случае (применительно к моему проекту) ситуация совсем обратная. Мне частенько приходится делать явное приведение к char sad.gif
Почему? Потому что я резонно предполагал более эффективную работу восьмибитного ядра именно с "родным" типом данных - с char. Поэтому старался иметь максимальное количество переменных такого типа.

Цитата
Не эквивалентны. В первом случае преобразование к типу char производится перед делением, во втором - после. Например при LCD_WIDTH=96, x=32 и lcdGetStringWidth(text)=0 результат этих выражений будет разным.

Ты говоришь про общий случай. Я - про строку кода конкретной функции lcdPrintText, в которой делимое всегда лежит в пределах 0 <= d < 96.
Поэтому эти выражения совершенно эквивалентны.
Ты можешь возразить - а откуда это может знать компилятор? Я соглашусь - не может он этого знать, он просто "железяка", которой внушили, что она много знает, и которой время от времени приходится "выпрямлять руки". biggrin.gif

Но продолжим о "выражениях".
Благодаря стандарту, первое выражение имеет в два с половиной раза больший объём кода.
А если в программе таких выражений десятки? Тогда мы получаем в коде сотни байт ненужного мусора, что для маленьких кристаллов является актуальной проблемой.

Что мы делаем? Мы делаем явное приведение типов/разбиваем выражения на несколько частей и т.д. и т.п., что, как ты верно заметил,
Цитата
лично мне это бы не понравилось, т.к. во-первых, больше текста - больше вероятность ошибиться, а во-вторых, ухудшается читаемость кода

в чём я полностью с тобой согласен!

Так что это палка о двух концах. laughing.gif

Да бог с этими стандартами.
Я попробую компилировать проект сразу в двух компиляторах - IAR и GCC. Хочу сравнить и отписаться об их "узких местах", так как меня это заинтересовало.
Может, ещё кому-то это будет интересно... smile.gif

ЗЫ: вся эта возня с битами снова навела меня на мысль "пощупать" 16-ти битные MSP430. Как-то годик назад я взглянул мельком на несколько мануалов, но показалось, что они послабее периферией универсальных "мег"...
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 29 2008, 21:43
Сообщение #79


Йа моск ;)
******

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



Цитата(AHTOXA @ Nov 29 2008, 21:31) *
Но ведь 50% от 0xFFFF - это гораздо больше, чем 50% от 0xFF! smile.gif

Плохо Вы знаете определение вероятности. Вероятность - это отношение количества интересующих состояний к общему количеству состояний. В рассматриваемом случае вероятность одинакова (мелочь не учитываем). А уж абсолютные количества состояний - это совсем другой вопрос. Если выбирается разрядность 8, значит кодер чтото знает о свойствах своих переменных.

А вообще, истоки этого дела (расширение до int) в системе команд PDP-11. Так же, как и описание восьмиричных констант на символ меньше шестнадцатиричных (ребята из DEC'а очень любили восьмиричную систему)

С другой стороны лично я выработал некий набор костылей, которые позволяют писать код, хорошо ложащийся как на AVR, так и на ARM (или на другой 32хбитный камень, да и 16тибитный тоже). В частности, это регулярное применение каста (UREG) и (REG), а сами эти типы определяют размер регистра (например, char для AVR, int для архитектур с более высокой разрядностью). Код, конечно, для неподготовленного человека содержит приличное количество странной писанины, но зато с весьма хорошим результатом после компиляции. Еще один финт - минимизация использования знаковых переменных, т.к. это часто приводит к лишним операциям типа расширения знака.

Кроме того, лично я, например, против современного игнорирования ключевого слова register. Но это отдельный разговор.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 29 2008, 21:56
Сообщение #80


Любитель
*****

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



Цитата(Rst7 @ Nov 30 2008, 01:43) *
С другой стороны лично я выработал некий набор костылей, которые позволяют писать код, хорошо ложащийся как на AVR, так и на ARM (или на другой 32хбитный камень, да и 16тибитный тоже). В частности, это регулярное применение каста (UREG) и (REG), а сами эти типы определяют размер регистра (например, char для AVR, int для архитектур с более высокой разрядностью). Код, конечно, для неподготовленного человека содержит приличное количество странной писанины, но зато с весьма хорошим результатом после компиляции. Еще один финт - минимизация использования знаковых переменных, т.к. это часто приводит к лишним операциям типа расширения знака.

Кроме того, лично я, например, против современного игнорирования ключевого слова register. Но это отдельный разговор.


Спасибо за советы smile.gif
Вас, видимо, весьма интересует тема оптимального кода.
Наверное, осталась привычка со времён спектрума?
Мне кажется, сейчас не каждый заглядывает в "недра" бинарников, особенно программеры PC софта.
За отсутствием необходимости? sad.gif

Раскопал ещё один "пережиток стандарта".
Имеем текст:
Код
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()...
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 29 2008, 22:00
Сообщение #81


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(sonycman @ Nov 30 2008, 00:02) *
Я попробую компилировать проект сразу в двух компиляторах - IAR и GCC. Хочу сравнить и отписаться об их "узких местах", так как меня это заинтересовало.
Может, ещё кому-то это будет интересно... smile.gif


Мне это будет интересно. Еще интереснее если Вы вооружитесь стандартом на
язык С и выступите в качестве третьего компилятора. Еще, GCC в первую очередь
компилятор стандартного языка С, во вторую компилятор для нескольких
популярных архитектур x86, ARM, 68k и уже в третью - четвертую компилятор для
AVR. Для AVR добавлено много оптимизаций, но всегда есть куда
совершенствоваться. Да но это не значит что на каждое Ваше хочу ктото кудато побежит
чегото делать, какие-то вещи невозможно сделать, какие-то очень трудно, на кикие-то
просто нет времени, а какаето просто не интересно делать. Не забывайте, что Вам никто
ничего не обязан.

Любая конструктивная и обоснованная критика принимается. Не конструктивная,
типа "мне ПОФИГ, что стандарт требует приведения выражения к int, я знаю что
при моих входных параметрах выражение никогда не даст в результате больше 96,
и я ХОЧЮ чтобы компилятор это угадал и использовав при расчетах тип char"
меня не интересует.

К сожалению в мои таланты не входит просто и доходчиво учить и разъяснять
положения стандарта и занимаюсь я этим очень редко и неохотно.

Это ссылка на стандарт: www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf

С уважением,
Анатолий.
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 29 2008, 22:24
Сообщение #82


Любитель
*****

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



Цитата(aesok @ Nov 30 2008, 02:00) *
Не забывайте, что Вам никто
ничего не обязан.

Я разве здесь хоть что-то от кого-то потребовал?
Просто привожу вещи, которые мне непонятны/кажутся глупыми/достойными восхищения и т.д. и т.п.
И премного благодарен всем, кто наставляет меня "на путь истинный" a14.gif
И, вероятнее всего, не только меня.

Цитата
мне ПОФИГ, что стандарт требует приведения выражения к int, я знаю что
при моих входных параметрах выражение никогда не даст в результате больше 96,
и я ХОЧЮ чтобы компилятор это угадал и использовав при расчетах тип char

Если вы не поняли, то весь смысл про char был в одном - применительно к AVR это неудобно и неэффективно. С моей точки зрения. Никому её не навязываю и тем более никого не убеждаю изменять стандарты smile.gif
А вот доводить до ума оптимизацию, думаю, нужно. В частности, по обработке switch?
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 29 2008, 22:24
Сообщение #83


Йа моск ;)
******

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



Цитата(aesok @ Nov 30 2008, 00:00) *
меня не интересует.

Простите, а Вы участвуете в разработке GCC, в частности для AVR?

Если да, то у меня есть конструктивная критика. Изложена она в ветке про сборки klen'а. Это Вас заинтересует? Или обычный ответ - "никто никому ничего не должен?" wink.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 29 2008, 22:36
Сообщение #84


Знающий
****

Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484



Цитата(Rst7 @ Nov 30 2008, 01:24) *
Простите, а Вы участвуете в разработке GCC, в частности для AVR?


Да.

Цитата(Rst7 @ Nov 30 2008, 01:24) *
Если да, то у меня есть конструктивная критика. Изложена она в ветке про сборки klen'а. Это Вас заинтересует? Или обычный ответ - "никто никому ничего не должен?" wink.gif


К сожалению ответ тоже, да. Идей и багов намного больше чем времени на них.

Анатолий.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 29 2008, 22:53
Сообщение #85


Йа моск ;)
******

Группа: Модераторы
Сообщений: 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. Так что все не так плохо smile.gif

Цитата(aesok @ Nov 30 2008, 00:36) *
К сожалению ответ тоже, да.

Я так и думал. Очень жаль. На самом деле внесенный баг весьма серьезен.

Вынужден констатировать, что многие опенсорсные проекты в конце концов превращаются в "жрите что дают". Да еще и морально подпитываются говнопиаром класса "халява рулит" sad.gif

За сим откланиваюсь. Было приятно освежить в памяти подзабытые вещи благодаря конструктивной беседе с Вами.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 29 2008, 23:14
Сообщение #86


Любитель
*****

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



Цитата(Rst7 @ Nov 30 2008, 02:53) *
Дык гдето в соседней ветке (кажется, "За что я не люблю Си") ктото привел макрос критической секции из цикла for, а я дальше выложил его вариант для IAR'а, с учетом его встроенных intrinsinc'ов. Кстати, есть еще в IAR'е всякие полезности типа __monitor, __save_interrupt и __restore_interrupt. Так что все не так плохо smile.gif

1. Посмотрю обязательно.
2. __monitor я и юзал. Жаль, что он работает только ко всей функции...

В ИАРе очень удобно сделана работа с указателями на память программ и eeprom. Она совершенно не отличается от указателей на оперативку a14.gif
Хотелось бы видеть такое когда-нибудь и в GCC.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 29 2008, 23:23
Сообщение #87


фанат дивана
******

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



Цитата(Rst7 @ Nov 30 2008, 02:43) *
Плохо Вы знаете определение вероятности.

Это да, еле-еле сдал на троечку 05.gif Но! Самой тётушке Вентцель yeah.gif
Зато в процентах я силёнsmile.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
aesok
сообщение Nov 29 2008, 23:31
Сообщение #88


Знающий
****

Группа: Участник
Сообщений: 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) *
Да еще и морально подпитываются говнопиаром класса "халява рулит" sad.gif


Я могу ответить только за себя. Я НИКОГДА не занимался пиаром свободного софта. ВЫ не найдете ни одного моего призыва чем то пользаваться а чем то нет.

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

Анатолий.

PS: Для чего я этим занимаюсь, Вас не касается.

Сообщение отредактировал aesok - Nov 29 2008, 23:59
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 30 2008, 10:23
Сообщение #89


Любитель
*****

Группа: Свой
Сообщений: 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 байт...
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 30 2008, 11:09
Сообщение #90


Йа моск ;)
******

Группа: Модераторы
Сообщений: 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


Попробуйте сделать аналогичный финт с гнусем, посмотрим, как он себя поведет.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 30 2008, 11:57
Сообщение #91


Любитель
*****

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



Цитата(Rst7 @ Nov 30 2008, 15:09) *
218 bytes in segment CODE

Круто!
Чуть погодя попробую.
Изначально (в IAR) для флагов ошибок действительно использовались битовые поля, но после того, как я взглянул, что вытворяет с ними гнусь - убрал поскорее 07.gif
Чуть погодя обязательно попробую и отпишусь о результатах smile.gif
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 30 2008, 13:13
Сообщение #92


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Привет, Rst7!
Цитата(Rst7 @ Nov 29 2008, 17:53) *
Да ну? Рассмотрим операцию сложения. Независимо от размера - char или int - половина возможных операндов (немного меньше, без 2n, где n - количество разрядов) приведет к переполнению. А значит - вероятность почти 50% и не зависит от размерности smile.gif
Честно говоря, я ничего не понял. smile.gif Я ведь говорю не о теоретической математике, а о сугубо прикладной. Математические величины, над которыми производятся вычисления в программе, как правило, отражают реальные сущности окружающего мира. Поэтому значения этих величин первичны по отношению к программе. Исходя из них программист выбирает, в частности, разрядность, необходимую для проведения вычислений. Я имел в виду, что для представления некой величины 8-ми бит может оказаться недостаточно с большей вероятностью, чем 16, и, тем более, 32-х. К примеру, количество людей, прошедших через турникет за час - оно вполне может измеряться несколькими сотнями. А вот превысить 65 тысяч, я думаю, не сможет. smile.gif


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 30 2008, 13:22
Сообщение #93


Любитель
*****

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



RST7
Не получается у меня научить гнуса правильно обращаться с битовым полем.
Даже с Вашей помощью... crying.gif
Вот что получилось:
Код
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_ERROR;

struct    usart_rx_status
{
    byte    counter;
    byte    mode;
    volatile bool data_available;
    USART_ERROR    error;
};

ISR(USART_RX_vect)
{
    static    byte    sign[] PROGMEM =    {'S','N'};
    static    byte    length;
    byte    data, state;
    USART_ERROR error;
    error    =    statusRx.error;

    do
    {
        state    =    UCSR0A;
        data    =    UDR0;
        if (statusRx.data_available)
            {
                error.lock_err    =    TRUE;
                continue;
            }
        if (state & ((1<<FE0)|(1<<DOR0)|(1<<UPE0)))
        {
            if (state & (1<<FE0)) error.frame_err    =    TRUE;
            if (state & (1<<DOR0)) error.ovrun_err    =    TRUE;
            if (state & (1<<UPE0)) error.parity_err    =    TRUE;
            statusRx.mode    =    RX_SEEK;
            statusRx.counter    =    0;
            continue;
        }
        else
        {
            error.frame_err    =    0;
            error.ovrun_err    =    0;
            error.parity_err    =    0;
            error.length_err    =    0;
            error.lock_err    =    0;
            error.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)
                {
                    error.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));
    statusRx.error    =    error;
}

и результат компиляции первой строчки:
Код
    error    =    statusRx.error;
     b38:    80 91 ae 01     lds    r24, 0x01AE
     b3c:    58 2f           mov    r21, r24
     b3e:    52 95           swap    r21
     b40:    51 70           andi    r21, 0x01; 1
     b42:    b8 2f           mov    r27, r24
     b44:    b1 70           andi    r27, 0x01; 1
     b46:    68 2f           mov    r22, r24
     b48:    66 95           lsr    r22
     b4a:    61 70           andi    r22, 0x01; 1
     b4c:    78 2f           mov    r23, r24
     b4e:    76 95           lsr    r23
     b50:    76 95           lsr    r23
     b52:    71 70           andi    r23, 0x01; 1
     b54:    f8 2f           mov    r31, r24
     b56:    f6 95           lsr    r31
     b58:    f6 95           lsr    r31
     b5a:    f6 95           lsr    r31
     b5c:    f1 70           andi    r31, 0x01; 1
     b5e:    e8 2f           mov    r30, r24
     b60:    e2 95           swap    r30
     b62:    e6 95           lsr    r30
     b64:    e1 70           andi    r30, 0x01; 1
     b66:    08 2f           mov    r16, r24
     b68:    02 95           swap    r16
     b6a:    06 95           lsr    r16
     b6c:    06 95           lsr    r16
     b6e:    01 70           andi    r16, 0x01; 1

дальше в коде в основном всё осталось по-прежнему...
laughing.gif
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 30 2008, 13:41
Сообщение #94


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 30 2008, 02:02) *
Зачем часто писать явное приведение к int? Разумнее сразу иметь хотя-бы одну переменную размерности int, если обработка данных типа char приводит к образованию переполнения smile.gif
Это можно. Но тогда в памяти будут храниться незначащие байты.
Цитата(sonycman @ Nov 30 2008, 02:02) *
Ты говоришь про общий случай. Я - про строку кода конкретной функции lcdPrintText, в которой делимое всегда лежит в пределах 0 <= d < 96. Поэтому эти выражения совершенно эквивалентны.
Я говорил о правилах языка, а они пишутся именно для общего случая. Я вполне допускаю, что изменение правил дало бы для данной конкретной программы выигрыш в объеме. Вопрос в том, стоит ли этот выигрыш потери совместимости. В конце концов, если уж так хочется, можно ИМХО создать свой класс mychar, и определить для него такую математику, какую хочется. В том числе приведение к char каждого промежуточного результата. И другой язык для этого придумывать не обязательно. smile.gif


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Rst7
сообщение Nov 30 2008, 13:46
Сообщение #95


Йа моск ;)
******

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



Цитата
и результат компиляции первой строчки:


Жесть. Все биты превратил в char'ы и разложил в регистрах. В конце функции, кстати, должен был собрать вместе smile.gif

Выбросьте Вы, наверное, нафиг эту опенсорсную какашку.

Потому как на данном этапе получить из него более лучший чем у IAR'а код не получается. И врядли когда-либо в обозримом будущем получится. Даже с учетом того, что у IAR'а иногда наблюдаются психозы с указателями.

А в общем, я бы рекомнедовал купить IAR и клевать мозг его разработчикам. Потому как тогда будут заплачены денежки и есть за что бороться. Сам я в ближайшее время собираюсь по этому пути пойти.

А с гнусем - Вы же сами видите, любая просьба (даже о рассмотрении серьезного бага в оптимизаторе) посылается куда подальше - ведь "никто никому не должен". Аргумент о том, что багов и пожеланий больше чем времени, не принимается - нет времени пилить напильником гнуся - не надо за него вообще браться. Как там, в StarWars - "не надо пытаться, делай - или не делай" smile.gif

Пардон, если зацепил кого. Ничего личного, просто констатация факта.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 30 2008, 13:57
Сообщение #96


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 30 2008, 02:56) *
Имеем текст:
Код
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>

Здесь вроде нет знаковых переменных, и нет сложения. Почему не сработала оптимизация?
Что именно тут можно было сделать более оптимально?

Цитата(sonycman @ Nov 30 2008, 02:56) *
Также есть проблемы с утилитой создания листинга avr-objdump - как видно, неправильно вычисляется адрес подпрограммы деления...

А зачем вообще в данном случае использовать дизассемблирование? Почему не смотреть сразу вывод компилятора? Там хотя бы все имена символов на своих местах:
Код
        lds r24,maxRPM
        ldi r25,lo8(0)
        lds r18,minRPM
        sub r24,r18
        sbc r25,__zero_reg__
        ldi r22,lo8(2)
        ldi r23,hi8(2)
        rcall __divmodhi4
        sts percent,r22
        ret
А узнать адрес функции удобнее из map-файла...
Цитата(sonycman @ Nov 30 2008, 02:56) *
Так это как раз не компилятор, это просто библиотечные макросы. Аналогичные макросы можно сделать для любого минимально вменяемого компилятора.

Но разве есть подобные макросы для IAR? Там ведь приходится пользоваться громоздкой конструкцией с pragma и примитивными __disable_interrupt() и __enable_interrupt()...
Не знаю, я IAR'ом никогда не пользовался. Даже если нет, что мешает написать? Вот в GCC тоже нет таких макросов - так сделали же...

Сообщение отредактировал alx2 - Nov 30 2008, 14:50


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 30 2008, 14:19
Сообщение #97


Любитель
*****

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



Цитата(Rst7 @ Nov 30 2008, 17:46) *
Жесть. Все биты превратил в char'ы и разложил в регистрах. В конце функции, кстати, должен был собрать вместе smile.gif
Выбросьте Вы, наверное, нафиг эту опенсорсную какашку.

Наверное, так и придётся поступить в конце концов. Но почему-то жаль... crying.gif

Цитата(alx2 @ Nov 30 2008, 17:41) *
В конце концов, если уж так хочется, можно ИМХО создать свой класс mychar, и определить для него такую математику, какую хочется.

А вот это очень интересно! Надо будет попробовать на досуге! smile.gif

Цитата(alx2 @ Nov 30 2008, 17:57) *
А зачем вообще в данном случае использовать дизассемблирование? Почему не смотреть сразу вывод компилятора? Там хотя бы все имена символов на своих местах:

А как помотреть? Я в эклипсе не вижу больше никаких файлов после компиляции, кроме .lss 07.gif

Цитата
Даже если нет, что мешает написать?

Мне самому просто знаний не хватит написать "извращение", подобное ATOMIC_BLOCK().
По крайней мере, на данных порах.
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 30 2008, 14:21
Сообщение #98


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 30 2008, 04:14) *
В ИАРе очень удобно сделана работа с указателями на память программ и eeprom. Она совершенно не отличается от указателей на оперативку a14.gif
Хотелось бы видеть такое когда-нибудь и в GCC.
Можно в двух словах, как это сделано в IAR? Предполагаю, что там сделаны "универсальные указатели", которые включают не только адрес, но и идентификатор адресного пространства (код/данные). Кстати, опять же, IMHO ничто не мешает определить какой-нибудь класс u_pointer, хранящий такой указатель, и все необходимые для него операции. И не надо ждать, когда авторы компилятора что-то там сделают...


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
sonycman
сообщение Nov 30 2008, 14:34
Сообщение #99


Любитель
*****

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



Цитата(alx2 @ Nov 30 2008, 18:21) *
Можно в двух словах, как это сделано в IAR? Предполагаю, что там сделаны "универсальные указатели", которые включают не только адрес, но и идентификатор адресного пространства (код/данные). Кстати, опять же, IMHO ничто не мешает определить какой-нибудь класс u_pointer, хранящий такой указатель, и все необходимые для него операции. И не надо ждать, когда авторы компилятора что-то там сделают...

Я без понятия, как там это сделано. Но выглядит вот так:
Код
__no_init __eeprom byte    ds1820romcodes[4][10]    @ 0x0;
static     unsigned char    ds18rom[4][10];

void    ds18Init(void)
{
    for(byte    a=0;a<40;a++)
    {
        ds18rom[0][a]    =    ds1820romcodes[0][a];
    }
}

Также и с обращением на чтение памяти программ:
Код
lcdPrintText("CPU");

void  lcdPrintText(char const __flash __flash *text)
{
  while(*text) lcdPutChar(*text++);
}

laughing.gif
Go to the top of the page
 
+Quote Post
alx2
сообщение Nov 30 2008, 14:40
Сообщение #100


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(sonycman @ Nov 30 2008, 03:24) *
А вот доводить до ума оптимизацию, думаю, нужно. В частности, по обработке switch?
Можно немного подсказать gcc, поместив промежуточный результат во временную переменную:
Код
void do_something();
void do_something_else();
void fff(char flags)
{
    char tmp = flags & 0xe0;
    switch(tmp)
    {
        case 0x40:
            do_something();
            break;
        case 0x80:
            do_something_else();
    }
}

Результат компиляции:
Код
_Z3fffc:
        andi r24,lo8(-32)
        cpi r24,lo8(64)
        breq .L3
        cpi r24,lo8(-128)
        brne .L5
        rjmp .L6
.L3:
        rcall _Z12do_somethingv
        ret
.L6:
        rcall _Z17do_something_elsev
.L5:
        ret


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post

10 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 21:50
Рейтинг@Mail.ru


Страница сгенерированна за 0.03265 секунд с 7
ELECTRONIX ©2004-2016