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

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

|
Помогите разобраться с WINAVR. При размещении переменных в регистрах компилятор ведёт себя подозрительно: сокращает функции, в которых они используются.  Но при обычном объявлении всё работает. Подскажите, где может быть ошибка? Код #include <avr/io.h> #include <avr/interrupt.h> volatile register unsigned long count_ms asm("r4"); volatile register unsigned char flag_ms asm("r8"); ///////////////////////////////////////////////////////////////////////////////////////////////// void timer_ms(unsigned long value) { count_ms = value; flag_ms = 0; while(flag_ms == 0); } ///////////////////////////////////////////////////////////////////////////////////////////////// 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; } }
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 37)
|
Jun 10 2008, 12:15
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Регистровые volatile переменные в GCC не работают. Анатолий AVRGCC ignores "volatile" keyword for "register" variables http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17336
Сообщение отредактировал aesok - Jun 10 2008, 12:28
|
|
|
|
|
Jun 10 2008, 12:36
|
Участник

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

|
Цитата(aesok @ Jun 10 2008, 15:15)  Регистровые volatile переменные в GCC не работают. Анатолий AVRGCC ignores "volatile" keyword for "register" variables http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17336И каков же выход? Использовать IAR?
|
|
|
|
|
Jun 10 2008, 14:02
|
Участник

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

|
Цитата(dimka76 @ Jun 10 2008, 15:55)  Используйте GPIO0, GPIO1, GPIO2. В принципе можно даже использовать любые незадействованные SFR с адресом 0х00 - 0х1F Если не трудно, подскажите как использовать SFR в дипазоне 0x09...0x13 (записать/прочитать данные 2-х или 4-х байтные)? Цитата(singlskv @ Jun 10 2008, 16:59)  Просто уберите volatile при объявлении регистровой переменной, все должно скомпилится правильно. Скомпилировалось, но не правильно. Можете сами проверить, в архиве весь проект...
|
|
|
|
|
Jun 10 2008, 14:33
|
Участник

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

