Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Перенос кода из под ИАРа на WinAVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Страницы: 1, 2, 3
aesok
Цитата(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



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

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


Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так.
msalov
Цитата(Rst7 @ Nov 27 2008, 09:56) *
Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так.
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.
Rst7
Цитата(gotty @ Nov 27 2008, 10:51) *
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

Ссылку. Чтото я совсем потерялся.
msalov
Цитата(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.
sonycman
Цитата(gotty @ Nov 27 2008, 12:51) *
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

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

А может существует какая-то опция, позволяющая отключать эту фичу?
zltigo
Цитата(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
sonycman
Цитата(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
alx2
Цитата(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.
Сергей Борщ
Цитата(sonycman @ Nov 27 2008, 12:04) *
Понятно, спасибо smile.gif
Оставим это как дань стандартам и одновременно лень производителей smile.gif
Стандарт не запрещает оптимизатору не расширять char до int если результат останется одинаковым. Или расширить, но потом все лишнее выкинуть.

Цитата(sonycman @ Nov 27 2008, 12:04) *
то есть ругается на все PSTR() и на все PROGMEM.
Чего такого неправильного я там сделал? 07.gif
Это не вы, это они намудрили в компиляторе.
alx2
Цитата(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 И все ради чего? Ради экономии пары процентов машинного кода?
sonycman
Цитата(alx2 @ Nov 27 2008, 15:29) *
Как ты получил такой код??? =8-( )
Скажи, пожалуйста, версию своего компилятора, с какой оптимизацией компилировался код и как определено byte.

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

Странно всё это...
aesok
Цитата(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.

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

Анатолий.
sonycman
2aesok
Если у меня в программе операнд имеет тип char, то это значит, что ни при каких условиях не будет достигнуто переполнение.
Следуя вашей логике, можно и операнды типа word обрабатывать, расширяя до double word...
Rst7
Цитата(aesok @ Nov 27 2008, 18:52) *
Расмотрим пример

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

Только не надо спрашивать, как это - "в другом стиле", на форуме выложенно достаточно, чтобы оценить кривость моих рук smile.gif
aesok
Цитата(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


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

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

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

Насчёт кривости рук - что вы скажете про то, откуда берутся странные предупреждения об обязательной инициализации и так инициализированных строковых массивов, расположенных в памяти программ?
aesok
Цитата
Этот пример не имеет ничего общего с моим приложением.
Как не трудно было заметить из моего примера, константа 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/ Вы можете убрать мешающие Вам предупреждения сами.

Анатолий.
sonycman
Цитата(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
aesok
Цитата(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) *
Добрался до компа. На всякий случай повторю повнятнее:


Пока не знаю.

Анатолий.
sonycman
Цитата(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
aesok
Цитата(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.

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


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

Анатолий.
sonycman
Цитата(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

ЗЫ: Всем спокойной ночи!
Сергей Борщ
Цитата(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ут компилятор смог сообразить и отбросить расширение.
alx2
Цитата(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 результат этих выражений будет разным.
Rst7
Цитата
Во-вторых, я подозреваю, что вероятность выхода результата неких вычислений за границы диапазона (-128...127) намного выше чем диапазона (-32768...32767).


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

Но ведь 50% от 0xFFFF - это гораздо больше, чем 50% от 0xFF! smile.gif
sonycman
Цитата(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. Как-то годик назад я взглянул мельком на несколько мануалов, но показалось, что они послабее периферией универсальных "мег"...
Rst7
Цитата(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. Но это отдельный разговор.
sonycman
Цитата(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()...
aesok
Цитата(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

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

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

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

Если вы не поняли, то весь смысл про char был в одном - применительно к AVR это неудобно и неэффективно. С моей точки зрения. Никому её не навязываю и тем более никого не убеждаю изменять стандарты smile.gif
А вот доводить до ума оптимизацию, думаю, нужно. В частности, по обработке switch?
Rst7
Цитата(aesok @ Nov 30 2008, 00:00) *
меня не интересует.

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

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


Да.

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


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

Анатолий.
Rst7
Цитата(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

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

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

В ИАРе очень удобно сделана работа с указателями на память программ и eeprom. Она совершенно не отличается от указателей на оперативку a14.gif
Хотелось бы видеть такое когда-нибудь и в GCC.
AHTOXA
Цитата(Rst7 @ Nov 30 2008, 02:43) *
Плохо Вы знаете определение вероятности.

Это да, еле-еле сдал на троечку 05.gif Но! Самой тётушке Вентцель yeah.gif
Зато в процентах я силёнsmile.gif
aesok
Цитата(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: Для чего я этим занимаюсь, Вас не касается.
sonycman
Неважнецки получается у 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 байт...
Rst7
Хоть я и откланялся, но господину 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


Попробуйте сделать аналогичный финт с гнусем, посмотрим, как он себя поведет.
sonycman
Цитата(Rst7 @ Nov 30 2008, 15:09) *
218 bytes in segment CODE

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


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

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

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

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

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

Пардон, если зацепил кого. Ничего личного, просто констатация факта.
alx2
Цитата(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 тоже нет таких макросов - так сделали же...
sonycman
Цитата(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().
По крайней мере, на данных порах.
alx2
Цитата(sonycman @ Nov 30 2008, 04:14) *
В ИАРе очень удобно сделана работа с указателями на память программ и eeprom. Она совершенно не отличается от указателей на оперативку a14.gif
Хотелось бы видеть такое когда-нибудь и в GCC.
Можно в двух словах, как это сделано в IAR? Предполагаю, что там сделаны "универсальные указатели", которые включают не только адрес, но и идентификатор адресного пространства (код/данные). Кстати, опять же, IMHO ничто не мешает определить какой-нибудь класс u_pointer, хранящий такой указатель, и все необходимые для него операции. И не надо ждать, когда авторы компилятора что-то там сделают...
sonycman
Цитата(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
alx2
Цитата(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
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.