|
Размещение "изменчивой" переменной в регистре, WinAVR |
|
|
|
May 21 2007, 02:35
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Как добиться, чтобы WinAVR разместил переменную в регистре и не оптимизировал ее? Т.е. есть маленькая программа, хотелось одну переменную поместить в регистр для ускорения доступа, причем изменение переменной возможно в прерывании. Если бы писал на асме, то просто разместил бы переменную в регистре по своему усмотрению и использовал бы всегда значение этого регистра, однако с WinAVR такой трюк не прошел  . Поясню: 1) Пишу: volatile unsigned char Timer; Результат: переменная размещена в ОЗУ (@ 0x0078), считывается каждый раз. Все логично. Дизасм: if (Timer > max) max = Timer; // внутри цикла Код LDS R24,0x0078 // в цикле CP R25,R24 // в цикле BRCC PC+0x03 // в цикле LDS R25,0x0078 // в цикле 2) Пишу: register unsigned char Timer asm("r15"); Результат: переменная размещена в регистре R15, но считывание оптимизировано. Тоже логично - компилятор "не знает", что она может менятся в прерывании. Дизасм: if (Timer > max) max = Timer; // внутри цикла Код MOV R19,R15 // за циклом ... CP R25,R19 // в цикле BRCC PC+0x02 // в цикле MOV R25,R19 // в цикле ... 3) Пишу оба модификатора: volatile register unsigned char Timer asm("r15"); Результат: практически тот же, что и в п.2. Компилятор "частично помнит" что переменная volatile и при копировании использует значение регистра R15, однако при сравнении в цикле все равно использует копию R15 в R19. В результате программа не работает как ожидалось. Дизасм: if (Timer > max) max = Timer; // внутри цикла Код MOV R19,R15 // за циклом ... CP R25,R19 // в цикле BRCC PC+0x02 // в цикле MOV R25,R15 // в цикле ... В результате пришлось использовать вариант 1. Расходы на чтение/запись ОЗУ в принципе небольшие - 1 команда LDS. Однако в цикле уже ощутимо, да и все же хочется иметь возможность "управлять" действиями компилятора.
--------------------
Common sense is not so common.
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 29)
|
May 21 2007, 09:35
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(mdmitry @ May 21 2007, 16:19)  Если в прерывании не используется более ничего, кроме указанной переменной, то прерывание описать как __attribute__ (naked), и руками сохранить sreg для корректности. Переменная оптимизируется в основной программе. При этом становится уже неважно как она меняется в прерывании. Конкретно в моем случае в прерывании как раз все в порядке.
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 02:43
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(mdmitry @ May 22 2007, 16:22)  Посмотрел свой код и в нем объявленные переменные по варианту 3 работают как надо. Используются несколько переменных в обработчике прерывания. Делалось это с Вашей целью: недопустить обращения к временным регистрам в прерывании для ускорения работы. В прерывании счетчик, маленький расчет и кое-какие присваивания. Я вроде понятно объяснил, но вижу что вы меня не поняли (или я недопонимаю). Повторюсь: переменная которую я привязываю к регистру R15 в обработчике прерывания изменяется правильно (меняется содержимое R15), однако код основной программы (ака функция main()) обращается с ней не как с volatile переменной - т.е. копирует ее в другой регистр (R19) и оперирует с ним в цикле, несмотря на то, что в любой момент времени R15 может измениться в прерывании. Цитата Посмотрите на опцию gcc -ffixed-reg Посмотрел. Из описания я понял что это средство для фиксации регистров для определенных целей (как например в winavr R1 == перманентный ноль), и недопущение их использования не по назначению. Имхо, это немного не то. По крайней мере ключики -ffixed-reg и -ffixed-reg-r15 не помогли  .
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 03:32
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Snaky @ May 23 2007, 09:43)  Посмотрел. Из описания я понял что это средство для фиксации регистров для определенных целей (как например в winavr R1 == перманентный ноль), и недопущение их использования не по назначению. Насколько мне не изменяет память, эти ключи являются директивой компилятору не использовать указанные регистры при кодогенерации. Т.е. эти залоченные регистры могут быть использованы пользователем по своему усмотрению (в ассемблерных программах, как правило) безопасно - т.е. без конфликтов с компилятором. Компилятору, ессно, в этом случае остается меньше регистров для реализации кодогенерации. Но в AVR регистров много, можно и поюзать несколько штук для себя без ущерба для качества кодогенерации. Второй момент - при использовании этих ключей надо и стандартную библиотеку перекомпилировать с этой же опцией. Если этого не сделать, то в случае, если компилятор вызывает функцию из библиотеки, то эта функция, будучи скомпилирована без залочки регистров, может использовать эти регистры и тем самым нарушить целостность работы программы.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
May 23 2007, 06:35
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(WHALE @ May 23 2007, 11:55)  Запретите в main во время работы с вашей переменной прерывание,где она может быть изменена. Я даже не знаю что ответить Давайте в третий раз попробую. Переменную я помечаю модификатором volatile потому что ее значение может измениться в обработчике прерываний, и программа должна это видеть. Для этого компилятору запрещено оптимизировать volatile переменные и положенно при любом обращении к переменной считывать заново ее значение. Проблема в том, что компилятор генерирует такой код, где в некоторых местах основной программы используется копия значения переменной, что неприемлемо и нарушает алгоритм работы программы. Более того, мне непонятно зачем он это вообще делает, если оптимизацией тут даже и не пахнет: копирует один регистр в другой и использует копию теми же командами работы с регистрами.
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 07:12
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(forever failure @ May 23 2007, 13:01)  io.h:21: warning: volatile register variables don't work as you might wish Может об этом и предупреждение ? Очень похоже что именно об этом. Странно что у меня Build succeeded with 0 Warnings... (WinAVR 20070122).
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 08:11
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Snaky @ May 23 2007, 11:12)  Очень похоже что именно об этом. Странно что у меня Build succeeded with 0 Warnings... (WinAVR 20070122). Скорее всего причина в том что нет ключа "-Wall" в коммандной строке компилятора. Анатолий.
|
|
|
|
|
May 23 2007, 08:20
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(aesok @ May 23 2007, 14:11)  Скорее всего причина в том что нет ключа "-Wall" в коммандной строке компилятора. Есть.
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 08:30
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Snaky @ May 23 2007, 12:20)  Есть. Почитайте про volatile <<global>> register здесь: http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00628.htmlВывод что volatile <<global>> register в GCC не работает. Почему у вас нет варинга не знаю. Анатолий.
|
|
|
|
|
May 23 2007, 08:32
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(ReAl @ May 23 2007, 14:27)  Попробуй к нему добавить ключ -Wextra C ключом -Wextra 1 warning: 'register' is not at beginning of declaration Поменял местами register и volatile: register volatile unsigned char Timer asm("r15"); Результат: Build succeeded with 0 Warnings... Генерируемый код от перестановки, как и следовало ожидать, не изменился.
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 08:47
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Snaky @ May 23 2007, 12:32)  C ключом -Wextra 1 warning: 'register' is not at beginning of declaration Поменял местами register и volatile: register volatile unsigned char Timer asm("r15"); Результат: Build succeeded with 0 Warnings... Генерируемый код от перестановки, как и следовало ожидать, не изменился. Попробуйте убрать volatile из определения Timer используйте -ffixed ИМХО, регистры лучше выбирать снизу (исключая r0,r1), то есть например asm("r2") А вобще, приведите минимальный "рабочий" код в котором будет ошибка, будет проще разобраться
|
|
|
|
|
May 23 2007, 08:50
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(mdmitry @ May 23 2007, 12:32)  В дополнение к замечаниям по регистрам: регистры r2-r15 отданы пользователю в WinAVR, о чем есть в справке по библиотеке замечание, поэтому перекомпилировать библиотеку нет необходимости. В avr-libc-user-manual а FAQ#13: "8.3.14 What registers are used by the C compiler?" описано как GCC использует регистры. Регистры которые можно безопастно использовать для регистровых переменных это r2..r7. Анатолий.
Сообщение отредактировал aesok - May 23 2007, 09:13
|
|
|
|
|
May 23 2007, 09:17
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(mdmitry @ May 23 2007, 14:32)  У Вас оптимизация по объему кода -Os. В моем случае была оптимизация по скорости -O2. Возможно это влияет на результат. Попробуйте поменять режим оптимизации. Не повлияло. Цитата(singlskv @ May 23 2007, 14:47)  Попробуйте убрать volatile из определения Timer используйте -ffixed ИМХО, регистры лучше выбирать снизу (исключая r0,r1), то есть например asm("r2") А вобще, приведите минимальный "рабочий" код в котором будет ошибка, будет проще разобраться -ffixed использую, без volatile лучше не стало. насчет порядка использования регистров - не согласен. где это сказано, что надо использовать снизу попорядку, а иначе будет неверный код? хотя все равно проверил - также копируется в R19. Сейчас выдерну из проекта рабочий кусочек - выложу. Цитата(aesok @ May 23 2007, 14:50)  В avr-libc-user-manual а FAQ#13: "8.3.14 What registers are used by the C compiler?" описано как GCC использует регистры. Регистры которые можно безопастно использовать для регистровых переменных это r2..r7. R2..R17
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 09:30
|

