|
|
  |
Winavr сокращает функцию, если переменные размещены в регистрах |
|
|
|
Jun 11 2008, 15:41
|
Участник

Группа: Свой
Сообщений: 69
Регистрация: 4-02-08
Из: Винница
Пользователь №: 34 732

|
Цитата(Сергей Борщ @ Jun 11 2008, 17:54)  Непонятен вопрос. Вы выделяете 4 регистра в области SFR под свою переменную в уме, а обращаетесь к ним через _SFR_IO_ADR() по конкретным адресам. А вы уверены, что вам нужна там 4-байтовая переменная? Я имел ввиду свойство макроса _SFR_IO16(io_addr) , при помощи которого получается 16-битная переменная, вроде как int. Выполнение арифметических операций при этом не должно вызывать трудностей. Например: Код #define var _SFR_IO16(0x09) ... var++; ... Однако, если я к переменной int буду обращаться как к отдельным байтам, то у меня сразу могут возникнуть некоторые трудности. Поправьте меня, если я заблуждаюсь.
|
|
|
|
|
Jun 11 2008, 16:48
|

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

|
Цитата(A.l.e.x. @ Jun 11 2008, 18:41)  Я имел ввиду свойство макроса _SFR_IO16(io_addr) , при помощи которого получается 16-битная переменная, вроде как int. А, теперь понял. Идем в avr/io.h, ищем, где и как определен макрос _SFR_IO16(). Находим его в avr/sfr_defs.h: Код #define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr)) #define _MMIO_WORD(mem_addr) (*(volatile uint16_t *)(mem_addr)) #define _MMIO_DWORD(mem_addr) (*(volatile uint32_t *)(mem_addr))
#define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + 0x20) #define _SFR_IO16(io_addr) _MMIO_WORD((io_addr) + 0x20) Дописываем в своем файле Код #define _SFR_IO32(io_addr) _MMIO_DWORD((io_addr) + 0x20) и радуемся. Цитата(A.l.e.x. @ Jun 11 2008, 18:41)  Однако, если я к переменной int буду обращаться как к отдельным байтам, то у меня сразу могут возникнуть некоторые трудности. Поправьте меня, если я заблуждаюсь. Какие трудности? При побайтовом доступе запись в программе на С усложняется, только и всего. Или вы имели ввиду другие трудности?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 11 2008, 18:48
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(AHTOXA @ Jun 11 2008, 21:44)  Это без volatile. Да, похоже единственный правильный вариант для gcc 4.x.x без раздувания кода и данных это с асм вставкой: Код #include <avr/io.h> #include <avr/interrupt.h>
///////////////////////////////////////////////////////////////////////////////////////////////// volatile register unsigned long count_ms asm("r4"); register unsigned char flag_ms asm("r8");
static void timer_ms(unsigned long value) { count_ms = value; flag_ms = 0; __asm__ __volatile__("and r8,r8\n\t"\ "breq .-4"); } ///////////////////////////////////////////////////////////////////////////////////////////////// ISR(TIM0_COMPA_vect) { if(count_ms){--count_ms;} else{flag_ms = 1;} } ///////////////////////////////////////////////////////////////////////////////////////////////// int main(void) { TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(0<<COM0B1)|(0<<COM0B0)|(1<<WGM01)|(0<<WGM00); //CTC TCCR0B = (0<<FOC0A)|(0<<FOC0B)|(0<<WGM02)|(0<<CS02)|(1<<CS01)|(0<<CS00); // FCPU/8 OCR0A = 149; TIMSK0 = (0<<OCIE0B)|(1<<OCIE0A)|(0<<TOIE0); sei(); while(1){ timer_ms(100); PORTB ^= 0x01; } } При этом код правильный и компактный WinAVR20070525: Код 88: 94 e6 ldi r25, 0x64; 100 8a: 49 2e mov r4, r25 8c: 51 2c mov r5, r1 8e: 61 2c mov r6, r1 90: 71 2c mov r7, r1 92: 88 20 and r8, r8 94: f1 f3 breq .-4 ; 0x92 <main+0x1a> while(1){ timer_ms(100); PORTB ^= 0x01; 96: 88 b3 in r24, 0x18; 24 98: 91 e0 ldi r25, 0x01; 1 9a: 89 27 eor r24, r25 9c: 88 bb out 0x18, r24; 24 9e: f4 cf rjmp .-24 ; 0x88 <main+0x10> Цитата(aesok @ Jun 10 2008, 16:15)  AVRGCC ignores "volatile" keyword for "register" variables А вот это не совсем так, оно не игнорируется целиком, но логика работы при этом мягко говоря странная...  результат при компиляции прерывания: volatile register unsigned long count_ms asm("r4"); Код ISR(TIM0_COMPA_vect) { 4a: 1f 92 push r1 4c: 0f 92 push r0 4e: 0f b6 in r0, 0x3f; 63 50: 0f 92 push r0 52: 11 24 eor r1, r1 if(count_ms){--count_ms;} 54: 41 14 cp r4, r1 56: 51 04 cpc r5, r1 58: 61 04 cpc r6, r1 5a: 71 04 cpc r7, r1 5c: 31 f0 breq .+12 ; 0x6a <__vector_6+0x20> 5e: 08 94 sec 60: 41 08 sbc r4, r1 62: 51 08 sbc r5, r1 64: 61 08 sbc r6, r1 66: 71 08 sbc r7, r1 68: 02 c0 rjmp .+4 ; 0x6e <__vector_6+0x24> else{flag_ms = 1;} 6a: 88 24 eor r8, r8 6c: 83 94 inc r8 6e: 0f 90 pop r0 70: 0f be out 0x3f, r0; 63 72: 0f 90 pop r0 74: 1f 90 pop r1 76: 18 95 reti Здесь все ок. без volatile, register unsigned long count_ms asm("r4"); Код ISR(TIM0_COMPA_vect) { 4a: 1f 92 push r1 4c: 0f 92 push r0 4e: 0f b6 in r0, 0x3f; 63 50: 0f 92 push r0 52: 11 24 eor r1, r1 54: 8f 93 push r24 56: 9f 93 push r25 58: af 93 push r26 5a: bf 93 push r27 if(count_ms){--count_ms;} 5c: 41 14 cp r4, r1 5e: 51 04 cpc r5, r1 60: 61 04 cpc r6, r1 62: 71 04 cpc r7, r1 64: 31 f0 breq .+12 ; 0x72 <__vector_6+0x28> 66: 08 94 sec 68: 41 08 sbc r4, r1 6a: 51 08 sbc r5, r1 6c: 61 08 sbc r6, r1 6e: 71 08 sbc r7, r1 70: 02 c0 rjmp .+4 ; 0x76 <__vector_6+0x2c> else{flag_ms = 1;} 72: 81 e0 ldi r24, 0x01; 1 74: 88 2e mov r8, r24 76: bf 91 pop r27 78: af 91 pop r26 7a: 9f 91 pop r25 7c: 8f 91 pop r24 7e: 0f 90 pop r0 80: 0f be out 0x3f, r0; 63 82: 0f 90 pop r0 84: 1f 90 pop r1 86: 18 95 reti Ну и зачем здесь сохраняются r24-r27 ? и почему нельзя было обойтись eor r8,r8 inc r8 как в предыдущем коде ? замечу при этом что добавляли/убирали volatile ВООБЩЕ У ДРУГОЙ ПЕРЕМЕННОЙ !
|
|
|
|
|
Jun 11 2008, 19:33
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Jun 11 2008, 23:04)  Второй раз повторяю, GCC не поддеживае volatile register переменные. Не подерживает - это значит что нет гарантии что любой код использующий volatile register переменные будет работать при любом уровне оптимизации. Но в Gcc 3.4.6 без volatile это ведь работало правильно при любом коде! Цитата К сожалению варинг сообщающий об этом пропал гте-то в 2005 году и если я правильно панял его вернули в феврале 2008. Да, его вернули http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34351Вопрос в том правильно ли было выключать/включать варнинги вместо того чтобы обращение к регистровым переменным пометить как неоптимизируемые(собственно как это и происходит при асм вставке) ? Ну и еще один вопрос, по Вашему мнению можно вообще пользоваться регистровыми переменными(без volatile) в GCC ?
|
|
|
|
|
Jun 11 2008, 19:47
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Jun 11 2008, 23:23)  Но в Gcc 3.4.6 без volatile это ведь работало правильно при любом коде! Наверное просто хуже работал оптимизатор и поэтому проблем не возникало. А в новых версиях добавили новые проходы оптимизации. Цитата Да, его вернули http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34351Вопрос в том правильно ли было выключать/включать варнинги вместо того чтобы обращение к регистровым переменным пометить как неоптимизируемые(собственно как это и происходит при асм вставке) ? GCC не помечает регистры признаком volatile. http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00657.htmlАнатолий.
Сообщение отредактировал aesok - Jun 11 2008, 19:58
|
|
|
|
|
Jun 11 2008, 20:13
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Jun 11 2008, 23:47)  В посте №22 я уже показывал что еще как помечает, только делает он это как-то ммм... странновато... Цитата Наверное просто хуже работал оптимизатор и поэтому проблем не возникало. А в новых версиях добавили новые проходы оптимизации. Дело в том что даже в самой последней WinAVR(20080512) есть демка под названием asmdemo. И там есть такой код: project.h : Код #ifdef __ASSEMBLER__
# define sreg_save r2 # define flags r16 # define counter_hi r4
#else /* !ASSEMBLER */
#include <stdint.h>
register uint8_t sreg_save asm("r2"); register uint8_t flags asm("r16"); register uint8_t counter_hi asm("r4");
#endif /* ASSEMBLER */ isrs.S : Код TIM0_COMPA_vect: in sreg_save, _SFR_IO_ADDR(SREG) inc counter_hi clr flags asmdemo.c : Код void ioinit(void) { counter_hi = 0; flags = 0; в данном случае все хорошо и на 3.4.6 и на 4.x.x, но только до момента пока я не решу пользуясь gcc 4.x.x добавить в сишном коде что-нить типа while (!flag);
|
|
|
|
|
Jun 11 2008, 20:57
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Jun 11 2008, 23:33)  Ну и еще один вопрос, по Вашему мнению можно вообще пользоваться регистровыми переменными(без volatile) в GCC ? Только если они не используются в прерываниях. Во первых безопасно можно использовать только регистры r2-r7, остальные могут использоваться компилятором. Во вторых почему нельзя использовать глобальные регистровые переменные в обработчиках прерываний. r2-r7 - это call-saved регистры, то-есть если есть большая функция для которой генерируется код использующий эти регистры то при в входе в функцию r2-r7 сохраняться в стеке при выходе из нее восстановятся. Допустим такая функция бала вызвана из main, при этом содержимое регистровой переменой временно сохранилось в стеке. В этот момент происходит прерывание и обработчик прерывания работая с регистровой перемеренной (r2-r7) работает не со своими данными а с данными функции которую он прервал. После завершения обработчика прерывания локальные значения r2-r7 в функции будут искажены, а после возврата из этой функции r2-r7 (глобальная переменная) будут восстановлены из стека, и если обработчик прерывания сохранял значения в регистровой переменной то оно будет заменено на предыдущее. Анатолий. Цитата(singlskv @ Jun 12 2008, 00:13)  register uint8_t flags asm("r16"); Чюш!!!! r16 используется для передачи аргументов функции. Это будет работать до тех пор пока в программе не появится функция у которой общий размер аргументов будет превышать 8 байт. Анатолий. Цитата(singlskv @ Jun 12 2008, 00:13)  В посте №22 я уже показывал что еще как помечает, только делает он это как-то ммм... странновато... Если чтото работает странно - это называеться не работает. Анатолий. Цитата(singlskv @ Jun 12 2008, 00:13)  В посте №22 я уже показывал что еще как помечает, только делает он это как-то ммм... странновато... Цитата Re: [PATCH] volatile global register variable From: Ian Lance Taylor <ian at airs dot com> To: "Joseph S. Myers" <joseph at codesourcery dot com> Cc: David Edelsohn <dje at watson dot ibm dot com>, gcc-patches at gcc dot gnu dot org, Mark Mitchell <mark at codesourcery dot com>, bergner at vnet dot ibm dot com Date: 09 Nov 2005 11:33:17 -0800 Subject: Re: [PATCH] volatile global register variable References: <200511091628.jA9GSTq17300@makai.watson.ibm.com><Pine.LNX.4.64.0511091812330.10480@digraph.polyomino.org.uk>
They "don't work as you might wish" because at the RTL level a global register variable is stored as a REG, and there is no way to mark a REG as volatile.
Сообщение отредактировал aesok - Jun 11 2008, 20:56
|
|
|
|
|
Jun 11 2008, 21:15
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Jun 12 2008, 00:39)  Только если они не используются в прерываниях. а нафига они тогда вобще нужны  Цитата Во первых безопасно можно использовать только регистры r2-r7, остальные могут использоваться компилятором. Да именно так и написанно в доке, но для обсуждаймого примера это не существенно. Цитата Во вторых почему нельзя использовать глобальные регистровые переменные в обработчиках прерываний. ............................................... Это все понятно, действительно для long long, float и др библиотек можно нарваться, Ну а если все это не используется ? Цитата(aesok @ Jun 12 2008, 00:57)  Чюш!!!! r16 используется для передачи аргументов функции. Это будет работать до тех пор пока в программе не появится функция у которой общий размер аргументов будет превышать 8 байт. Ну это наверное не ко мне а к Joerg Wunsch ?  приведу Вам полный файл C:\WinAVR-20080512\doc\avr-libc\examples\asmdemo\project.h Код /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * Joerg Wunsch wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch * ---------------------------------------------------------------------------- * * Demo combining C and assembly source files. * * $Id: project.h,v 1.1 2006/08/29 19:45:06 joerg_wunsch Exp $ */
/* * Global register variables. */ #ifdef __ASSEMBLER__
# define sreg_save r2 # define flags r16 # define counter_hi r4
#else /* !ASSEMBLER */
#include <stdint.h>
register uint8_t sreg_save asm("r2"); register uint8_t flags asm("r16"); register uint8_t counter_hi asm("r4");
#endif /* ASSEMBLER */ Просто сами его проверьте... Цитата They "don't work as you might wish" because at the RTL level a global register variable is stored as a REG, and there is no way to mark a REG as volatile. Но факт то на лицо.... просто возмите и скомпилируйте сами... иначе разговор очень странный, типа "это не может быть потому что не может быть..." Ну меняет наличие volatile поведение у регистровой переменной и все тут...
|
|
|
|
|
Jun 11 2008, 22:08
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Jun 12 2008, 01:15)  а нафига они тогда вобще нужны  Мое мнение их не надо использовать. Если регистровые переменые работают сегодня в коде из 50 строк, то нет ни какой гарантии что они будут работать когда размер проекта увеличется до 1000 строк. Цитата Это все понятно, действительно для long long, float и др библиотек можно нарваться, Ну а если все это не используется ? Все ваши функции не более 10 строк длиной? Вы точно знаете что компилятор не понаделает инлайн вставок и не превратит десяток таких функций в одну большую? Цитата Ну это наверное не ко мне а к Joerg Wunsch ?  Насколько я понял он использовал r16 для flags для того чтобы написать в isrs.S: Код ... ser flags ... Цитата Просто сами его проверьте... Это рабочий пример, только он рабочий до тех пор пока в него не добавили функцию Код void foo (long a, long b, char c); Цитата иначе разговор очень странный, типа "это не может быть потому что не может быть..." Ну меняет наличие volatile поведение у регистровой переменной и все тут... Меня не интерисует конкретный пример который случайно работает. В письме же написано регистровая переменая распологаеться в регистре. Регистр в GCC не имеет атрибута volatile, поэтому оптимизатор может оптимизировать доступ к этому регистру, тоесть переменной. Нельзя пологаться на volatile для регистровой переменной. Анатолий. Цитата(singlskv @ Jun 12 2008, 01:15)  Ну меняет наличие volatile поведение у регистровой переменной и все тут... Конечно меняет. GCC при компиляции кода выполняет порядка 200 проходов, до какого-то времени регистровая volatile переменная является volatile переменной и компилятор не оптимизирует к ней доступ, но в какой то момент она превращается в регистр, к сожалению без атрибута волативности, и вот тут возможна нежелательная оптимизация. Анатолий.
Сообщение отредактировал aesok - Jun 11 2008, 22:11
|
|
|
|
|
Jun 11 2008, 22:21
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Jun 12 2008, 01:43)  Все ваши функции не более 10 строк длиной? Вы точно знаете что компилятор не понаделает инлайн вставок и не превратит десяток таких функций в одну большую? Вы знаете...., да, я в этом точно уверен, потому что если я буду в каком-то конкретном случае сомневаться, я помещу такой код в отдельный файл, и как бы компилятор не хотел, он не будет иметь права чего-нить там лишнее соптимизировать... Цитата Насколько я понял он использовал r16 для flags для того чтобы написать в isrs.S: Код ... ser flags ... Вообще-то в этом конкретном примере легко можно было бы обойтись и без SER, и разместить flags в R2-R7, но речь то не об этом, насколько я понимаю это пример КАК МОЖНО писать для компиляции в Gcc ? Цитата Меня не интерисует конкретный пример который случайно работает. В письме же написано регистровая переменая распологаеться в регистре. Регистр в GCC не имеет атрибута volatile, поэтому оптимизатор может оптимизировать доступ к этому регистру, тоесть переменной. Нельзя пологаться на volatile для регистровой переменной. Еще раз спрашиваю, ПОЧЕМУ разный результат компиляции если из этого письма следует что volatile у регистровой переменной просто выкинули ??? Пока писал Вы ответили: Цитата Конечно меняет. GCC при компиляции кода выполняет порядка 200 проходов, до какого-то времени регистровая volatile переменная является volatile переменной и компилятор не оптимизирует к ней доступ, но в какой то момент она превращается в регистр, к сожалению без атрибута волативности, и вот тут возможна нежелательная оптимизация. Вот собственно и суть вопроса, почему в тот самый момент когда она(регистровая volatile) становиться просто регистром, код доступа к ней не помечается как сторонний как это происходит в случае asm volatile ?
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|