|
Цитата(singlskv @ Jun 10 2008, 17:06)  А какая версия WinAVR ? Скомпилируйте с листингом и покажите его. WinAVR-20080512 Код > "make.exe" all
-------- begin -------- avr-gcc (WinAVR 20080512) 4.3.0 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compiling C: main.c avr-gcc -c -mmcu=attiny13 -I. -gdwarf-2 -DF_CPU=1200000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -pedantic -Wa,-adhlns=./main.lst -std=gnu99 -Wundef -MMD -MP -MF .dep/main.o.d main.c -o main.o main.c:4: warning: file-scope declaration of 'count_ms' specifies 'register' main.c:5: warning: file-scope declaration of 'flag_ms' specifies 'register'
Linking: main.elf avr-gcc -mmcu=attiny13 -I. -gdwarf-2 -DF_CPU=1200000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -pedantic -Wa,-adhlns=main.o -std=gnu99 -Wundef -MMD -MP -MF .dep/main.elf.d main.o --output main.elf -Wl,-Map=main.map,--cref -lm
Creating load file for Flash: main.hex avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock main.elf main.hex
Creating load file for EEPROM: main.eep avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 --no-change-warnings -O ihex main.elf main.eep || exit 0
Creating Extended Listing: main.lss avr-objdump -h -S -z main.elf > main.lss
Creating Symbol Table: main.sym avr-nm -n main.elf > main.sym
Size after: AVR Memory Usage ---------------- Device: attiny13
Program: 158 bytes (15.4% Full) (.text + .data + .bootloader)
Data: 0 bytes (0.0% Full) (.data + .bss + .noinit) -------- end --------
|
|
|
|
|
Jun 10 2008, 16:28
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(singlskv @ Jun 10 2008, 18:06)  А какая версия WinAVR ? Все версии avr-gcc так работают. Анатолий.
|
|
|
|
|
Jun 10 2008, 17:44
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(aesok @ Jun 10 2008, 20:28)  Все версии avr-gcc так работают. Ну это как минимум не так  WinAVR20060421(Gcc 3.4.6): CODE 00000048 <timer_ms>: register unsigned long count_ms asm("r4"); register unsigned char flag_ms asm("r8"); ///////////////////////////////////////////////////////////////////////////////////////////////// void timer_ms(unsigned long value) { 48: b9 2f mov r27, r25 4a: a8 2f mov r26, r24 4c: 97 2f mov r25, r23 4e: 86 2f mov r24, r22 count_ms = value; 50: 48 2e mov r4, r24 52: 59 2e mov r5, r25 54: 6a 2e mov r6, r26 56: 7b 2e mov r7, r27 flag_ms = 0; 58: 88 24 eor r8, r8 while(flag_ms == 0); 5a: 88 20 and r8, r8 5c: f1 f3 breq .-4 ; 0x5a <timer_ms+0x12> 5e: 08 95 ret
00000060 <__vector_6>: } ///////////////////////////////////////////////////////////////////////////////////////////////// ISR(TIM0_COMPA_vect) { 60: 1f 92 push r1 62: 0f 92 push r0 64: 0f b6 in r0, 0x3f ; 63 66: 0f 92 push r0 68: 11 24 eor r1, r1 if(count_ms){--count_ms;} 6a: 41 14 cp r4, r1 6c: 51 04 cpc r5, r1 6e: 61 04 cpc r6, r1 70: 71 04 cpc r7, r1 72: 31 f0 breq .+12 ; 0x80 <__vector_6+0x20> 74: 08 94 sec 76: 41 08 sbc r4, r1 78: 51 08 sbc r5, r1 7a: 61 08 sbc r6, r1 7c: 71 08 sbc r7, r1 7e: 02 c0 rjmp .+4 ; 0x84 <__vector_6+0x24> else{flag_ms = 1;} 80: 88 24 eor r8, r8 82: 83 94 inc r8 84: 0f 90 pop r0 86: 0f be out 0x3f, r0 ; 63 88: 0f 90 pop r0 8a: 1f 90 pop r1 8c: 18 95 reti
0000008e <main>: } ///////////////////////////////////////////////////////////////////////////////////////////////// int main(void) { 8e: cf e9 ldi r28, 0x9F ; 159 90: d0 e0 ldi r29, 0x00 ; 0 92: de bf out 0x3e, r29 ; 62 94: cd bf out 0x3d, r28 ; 61 TCCR0A = (0<<COM0A1)|(0<<COM0A0)|(0<<COM0B1)|(0<<COM0B0)|(1<<WGM01)|(0<<WGM00); //CTC 96: 82 e0 ldi r24, 0x02 ; 2 98: 8f bd out 0x2f, r24 ; 47 TCCR0B = (0<<FOC0A)|(0<<FOC0B)|(0<<WGM02)|(0<<CS02)|(1<<CS01)|(0<<CS00); // FCPU/8 9a: 83 bf out 0x33, r24 ; 51 OCR0A = 149; 9c: 85 e9 ldi r24, 0x95 ; 149 9e: 86 bf out 0x36, r24 ; 54 TIMSK0 = (0<<OCIE0B)|(1<<OCIE0A)|(0<<TOIE0); a0: 84 e0 ldi r24, 0x04 ; 4 a2: 89 bf out 0x39, r24 ; 57 sei(); a4: 78 94 sei while(1){ timer_ms(100); a6: 64 e6 ldi r22, 0x64 ; 100 a8: 70 e0 ldi r23, 0x00 ; 0 aa: 80 e0 ldi r24, 0x00 ; 0 ac: 90 e0 ldi r25, 0x00 ; 0 ae: cc df rcall .-104 ; 0x48 <timer_ms> PORTB ^= 0x01; b0: 88 b3 in r24, 0x18 ; 24 b2: 91 e0 ldi r25, 0x01 ; 1 b4: 89 27 eor r24, r25 b6: 88 bb out 0x18, r24 ; 24 b8: f6 cf rjmp .-20 ; 0xa6 <__stack+0x7>
как видно, оверхед только здесь: Код 48: b9 2f mov r27, r25 4a: a8 2f mov r26, r24 4c: 97 2f mov r25, r23 4e: 86 2f mov r24, r22 и здесь: Код b2: 91 e0 ldi r25, 0x01; 1 Но при этом код абсолютно корректный ! Можно ли получить такой же компактный/быстрый код на Gcc 4.x.x ???
|
|
|
|
|
Jun 10 2008, 18:12
|

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