Начинающий профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 25-10-06
Из: СПб
Пользователь №: 21 648

|
>R2..R17 Из документации по Winavr: AVR Libc 1.4.5 FAQ 3. How to permanently bind a variable to a register? This can be done with register unsigned char counter asm("r3"); Typically, it should be possible to use r2 through r15 that way. Использую сейчас r2-r11. Посмотрел свой код и обнаружил следующее: 1. Если в основной программе элементарные действия (инкремент) с регистровыми данными (вариант 3 описания), то идет прямое использование регистров. 2. Действия более сложные (инкремент и работа с массивами), то начинает использоваться копирование в рабочие регистры WINAVR. IMHO: компилятор в зависимости от кода сам решает вопрос о использовании рабочих регистров и копировании данных. В моем коде без копирования все же не обойтись
Сообщение отредактировал mdmitry - May 23 2007, 09:32
--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
|
|
|
|
|
May 23 2007, 09:32
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Snaky @ May 23 2007, 13:17)  насчет порядка использования регистров - не согласен. где это сказано, что надо использовать снизу попорядку, а иначе будет неверный код? хотя все равно проверил - также копируется в R19. Сейчас выдерну из проекта рабочий кусочек - выложу. R2..R17 А вот потому что: • Function call conventions: Arguments - allocated left to right, r25 to r8. All arguments are aligned to start in even-numbered registers (odd-sized arguments, including char, have one free register above them). This allows making better use of the movw instruction on the enhanced core. Это из того же 8.3.14
|
|
|
|
|
May 23 2007, 09:45
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Выкладываю минимум где наблюдается. В коде помечено комментарием. Параметры вызова видны в makefile.
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 10:02
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Snaky @ May 23 2007, 13:45)  Выкладываю минимум где наблюдается. В коде помечено комментарием. Параметры вызова видны в makefile. Я же вам уже написал - GCC не поддерживает volatile register перемнные. Вы хотите доказать очевидный факт? Вот почему у вас нет варинга это да, странно. Анатолий.
|
|
|
|
|
May 23 2007, 10:06
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(aesok @ May 23 2007, 16:02)  Я же вам уже написал - GCC не поддерживает volatile register перемнные. Вы хотите доказать очевидный факт? Вот почему у вас нет варинга это да, странно. Да нет, не пытаюсь доказать, просто выкладываю по просьбе.
--------------------
Common sense is not so common.
|
|
|
|
|
May 23 2007, 10:15
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(aesok @ May 23 2007, 14:02)  Вот почему у вас нет варинга это да, странно. Посмотрел в WinAVR-20060421. demo.c Код register volatile unsigned char Timer asm("r15"); C:\work\avr>avr-gcc -Wall demo.c demo.c:1: warning: volatile register variables don't work as you might wish Кто нибудь проверте в WinAVR-2007.. (GCC 4.1.x) Анатолий.
Сообщение отредактировал aesok - May 23 2007, 10:17
|
|
|
|
|
May 23 2007, 10:40
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Snaky @ May 23 2007, 14:06)  Да нет, не пытаюсь доказать, просто выкладываю по просьбе. 1. зачем unsigned char tmp1, max; сделаны глобальными ??? при переносе их в main скомпилированный код уменьшается с 296 до 270 байт 2.циклы в прерывании не есть хорошо 3. убрал volatile, warning исчез вот код: Код 78: while(!Flag.Tick); +0000006E: 91800060 LDS R24,0x0060 Load direct from data space +00000070: FF80 SBRS R24,0 Skip if bit in register set +00000071: CFFC RJMP PC-0x0003 Relative jump 79: Flag.Tick = FALSE; +00000072: 91800060 LDS R24,0x0060 Load direct from data space +00000074: 7F8E ANDI R24,0xFE Logical AND with immediate +00000075: 93800060 STS 0x0060,R24 Store direct to data space 80: if (Timer > max) max = Timer; // <-- LOOK HERE! +00000077: 152F CP R18,R15 Compare +00000078: F408 BRCC PC+0x02 Branch if carry cleared +00000079: 2D2F MOV R18,R15 Copy register 81: tmp1--; +0000007A: 5091 SUBI R25,0x01 Subtract immediate 82: } +0000007B: F791 BRNE PC-0x0D Branch if not equal с R15 вроде как все в порядке P.S. Одно маленькое уточнение, версия компилятора у меня 20060421 Его Вам и порекомендую, особенно учитывая что проц у вас Tiny13 P.S.S Еще одно маленькое уточнение/вопрос А нужен ли вобще volatile, в том случае, если переменная регистровая и мы убедились в том что она дейсвительно разместилась в регистре (-ffixed) ???
|
|
|
|
|
May 24 2007, 02:22
|

