|
Что это фича или баг?, avr-gcc 4.1.2 WinAvr 20070525 |
|
|
|
Dec 1 2008, 07:46
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Столкнулся с очень интересным эффектом. Есть два кода, с моей точки зрения, которые должны работать идентично. Но первый случай не работает, второй работает безупречно. Код tty ? (UDR1 = data) : (UDR0 = data);
disasm code: +000023EA: 91E010C5 LDS R30,0x10C5 Load direct from data space +000023EC: 91F010C6 LDS R31,0x10C6 Load direct from data space +000023EE: 0FE9 ADD R30,R25 Add without carry +000023EF: 1DF1 ADC R31,R1 Add with carry +000023F0: 8180 LDD R24,Z+0 Load indirect with
+000023F1: 938000CE STS 0x00CE,R24 Store direct to data space +000023F3: 918000CE LDS R24,0x00CE Load direct from data space Код if (tty > 0) UDR1 = data; else UDR0 = data;
disasm come: +000023E8: 91E010C5 LDS R30,0x10C5 Load direct from data space +000023EA: 91F010C6 LDS R31,0x10C6 Load direct from data space +000023EC: 0FE9 ADD R30,R25 Add without carry +000023ED: 1DF1 ADC R31,R1 Add with carry +000023EE: 8180 LDD R24,Z+0 Load indirect with
+000023EF: 938000CE STS 0x00CE,R24 Store direct to data space При дизасме в первом случае, вижу на мой взгляд абсолютно бесполезную строчку Код LDS R24,0x00CE Load direct from data space но которая(мне кажется) ломает функционал uart начисто (проявляется следующим образом: из регистра приёмника вычитывается байт, который был вычитан до этого. То есть вижу иногда в общем пакете по два одинаковых байта). Кто-нибудь может пояснить значение этой строчки??? Рботающий и неработающий коды отличаются только ей. И чем собственно коснтрукция ? : ; для компилятора отличается от if else?
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 22)
|
Dec 1 2008, 08:21
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(forever failure @ Dec 1 2008, 11:00)  В первом случае в условии проверка на ненулевое значение, а во втором - на положительное. Может в этом разница ? Да собственно говоря в if можно и на равенство 0 проверять, асм будет такой же (постоянство радует  ). Меня просто напрягает, свободное обращение с регистром уарта UDR. Ведь и запись и чтение этого регистра запускают определённые физические процессы в уарте. А тут захотелось ему, он взял и вычитал значение из этого регистра в R24. Неприятное явление. ЗЫ В IAR и тот и другой случаи работают нормально. Цитата(Непомнящий Евгений @ Dec 1 2008, 11:09)  ? : возвращает результат, if else - нет. Больше вроде бы ничем.
Собственно в строчке LDS R24,0x00CE , насколько я понял, и возвращается результат операции UDR1 = data. 0x00CE это адрес UDR регистра, я не понимаю как это строчка может сообщать о результате операции.  Цитата(_Pasha @ Dec 1 2008, 11:10)  Нескромный вопрос: tty у Вас volatile? Просто не могу себе представить ситуацию, когда селектором устройств является не volatile переменная... К моему стыду действительно не volatile. Эта переменная часть структуры, описывающей уарт Код typedef struct { /** \brief tty - One of the defines UART_CHANNEL_0 or UART_CHANNEL_1. Which defines a number of UART. */ uint8_t tty; ...... ..... ..... } UartDescriptor_t;
|
|
|
|
|
Dec 1 2008, 09:03
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(xelax @ Dec 1 2008, 12:21)  я не понимаю как это строчка может сообщать о результате операции.  Код tty ? (UDR1 = data) : (UDR0 = data); Выполняется (UDR1 = data) и результат выражения - это значение UDR1, которое надо предварительно прочитать, из-за того, что оно описано volatile. А то, что результат больше никому не нужен - это уже совсем другая история. Мораль: хочешь, чтобы оно просто записало в порт, так и скажи компилеру, а проктология - не компьютерная наука.  Так что это фича. И лишнее доказательство того, что компилер не может оградить программиста от ошибок.
|
|
|
|
|
Dec 1 2008, 09:12
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(Непомнящий Евгений @ Dec 1 2008, 11:23)  И еще вопросик - я не въеду, где в приведенном вами дизасме происходит сравнение tty c 0? Или вы привели только кусочек? Да это кусок был... вот более полная версия  , с сравнением : Код 7c: 90 91 00 00 lds r25, 0x0000 80: 80 91 00 00 lds r24, 0x0000 84: 89 17 cp r24, r25 86: 01 f0 breq .+0 ; 88: e0 91 00 00 lds r30, 0x0000 8c: f0 91 00 00 lds r31, 0x0000 90: e9 0f add r30, r25 92: f1 1d adc r31, r1 94: 80 81 ld r24, Z 96: 80 93 ce 00 sts 0x00CE, r24 Это дизасм библиотечки, так что нет всех адресов  Ок. В принципе понял свою ошибку.
|
|
|
|
|
Dec 1 2008, 09:28
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Непомнящий Евгений @ Dec 1 2008, 13:15)  Т.е. получается что на один шаг оптимизатор срабатывает (выкидывая чтение в данном случае), а вот на два шага - в случае tty ? UDR1 = data : UDR0 = data - уже нет... Вот автор сказал, что ИАР выкинул лишнее чтение, а мне грустно: если компилер таким изящным манером исправил логическую ошибку программиста (согласитесь, ошибка ведь была), то где гарантия, что не бывает обратных ситуаций, т.е. абсолютно правильные с точки зрения логики действия программера цензурируются оптимизатором и это рождает ошибку. В общем, я все больше начинаю понимать gcc
|
|
|
|
|
Dec 1 2008, 09:54
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(_Pasha @ Dec 1 2008, 12:28)  Вот автор сказал, что ИАР выкинул лишнее чтение, а мне грустно: если компилер таким изящным манером исправил логическую ошибку программиста (согласитесь, ошибка ведь была), то где гарантия, что не бывает обратных ситуаций, т.е. абсолютно правильные с точки зрения логики действия программера цензурируются оптимизатором и это рождает ошибку. В общем, я все больше начинаю понимать gcc  А собственно компилятор ошибок и не исправляет, если уж на то пошло. А скорее всего это строчки убираются в процессе оптимизации. Так что я бы не стал обвинять ни iar ни gcc. Просто как показала практика у iar оптимизация тщательней делается
|
|
|
|
|
Dec 1 2008, 10:30
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(_Pasha @ Dec 1 2008, 12:28)  Вот автор сказал, что ИАР выкинул лишнее чтение... В общем, я все больше начинаю понимать gcc  Я собственно имел в виду, что обе строчки Код UDR1 = data;
tty ? UDR1 = data : UDR0 = data; Должны приводить к вычитыванию UDR1... Только в первом случае это чтение оптимизится, а во втором нет...
|
|
|
|
|
Dec 1 2008, 10:44
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(gotty @ Dec 1 2008, 13:33)  Никакая оптимизация не должна выкидывать чтение volatile переменной. Ну тогда получается, что конструкции вида Код РЕГИСТР = значение; должны приводить к записи регистра и его последующему чтению. Т.е. запись регистра без чтения на С вообще невозможна
|
|
|
|
|
Dec 1 2008, 10:51
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(gotty @ Dec 1 2008, 13:44)  Никакая оптимизация не должна выкидывать чтение volatile переменной. Зачем доводить идею до абсурда. Цитата(Непомнящий Евгений @ Dec 1 2008, 13:44)  Код РЕГИСТР = значение; должны приводить к записи регистра и его последующему чтению. Т.е. запись регистра без чтения на С вообще невозможна  А в случае с уартом в avr, будет полная неразбериха в линии. И ещё смысл делать read для write-only регистров
|
|
|
|
|
Dec 1 2008, 11:02
|
Знающий
   
Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045