|
Цитата(singlskv @ Jun 10 2008, 23:44)  Можно ли получить такой же компактный/быстрый код на Gcc 4.x.x ??? Увы Без оптимизации выходит: Код void timer_ms(unsigned long value) { 48: df 93 push r29 4a: cf 93 push r28 4c: 00 d0 rcall .+0 ; 0x4e <timer_ms+0x6> 4e: 00 d0 rcall .+0 ; 0x50 <timer_ms+0x8> 50: cd b7 in r28, 0x3d; 61 52: de b7 in r29, 0x3e; 62 54: 69 83 std Y+1, r22; 0x01 56: 7a 83 std Y+2, r23; 0x02 58: 8b 83 std Y+3, r24; 0x03 5a: 9c 83 std Y+4, r25; 0x04 count_ms = value; 5c: 49 80 ldd r4, Y+1; 0x01 5e: 5a 80 ldd r5, Y+2; 0x02 60: 6b 80 ldd r6, Y+3; 0x03 62: 7c 80 ldd r7, Y+4; 0x04 flag_ms = 0; 64: 88 24 eor r8, r8 while(flag_ms == 0); 66: 88 2d mov r24, r8 68: 88 23 and r24, r24 6a: e9 f3 breq .-6 ; 0x66 <timer_ms+0x1e> } 6c: 0f 90 pop r0 6e: 0f 90 pop r0 70: 0f 90 pop r0 72: 0f 90 pop r0 74: cf 91 pop r28 76: df 91 pop r29 78: 08 95 ret и так далее, а начиная с -O1: Код void timer_ms(unsigned long value) { 48: ff cf rjmp .-2 ; 0x48 <timer_ms> Это avr-gcc (GCC) 4.4.0 20080530 (experimental).
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Jun 10 2008, 19:32
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(AHTOXA @ Jun 10 2008, 23:12)  и так далее, а начиная с -O1: Код void timer_ms(unsigned long value) { 48: ff cf rjmp .-2 ; 0x48 <timer_ms> Это avr-gcc (GCC) 4.4.0 20080530 (experimental). gcc-4.2.2 начиная c -O1: Код 7:test.c **** void timer_ms(unsigned long value) 8:test.c **** { 79 /* prologue: frame size=0 */ 80 /* prologue end (size=0) */ 9:test.c **** count_ms = value; 83 0000 2B01 movw r4,r22 84 0002 3C01 movw r6,r24 10:test.c **** flag_ms = 0; 87 0004 8824 clr r8 88 .L2: 11:test.c **** while(flag_ms == 0); 91 0006 8820 tst r8 92 0008 01F0 breq .L2 93 /* epilogue: frame size=0 */ 94 000a 0895 ret 95 /* epilogue end (size=1) */ 96 /* function timer_ms size 6 (5) */ 12:test.c **** }
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Jun 11 2008, 06:39
|
Участник

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

|
Цитата(Сергей Борщ @ Jun 10 2008, 17:19)  Конкретно в этом простом случае можно написать вставку на инлайновом ассемблере. Можно ли подобно макросу _SFR_IO16(io_addr) расположить 32-битную переменную в область SFR?
|
|
|
|
|
Jun 11 2008, 12:33
|

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

|
Цитата(alx2 @ Jun 11 2008, 01:32)  gcc-4.2.2 начиная c -O1: Странно... avr-gcc.exe (GCC) 4.2.2 (WinAVR 20071221): Код 00000048 <timer_ms>: 48: 2b 01 movw r4, r22 4a: 3c 01 movw r6, r24 4c: 88 24 eor r8, r8 4e: ff cf rjmp .-2 ; 0x4e <timer_ms+0x6> avr-gcc.exe (GCC) 4.1.2 (WinAVR 20070525): Код void timer_ms(unsigned long value) { 4a: 46 2e mov r4, r22 4c: 57 2e mov r5, r23 4e: 68 2e mov r6, r24 50: 79 2e mov r7, r25 count_ms = value; flag_ms = 0; 52: 88 24 eor r8, r8 54: ff cf rjmp .-2 ; 0x54 <timer_ms+0xa> А у Вас какой GCC 4.2.2? Хочу такой же
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
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 ?
|
|
|
|
|
Jun 12 2008, 06:21
|
Участник

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

|
Цитата(Сергей Борщ @ Jun 11 2008, 19:48)  А, теперь понял. Идем в 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) и радуемся.Какие трудности? При побайтовом доступе запись в программе на С усложняется, только и всего. Или вы имели ввиду другие трудности? Действительно, работает, хотя я раньше так уже пробовал. Мне казалось, что результат компиляции неработоспособен из-за таких разных команд как OUT и STS: Код var16++; +00000044: B18E IN R24,0x0E +00000045: B19F IN R25,0x0F +00000046: 9601 ADIW R24,0x01 +00000047: B99F OUT 0x0F,R25 +00000048: B98E OUT 0x0E,R24 var32++; +00000049: 91800029 LDS R24,0x0029 +0000004B: 9190002A LDS R25,0x002A +0000004D: 91A0002B LDS R26,0x002B +0000004F: 91B0002C LDS R27,0x002C +00000051: 9601 ADIW R24,0x01 +00000052: 1DA1 ADC R26,R1 +00000053: 1DB1 ADC R27,R1 +00000054: 93800029 STS 0x0029,R24 +00000056: 9390002A STS 0x002A,R25 +00000058: 93A0002B STS 0x002B,R26 +0000005A: 93B0002C STS 0x002C,R27 Всё правильно, только команды IN и OUT здесь были бы более уместны  . А как бы компилятору это намекнуть?
|
|
|
|
|
Jun 12 2008, 11:50
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(AHTOXA @ Jun 11 2008, 17:33)  Странно... avr-gcc.exe (GCC) 4.2.2 (WinAVR 20071221): Код 00000048 <timer_ms>: 48: 2b 01 movw r4, r22 4a: 3c 01 movw r6, r24 4c: 88 24 eor r8, r8 4e: ff cf rjmp .-2 ; 0x4e <timer_ms+0x6> Цитата(AHTOXA @ Jun 11 2008, 22:44)  Это без volatile. Тогда ничего странного - без volatile это совершенно правильный код, т.к. timer_ms никогда не завершится. Я компилировал код, приведенный в первом посте. Без каких-либо изменений. Цитата(AHTOXA @ Jun 11 2008, 17:33)  А у Вас какой GCC 4.2.2? Хочу такой же  ? не понимаю вопроса. У меня avr-gcc-4.2.2. Цитата(aesok @ Jun 12 2008, 01:57)  Во вторых почему нельзя использовать глобальные регистровые переменные в обработчиках прерываний. r2-r7 - это call-saved регистры, то-есть если есть большая функция для которой генерируется код использующий эти регистры то при В таких случаях помогает -ffixed-reg. У меня есть целая линейка проектов, где обмен данными между обработчиком прерываний и основной программой идет именно через регистры, и таких регистров аж 8 штук. Остальным функциям просто запрещено ими пользоваться в своих личных целях.
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Jun 12 2008, 12:22
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(alx2 @ Jun 12 2008, 15:50)  Я компилировал код, приведенный в первом посте. Без каких-либо изменений. ? не понимаю вопроса. У меня avr-gcc-4.2.2. Да, я могу подтвердить это, код c volatile компактный и корректный. ИТОГО на этом коде: WinAVR 20060421 (Gcc 3.4.6) работает и с и без volatile WinAVR 20070525 (Gcc 4.1.2) не работает WinAVR 20071221 (Gcc 4.2.2) работает с volatile WinAVR 20080512 (Gcc 4.3.0) не работает WinAVR 200XYYZZ (Gcc 4.4.X) будет ругаться варнингом, про работоспособность ??? Сейчас попробую пособирать свои проекты с похожими конструкциями на 4.2.2
|
|
|
|
|
Jun 12 2008, 19:04
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(AHTOXA @ Jun 12 2008, 22:20)  А я компилировал код, приведённый в посте №9, там нет volatile  Теперь всё понятно, вопрос снят  Да, это я посоветовал попробовать убрать volatile т.к. на версиях 3.4.? оно вызывало варнинг и небольшое изменение кода. Т.к. я пока сижу на 3.4.6 проблем с регистровыми переменными не наблюдалось, но ведь когда-то все равно придеться переползать на что-нить поновее хотя бы из-за поддержки новых чипов... поэтому и пытаюсь понять на какую версию стоит переползать (отказываться от регистровых переменных очень не хочется, иногда это дает выигрыш в разы...) Потестировал немного 4.2.2 , вроде все корректно, правда выигрыша по оптимизации я не получил по сравнению с 3.4.6, где-то один быстрее где-то другой, по сумме, 3.4.6 на моих проектах оказался даже чуть быстрее, но разница не принципиальна. Единственный не до конца приятный/понятный момент при работе с регистровыми переменными на 4.2.2 это при чтении/записи IO в/из регистровой переменной: Код volatile register unsigned char pinb asm("r2"); ........ //запись PORTB = pinb; ; 8e: 28 ba out 0x18, r2; 24
// чтение pinb = PINB; ; a8: 86 b3 in r24, 0x16; 22 ; aa: 28 2e mov r2, r24 Почему при записи он писал прямо а при чтении читал в r24 ? 3.4.6 обходился без r24
|
|
|
|
|
Jun 12 2008, 20:51
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(singlskv @ Jun 12 2008, 17:22)  ИТОГО на этом коде: WinAVR 20060421 (Gcc 3.4.6) работает и с и без volatile WinAVR 20070525 (Gcc 4.1.2) не работает WinAVR 20071221 (Gcc 4.2.2) работает с volatile WinAVR 20080512 (Gcc 4.3.0) не работает WinAVR 200XYYZZ (Gcc 4.4.X) будет ругаться варнингом, про работоспособность ??? Могу до кучи добавить, что gcc-4.3.1 с -O1 генерит код как gcc-4.2.2, а начиная с -O2 дает rjmp на себя.
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|