Mute Beholder
  
Группа: Свой
Сообщений: 260
Регистрация: 4-04-07
Из: Третья планета от Солнца
Пользователь №: 26 754

|
Цитата(singlskv @ May 23 2007, 16:40)  1. зачем unsigned char tmp1, max; сделаны глобальными ???
3. убрал volatile, warning исчез с R15 вроде как все в порядке 1. Я же кусочек выдрал из всего проекта (повыкидывал другие функции) и не стал его вылизывать, переменные локализовывать. 3. Да и не было у меня warning-а изначально, про что сейчас речь и идет. И с R15 не в порядке было при любом объявлении. Цитата А нужен ли вобще volatile, в том случае, если переменная регистровая и мы убедились в том что она дейсвительно разместилась в регистре (-ffixed) ??? На этот вопрос я отвечал уже выше. Ладно, думаю тема исчерпана. Для себя сделал выводы, что лучше так не делать ибо gcc это не приветствует  , хотя, гад, и предупреждать отказывается. Ну и, естественно, новое не всегда лучше старого.
--------------------
Common sense is not so common.
|
|
|
|
|
May 24 2007, 08:55
|

Начинающий профессионал
    
Группа: Свой
Сообщений: 1 215
Регистрация: 25-10-06
Из: СПб
Пользователь №: 21 648

|
>хотя, гад, и предупреждать отказывается. Ну и, естественно, новое не всегда лучше старого. При опции -Wall включены не все предупреждения, в частности, упомянутое ранее. Это описано в документации к gcc. Ваш тест запустил под WINAVR-2007. Действительно есть копирование. Предупреждения нет, так как в опциях компилятора не указано его генерировать. В своем проекте на пробу включил  предупреждения, так сразу 5 штук получил  .
--------------------
Наука изощряет ум; ученье вострит память. Козьма Прутков
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|