|
Цитата(Непомнящий Евгений @ Dec 1 2008, 12:44)  Ну тогда получается, что конструкции вида Код РЕГИСТР = значение; должны приводить к записи регистра и его последующему чтению. Т.е. запись регистра без чтения на С вообще невозможна  Надо различать конструкции. Оператор ?: подразумевает дальнейшее использование возвращаемого значения, а РЕГИСТР = значение - допускает.
|
|
|
|
|
Dec 1 2008, 11:51
|

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

|
Цитата(gotty @ Dec 1 2008, 16:02)  Надо различать конструкции. Оператор ?: подразумевает дальнейшее использование возвращаемого значения, а РЕГИСТР = значение - допускает. Тогда по идее конструкция Код a = b ? func1() : func2(); должна сначала вызвать обе функции?
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Dec 1 2008, 12:07
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(AHTOXA @ Dec 1 2008, 15:51)  должна сначала вызвать обе функции?  А это тут при чем?  По теме Код (void) (tty ? UDR1 = data : UDR0 = data); Можете проверить, насколько это кошерно ? ЗЫ некошерно, уже проверил.  ЗЫ^2 последний WinAVR-20081118rc2 Код #include<avr/io.h> volatile uint8_t UR0,UR1,tty,data;
int main(void) { while(1) { tty ? UR1=data : UR0=data; } return(0); } ../test.c:9: error: lvalue required as left operand of assignment не оставляет шанса для кривотолков.
|
|
|
|
|
Dec 1 2008, 15:12
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(_Pasha @ Dec 1 2008, 16:38)  Понятно. Не догнал...  Господа, внимание! Мой путь через ж%пу к звездам: исходные те же Код int main(void) { while(1) { tty ? (void)(UR1=data) : (void)(UR0=data); } return(0); } ЛыстынГ: Код int main(void) { while(1) { tty ? (void)(UR1=data) : (void)(UR0=data); 6c: 80 91 02 01 lds r24, 0x0102 70: 88 23 and r24, r24 72: 29 f0 breq .+10 ; 0x7e <main+0x12> 74: 80 91 01 01 lds r24, 0x0101 78: 80 93 03 01 sts 0x0103, r24 7c: f7 cf rjmp .-18 ; 0x6c <main> 7e: 80 91 01 01 lds r24, 0x0101 82: 80 93 00 01 sts 0x0100, r24 86: f2 cf rjmp .-28 ; 0x6c <main>
00000088 <_exit>: 88: f8 94 cli
0000008a <__stop_program>: 8a: ff cf rjmp .-2 ; 0x8a <__stop_progr такшта... надо было хоть раз голову включить.
|
|
|
|
|
Dec 11 2008, 09:13
|

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

|
Цитата(_Pasha @ Dec 1 2008, 17:12)  Господа, внимание! Мой путь через ж%пу к звездам: исходные те же Код int main(void) { while(1) { tty ? (void)(UR1=data) : (void)(UR0=data); } return(0); } Мдя... Тогда уж лучше, если так хочется поизвращаться, переходить на С++ (заодно и с атомарными фрагментами кода будет легче через класс критической секции). В С++ несколько унифицировали понятие lvalue и он допускает не только возможное в С Код variable = (flag ? function1 : function2)(argument1, argument2); вместо Код variable = (flag ? function1(argument1, argument2) : function2(argument1, argument2) ); но и такое: Код #include <avr/io.h>
void foo(uint8_t flag, uint8_t data) { (flag ? PORTB : PORTC) = data; } Код .global _Z3foohh .type _Z3foohh, @function _Z3foohh: /* prologue: frame size=0 */ /* prologue end (size=0) */ tst r24 breq .L2 out 37-0x20,r22 ret .L2: out 40-0x20,r22 ret Кстати, это только более простая и логичная запись допустимого в С Код *(flag ? &PORTB : &PORTC) = data; с шансами на упрощение работы оптимизатора - ему теперь не надо будет в "сыром" коде взятые по флагу указатели сводить назад в константные out, что он может и не потянуть. А пример выше с функциями - это по сути пример с указателями, поэтому и в чистом С катит.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|