Перейти к содержанию
    

Перенос кода из под ИАРа на WinAVR

Сейчас у меня вот такие опции:
Хм. Странно. Ничего подозрительного не вижу, и на простых примерах воспроизвести не могу. Не генерится у меня код для таких функций...

 

 

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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

-2, -3

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

оно дает неверные значения для нечетных положительных чисел. Например, 1/2 даст 1, тогда как должно быть 0. Как минимум, требуется еще sbrs rx,7 в начале, что дает все те же три инструкции...

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Если уж быть точным, там тип 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: ... даже 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>
    }

Одно хоть радует - при вызове функции есть хоть какая-то польза от восьмибитных параметров - их быстрее загружать :)

А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит :crying: ... даже switch:

 

 

6.8.4.2 The switch statement

Constraints

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

 

А дальше всё равно бессмысленное "растягивание" до 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А дальше всё равно бессмысленное "растягивание" до int... и впустую потраченное время и место во флэш.

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

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так.
Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.

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

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

 

А может существует какая-то опция, позволяющая отключать эту фичу?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

А может существует какая-то опция, позволяющая отключать эту фичу?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Понятно, спасибо :)

Оставим это как дань стандартам и одновременно лень производителей :)

 

Почти во всём при компиляции своего проекта уже разобрался.

Ещё вот беспокоят такие ворнинги:

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:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

void  lcdPrintText(PGM_P text, byte flags, signed char x, signed char y)
  switch(flags & 0xe0)
  {
...

Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит :crying: ... даже 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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Понятно, спасибо :)

Оставим это как дань стандартам и одновременно лень производителей :)

Стандарт не запрещает оптимизатору не расширять char до int если результат останется одинаковым. Или расширить, но потом все лишнее выкинуть.

 

то есть ругается на все PSTR() и на все PROGMEM.

Чего такого неправильного я там сделал? :07:

Это не вы, это они намудрили в компиляторе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

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

×
×
  • Создать...