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

непонятное поведение IAR при генерации кода для STM32

Добрый день.

Имеем STM32L1 семейства.

Столкнулся со странностью оптимизатора IAR, или что то недопонимаю сам.

Имеем следующие структуры

typedef __packed struct {
  uint32_t ID;
  uint16_t VERS;
  uint32_t UID;
  uint32_t DeviceType;
  uint32_t DeviceNumber;
  uint32_t CreateTime;
  uint32_t ExpireTime;
} tagExpireKey;

typedef __packed struct {
  uint8_t  G[10];
} tagExpireKeyCrypt;

typedef __packed struct {
  tagExpireKey       Data;
  tagExpireKeyCrypt  Crypt;
  uint32_t           ControlCRC;
} tagExpireKeyDevice;

глобальную переменную этого типа

tagExpireKeyDevice License;

Переменная License загружается выше по тексту программы.
Данные в полях всех структур корректные.
Далее в тексте программы выполняются 2 проверки:
 

uint32_t CurTime;
CurTime = FRTC.GetSeconds();

for (;;) {
  ...
  if (CurTime < LicenseCUR.Data.CreateTime) break;
  if (CurTime > LicenseCUR.Data.ExpireTime) break;
  ...
}

  что в asm выглядит следующим образом

 

  \                     ??DataTable1_2:
   \   00000000   0x........         DC32     LicenseCUR
   \                     ??DataTable1_4:
   \   00000000   0x........         DC32     FRTC
   ...
   \   00000004   0x....             LDR.N    R5,??DataTable1_2
   ...
     83              CurTime = FRTC.GetSeconds();
   \   00000020   0x....             LDR.N    R6,??DataTable1_4
   \   00000028   0x4630             MOV      R0,R6
   \   0000002A   0x.... 0x....      BL       _ZN4TRTC10GetSecondsEv
   ...
     95              if (CurTime < LicenseCUR.Data.CreateTime) break;
   \   0000002E   0xF8D5 0x1012      LDR      R1,[R5, #+18]
   \   00000032   0x4288             CMP      R0,R1
   \   00000034   0xBF24             ITT      CS
   \   00000036   0xF8D5 0x1016      LDRCS    R1,[R5, #+22]
   \   0000003A   0x4281             CMPCS    R1,R0
     99              if (CurTime > LicenseCUR.Data.ExpireTime) break;
   \   0000003C   0xD303             BCC.N    ??CheckCurLicense_0

  проходя в отладчике этот кусок кода, увидел что при первом сравнении в R1 при выполнении LDR R1,[R5, #+18]
  была выполнена загрузка значения поля LicenseCUR.Data.CreateTime и условие программы было выполнено,
  а вот при выполнении LDRCS  R1,[R5, #+22]  значение поля LicenseCUR.Data.ExpireTime в R1 не загружается.

  если изменить текст программы как

asm("nop");
if (CurTime < LicenseCUR.Data.CreateTime) break;
    
asm("nop");
if (CurTime > LicenseCUR.Data.ExpireTime) break;

  получаем следующий корректно работающий листинг:

 

   94              asm("nop");
   \   0000002E   0xBF00             nop
     95              if (CurTime < LicenseCUR.Data.CreateTime) break;
   \   00000030   0xF8D5 0x1012      LDR      R1,[R5, #+18]
   \   00000034   0x4288             CMP      R0,R1
   \   00000036   0xD308             BCC.N    ??CheckCurLicense_0
     96              
     97              asm("nop");
   \   00000038   0xBF00             nop
     98              // время лицензии закончилось
     99              if (CurTime > LicenseCUR.Data.ExpireTime) break;
   \   0000003A   0xF8D5 0x1016      LDR      R1,[R5, #+22]
   \   0000003E   0x4281             CMP      R1,R0
   \   00000040   0xD303             BCC.N    ??CheckCurLicense_0

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

  LDR      R1,[R5, #+18]
  LDR      R1,[R5, #+22]

  в чем моя, или не моя, ошибка?
  то что инструкция <ITT CS> и далее <LDRCS> не верно работают с упакованными структурами или что то другое?

  спасибо.

 

p.s. Если модераторы посчитают необходимым - можно перенести тему в ARM форум. Не стал дублировать сообщения.

Изменено пользователем Zeal0t

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


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

51 минуту назад, Zeal0t сказал:

 


  \                     ??DataTable1_2:
   \   00000000   0x........         DC32     LicenseCUR
   \                     ??DataTable1_4:
   \   00000000   0x........         DC32     FRTC
   ...
   \   00000004   0x....             LDR.N    R5,??DataTable1_2
   ...
     83              CurTime = FRTC.GetSeconds();
   \   00000020   0x....             LDR.N    R6,??DataTable1_4
   \   00000028   0x4630             MOV      R0,R6
   \   0000002A   0x.... 0x....      BL       _ZN4TRTC10GetSecondsEv
   ...
     95              if (CurTime < LicenseCUR.Data.CreateTime) break;
   \   0000002E   0xF8D5 0x1012      LDR      R1,[R5, #+18]
   \   00000032   0x4288             CMP      R0,R1
   \   00000034   0xBF24             ITT      CS
   \   00000036   0xF8D5 0x1016      LDRCS    R1,[R5, #+22]
   \   0000003A   0x4281             CMPCS    R1,R0
     99              if (CurTime > LicenseCUR.Data.ExpireTime) break;
   \   0000003C   0xD303             BCC.N    ??CheckCurLicense_0

  проходя в отладчике этот кусок кода, увидел что при первом сравнении в R1 при выполнении LDR R1,[R5, #+18]
  была выполнена загрузка значения поля LicenseCUR.Data.CreateTime и условие программы было выполнено,
  а вот при выполнении LDRCS  R1,[R5, #+22]  значение поля LicenseCUR.Data.ExpireTime в R1 не загружается.

Что значит "условие программы было выполнено"? Флаг C после команды "CMP R0,R1" чему равен?

Раз "значение поля LicenseCUR.Data.ExpireTime в R1 не загружается", то очевидно что флаг C в этот момент был ==0. Тогда что Вас удивляет?

Цитата

  в чем моя, или не моя, ошибка?

Видимо в том, что Вы не знаете как работают префиксы условного выполнения команд в ARM. Прочитайте мануал по системе команд Cortex-M.

52 минуты назад, Zeal0t сказал:

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

NOP не сбрасывает никаких "очередей". После вставки лишних команд оптимизатор решил, что использовать условные переходы выгоднее, чем префиксы условного выполнения команд. Только и всего.

Совет: Если отлаживаете по шагам, то отключайте оптимизацию. Или изучайте ассемблер и отлаживайте по ассемблерному коду.

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


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

2 hours ago, jcxz said:

Что значит "условие программы было выполнено"? Флаг C после команды "CMP R0,R1" чему равен?

Раз "значение поля LicenseCUR.Data.ExpireTime в R1 не загружается", то очевидно что флаг C в этот момент был ==0. Тогда что Вас удивляет?

Видимо в том, что Вы не знаете как работают префиксы условного выполнения команд в ARM. Прочитайте мануал по системе команд Cortex-M.

NOP не сбрасывает никаких "очередей". После вставки лишних команд оптимизатор решил, что использовать условные переходы выгоднее, чем префиксы условного выполнения команд. Только и всего.

Совет: Если отлаживаете по шагам, то отключайте оптимизацию. Или изучайте ассемблер и отлаживайте по ассемблерному коду.

Да было бы там что отлаживать - 2 банальных условия.

В asm листинги полез уж после того, как программа не стала работать так как задумывалось.

Проблема не в IAR, оптимизации и asm инструкциях. На модуле часов села батарея. Во время очередного прогона часы получили время 0. А я не обратил на это внимания, т.к. был уверен в том, что там все нормально. Уже в процессе разбирательств устройство успело синхронизировать время с актуальным на данный момент и корректно отработал вариант с nop вставками.

Поэтому все так и получилось.

Спасибо. Проблема решена.

 

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


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

10 минут назад, Zeal0t сказал:

На модуле часов села батарея. Во время очередного прогона часы получили время 0. А я не обратил на это внимания, т.к. был уверен в том, что там все нормально.

Там не нормально, потому что в RTC модулях обычно бывают флаги "данные в часах валидны". Когда батарейка садится этот флаг сбрасывается. Естественно при каждом чтении часов нужно смотреть и этот флаг. Раз вы его не смотрите, значит и там тоже не нормально.

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


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

6 minutes ago, jcxz said:

Там не нормально, потому что в RTC модулях обычно бывают флаги "данные в часах валидны". Когда батарейка садится этот флаг сбрасывается. Естественно при каждом чтении часов нужно смотреть и этот флаг. Раз вы его не смотрите, значит и там тоже не нормально.

в DS1388 тоже есть такой флаг? подскажите, если не трудно )

не нужно придираться к людям, даже если сам гуру - все мы с чего то начинали )

Изменено пользователем Zeal0t

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


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

3 минуты назад, Zeal0t сказал:

в DS1388 тоже есть такой флаг? подскажите, если не трудно )

Даже если отдельного бита нет, то следует считанное значение сначала проверять на допустимость (на диапазон). Это и есть - проверка валидности. И только потом его как то использовать.

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


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

On 1/5/2019 at 6:12 PM, Zeal0t said:

в DS1388 тоже есть такой флаг? подскажите, если не трудно ) . . .

Bit 7: Oscillator Stop Flag (OSF)

такие флаги есть в каждом уважающем себя RTC. Он устанавливается при первоначальном включении, а также при зафиксированных внутри RTC сбоях (например провал по питанию при заниженном напряжение резервной батареи).

 

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


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

2 минуты назад, k155la3 сказал:

Bit 7: Oscillator Stop Flag (OSF)

Вам, коллега, надо мзду брать за чтение даташитов за лентяев. :biggrin:

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


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

3 minutes ago, jcxz said:

Вам, коллега, надо мзду брать за чтение даташитов за лентяев. :biggrin:

Не, не чтение. Ctrl<F> Операция, которую я "вырабатывал" годАми тренировок :)

На "чтение" ТС у меня может запросить прайс.

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


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

20 hours ago, k155la3 said:

Не, не чтение. Ctrl<F> Операция, которую я "вырабатывал" годАми тренировок :)

На "чтение" ТС у меня может запросить прайс.

Спасибо за предложение. Если будет необходимо - обязательно обращусь.

 

А теперь вопрос не по теме топика.

Для jcxz и K155ЛА3.

Вы когда делаете какой то новый модуль, или наращиваете функциональность существующего - вот прям вот сразу так все обвешиваете тестами, проверками и прочими защитами? Или все же изначально делается какой более-менее работающий макет и потом, если он взлетел и устраивает, то уже доделываете для  него все что по хорошему нужно и необходимо?

Или может уважаемые пишут все сразу что может понадобится и, естественно конечно, без ошибок и ляпов?

Ну извините раз так. Я почему то считал, что различные форумы и группы именно для этого и созданы - общение и обсуждение.

Или может это сейчас стиль общения такой - ткнуть мордой и сказать RTFM? Ну будем тогда знать.

Извините что отнял ваше драгоценное время.

 

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


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

1 час назад, Zeal0t сказал:

Вы когда делаете какой то новый модуль, или наращиваете функциональность существующего - вот прям вот сразу так все обвешиваете тестами, проверками и прочими защитами?

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

1 час назад, Zeal0t сказал:

Или может это сейчас стиль общения такой - ткнуть мордой и сказать RTFM? Ну будем тогда знать.

Извините что отнял ваше драгоценное время.

PS: Какая-то странная реакция на простое замечание....   Извините что потревожили вашу корону. :king: В мыслях такого не было.  :hi:

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


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

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

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

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

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

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

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

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

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

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