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

Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Nov 26 2008, 20:45
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 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 вполне бы прошло.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Nov 26 2008, 21:35
|

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

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

Любитель
    
Группа: Свой
Сообщений: 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-ти бит  ... даже 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... и впустую потраченное время и место во флэш.
|
|
|
|
|
Nov 27 2008, 04:14
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(sonycman @ Nov 27 2008, 01:02)  Но смысла в нём мало - всё равно всё тупо "растягивается" до 16-ти бит  ... даже 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
|
|
|
|
|
Nov 27 2008, 08:51
|
Знающий
   
Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045

|
Цитата(Rst7 @ Nov 27 2008, 09:56)  Аналогично есть вопросы к выражению. Все операнды и результат 8 бит, а в середине выражение вычисляется через 16 бит. Чтото не так. Это называется Integer promotion - приведение char к int в промежуточных вычислениях, прописано в стандарте.
|
|
|
|
|
Nov 27 2008, 09:24
|
Знающий
   
Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045

|
Цитата(Rst7 @ Nov 27 2008, 11:08)  Ссылку. Чтото я совсем потерялся. ISO/IEC 9899:19995.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.
|
|
|
|
|
Nov 27 2008, 09:45
|

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

|
Цитата(sonycman @ Nov 27 2008, 12:28)  Но неужели слепое следование стандартам больших машин - это абсолютно правильно и на AVR? Следование стандартам ВСЕГДА правильно, а вот то, что int на восьмибитовике 1бит - вот это уже НЕ ПРАВИЛЬНОЕ (хотя не противоречащее стандарту) решение принятое когда-то производителями восьмибитовых компиляторов  , полагаю для тупой совместимости с массовыми на тот момент 16bit-овиками, дабы _бездумно_  портировать исходники с 16bit интами. Если int действительно имел максимально естественую для 8bit контроллера разрядность 8bit, то и проблем c этитм не было-бы, как их нет не 16/32bit платформах. Цитата А может существует какая-то опция, позволяющая отключать эту фичу? Гипотетически изменить размерность int в хидерах на 8bit и пресобрать все, включая библиотеки. Если авторы компилятора все делали правильно, то должно получиться. А вообще пора завязывать с 8bit
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Nov 27 2008, 10:04
|

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

|
Цитата(zltigo @ Nov 27 2008, 13:45)  Следование стандартам ВСЕГДА правильно, а вот то, что 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. Чего такого неправильного я там сделал?
|
|
|
|
|
Nov 27 2008, 11:29
|

Местный
  
Группа: Участник
Сообщений: 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-ти бит  ... даже 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
|
|
|
|
|
Nov 27 2008, 11:35
|

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

|
Цитата(sonycman @ Nov 27 2008, 12:04)  Понятно, спасибо Оставим это как дань стандартам и одновременно лень производителей  Стандарт не запрещает оптимизатору не расширять char до int если результат останется одинаковым. Или расширить, но потом все лишнее выкинуть. Цитата(sonycman @ Nov 27 2008, 12:04)  то есть ругается на все PSTR() и на все PROGMEM. Чего такого неправильного я там сделал?  Это не вы, это они намудрили в компиляторе.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|