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

Что это фича или баг?

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

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? :07:

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


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

В первом случае в условии проверка на ненулевое значение, а во втором - на положительное. Может в этом разница ?

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


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

И чем собственно коснтрукция ? : ; для компилятора отличается от if else? :07:

 

? : возвращает результат, if else - нет. Больше вроде бы ничем.

 

Собственно в строчке LDS R24,0x00CE , насколько я понял, и возвращается результат операции UDR1 = data.

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


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

но которая(мне кажется) ломает функционал uart начисто

Нескромный вопрос: tty у Вас volatile? Просто не могу себе представить ситуацию, когда селектором устройств является не volatile переменная...

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


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

В первом случае в условии проверка на ненулевое значение, а во втором - на положительное. Может в этом разница ?

 

Да собственно говоря в if можно и на равенство 0 проверять, асм будет такой же (постоянство радует :) ).

 

Меня просто напрягает, свободное обращение с регистром уарта UDR. Ведь и запись и чтение этого регистра запускают определённые физические процессы в уарте. А тут захотелось ему, он взял и вычитал значение из этого регистра в R24. Неприятное явление.

 

ЗЫ В IAR и тот и другой случаи работают нормально.

 

? : возвращает результат, if else - нет. Больше вроде бы ничем.

 

Собственно в строчке LDS R24,0x00CE , насколько я понял, и возвращается результат операции UDR1 = data.

 

 

0x00CE это адрес UDR регистра, я не понимаю как это строчка может сообщать о результате операции. :07:

 

Нескромный вопрос: 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;

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


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

0x00CE это адрес UDR регистра, я не понимаю как это строчка может сообщать о результате операции. :07:

 

Ну вероятно GGC полагает, что результатом операции a=b является значение "a" после операции присваивания. А "а" у вас - UDR1 - вероятно помеченный volatile или еще как-то. Вот его значение и вычитывается...

 

И еще вопросик - я не въеду, где в приведенном вами дизасме происходит сравнение tty c 0? Или вы привели только кусочек?

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


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

я не понимаю как это строчка может сообщать о результате операции. :07:

 

tty ? (UDR1 = data) : (UDR0 = data);

Выполняется (UDR1 = data) и результат выражения - это значение UDR1, которое надо предварительно прочитать, из-за того, что оно описано volatile. А то, что результат больше никому не нужен - это уже совсем другая история.

 

Мораль: хочешь, чтобы оно просто записало в порт, так и скажи компилеру, а проктология - не компьютерная наука. :)

Так что это фича. И лишнее доказательство того, что компилер не может оградить программиста от ошибок.

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


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

И еще вопросик - я не въеду, где в приведенном вами дизасме происходит сравнение 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

 

Это дизасм библиотечки, так что нет всех адресов :laughing:

 

Ок. В принципе понял свою ошибку.

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


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

Выполняется (UDR1 = data) и результат выражения - это значение UDR1, которое надо предварительно прочитать, из-за того, что оно описано volatile. А то, что результат больше никому не нужен - это уже совсем другая история.

 

Кстати, по-идее даже просто запись UDR1=data должна приводить к вычитыванию UDR1 :)

 

Т.е. получается что на один шаг оптимизатор срабатывает (выкидывая чтение в данном случае), а вот на два шага - в случае tty ? UDR1 = data : UDR0 = data - уже нет...

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


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

Т.е. получается что на один шаг оптимизатор срабатывает (выкидывая чтение в данном случае), а вот на два шага - в случае tty ? UDR1 = data : UDR0 = data - уже нет...

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

В общем, я все больше начинаю понимать gcc :)

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


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

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

В общем, я все больше начинаю понимать gcc :)

 

А собственно компилятор ошибок и не исправляет, если уж на то пошло. А скорее всего это строчки убираются в процессе оптимизации. Так что я бы не стал обвинять ни iar ни gcc.

 

Просто как показала практика у iar оптимизация тщательней делается :)

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


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

Вот автор сказал, что ИАР выкинул лишнее чтение...

В общем, я все больше начинаю понимать gcc :)

 

Я собственно имел в виду, что обе строчки

UDR1 = data;

tty ? UDR1 = data : UDR0 = data;

 

Должны приводить к вычитыванию UDR1...

 

Только в первом случае это чтение оптимизится, а во втором нет...

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


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

А собственно компилятор ошибок и не исправляет, если уж на то пошло. А скорее всего это строчки убираются в процессе оптимизации. Так что я бы не стал обвинять ни iar ни gcc.

 

Просто как показала практика у iar оптимизация тщательней делается :)

Никакая оптимизация не должна выкидывать чтение volatile переменной. Обсуждение было в теме http://electronix.ru/forum/index.php?showtopic=54275

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


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

Никакая оптимизация не должна выкидывать чтение volatile переменной.

Ну тогда получается, что конструкции вида

РЕГИСТР = значение;

должны приводить к записи регистра и его последующему чтению. Т.е. запись регистра без чтения на С вообще невозможна :)

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


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

Никакая оптимизация не должна выкидывать чтение volatile переменной.

 

Зачем доводить идею до абсурда.

 

РЕГИСТР = значение;

должны приводить к записи регистра и его последующему чтению. Т.е. запись регистра без чтения на С вообще невозможна :)

 

А в случае с уартом в avr, будет полная неразбериха в линии. :)

И ещё смысл делать read для write-only регистров :(

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


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

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

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

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

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

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

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

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

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

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