Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Winavr сокращает функцию
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
A.l.e.x.
Помогите разобраться с WINAVR. При размещении переменных в регистрах компилятор ведёт себя подозрительно: сокращает функции, в которых они используются. 07.gif Но при обычном объявлении всё работает. Подскажите, где может быть ошибка?

Код
#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;
    }
}
aesok
Регистровые volatile переменные в GCC не работают.

Анатолий

AVRGCC ignores "volatile" keyword for "register" variables
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=17336
A.l.e.x.
Цитата(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?
dimka76
Цитата(A.l.e.x. @ Jun 10 2008, 15:36) *
И каков же выход? Использовать IAR?


Используйте GPIO0, GPIO1, GPIO2. В принципе можно даже использовать любые незадействованные SFR с адресом 0х00 - 0х1F
singlskv
Цитата(A.l.e.x. @ Jun 10 2008, 16:36) *
И каков же выход?
Просто уберите volatile при объявлении регистровой переменной,
все должно скомпилится правильно.
A.l.e.x.
Цитата(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 при объявлении регистровой переменной,
все должно скомпилится правильно.

Скомпилировалось, но не правильно. Можете сами проверить, в архиве весь проект...
singlskv
Цитата(A.l.e.x. @ Jun 10 2008, 18:02) *
Скомпилировалось, но не правильно. Можете сами проверить, в архиве весь проект...
А какая версия WinAVR ?
Скомпилируйте с листингом и покажите его.
Сергей Борщ
Цитата(A.l.e.x. @ Jun 10 2008, 15:36) *
И каков же выход?
Конкретно в этом простом случае можно написать вставку на инлайновом ассемблере.
A.l.e.x.
Цитата(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 --------
aesok
Цитата(singlskv @ Jun 10 2008, 18:06) *
А какая версия WinAVR ?


Все версии avr-gcc так работают.

Анатолий.
singlskv
Цитата(aesok @ Jun 10 2008, 20:28) *
Все версии avr-gcc так работают.
Ну это как минимум не так smile.gif

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 ???
AHTOXA
Цитата(singlskv @ Jun 10 2008, 23:44) *
Можно ли получить такой же компактный/быстрый код на Gcc 4.x.x ???


Увы sad.gif

Без оптимизации выходит:
Код
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).
alx2
Цитата(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        **** }
A.l.e.x.
Цитата(Сергей Борщ @ Jun 10 2008, 17:19) *
Конкретно в этом простом случае можно написать вставку на инлайновом ассемблере.

Можно ли подобно макросу _SFR_IO16(io_addr) расположить 32-битную переменную в область SFR?
AHTOXA
Цитата(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? Хочу такой жеsmile.gif
singlskv
Цитата(AHTOXA @ Jun 11 2008, 16:33) *
Странно...
avr-gcc.exe (GCC) 4.2.2 (WinAVR 20071221):
.....................
avr-gcc.exe (GCC) 4.1.2 (WinAVR 20070525):
.....................
Это с volatile или без перед register ?
Сергей Борщ
Цитата(A.l.e.x. @ Jun 11 2008, 09:39) *
Можно ли подобно макросу _SFR_IO16(io_addr) расположить 32-битную переменную в область SFR?
Непонятен вопрос. Вы выделяете 4 регистра в области SFR под свою переменную в уме, а обращаетесь к ним через _SFR_IO_ADR() по конкретным адресам. А вы уверены, что вам нужна там 4-байтовая переменная?
A.l.e.x.
Цитата(Сергей Борщ @ Jun 11 2008, 17:54) *
Непонятен вопрос. Вы выделяете 4 регистра в области SFR под свою переменную в уме, а обращаетесь к ним через _SFR_IO_ADR() по конкретным адресам. А вы уверены, что вам нужна там 4-байтовая переменная?

Я имел ввиду свойство макроса _SFR_IO16(io_addr) , при помощи которого получается 16-битная переменная, вроде как int. Выполнение арифметических операций при этом не должно вызывать трудностей. Например:
Код
#define var  _SFR_IO16(0x09)
...
var++;
...

Однако, если я к переменной int буду обращаться как к отдельным байтам, то у меня сразу могут возникнуть некоторые трудности. Поправьте меня, если я заблуждаюсь.
mdmitry
Разные версии WinAvr разрешают располагать регистровые переменные пользователя в разных регистрах. Это хорошо видно из документации по avr-libc. Имел проблему при переходе на WinAVR-20071221 с предыдущей версии. Поэтому тесты участников надо бы сопровождать соответствующими комментариями не только по версии компилятора но и по допускаемым для использования регистрам, уровень оптимизации тоже играет роль (-Os -O1 -O2). В одной версии компилятора регистров для пользователя остается больше, а в другой меньше.
Сергей Борщ
Цитата(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 буду обращаться как к отдельным байтам, то у меня сразу могут возникнуть некоторые трудности. Поправьте меня, если я заблуждаюсь.
Какие трудности? При побайтовом доступе запись в программе на С усложняется, только и всего. Или вы имели ввиду другие трудности?
AHTOXA
Цитата(singlskv @ Jun 11 2008, 19:54) *
Это с volatile или без перед register ?


Это без volatile.
singlskv
Цитата(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
А вот это не совсем так, оно не игнорируется целиком, но логика работы при этом
мягко говоря странная... sad.gif
результат при компиляции прерывания:
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 ВООБЩЕ У ДРУГОЙ ПЕРЕМЕННОЙ !
aesok
Второй раз повторяю, GCC не поддерживает volatile register переменные. Не
поддерживает - это значит что нет гарантии что любой код использующий
volatile register переменные будет работать при любом уровне оптимизации. К
сожалению варинг сообщающий об этом пропал где-то в 2005 году и если я
правильно понял его вернули в феврале 2008. Попробуйте откомпилировать
тестовый пример с "volatile register" GCC 4.4 с клюем -Wall. Или с ключом
-Wvolatile-register-var на 4.3.

Анатолий.
singlskv
Цитата(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 ?
aesok
Цитата(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

Анатолий.
singlskv
Цитата(aesok @ Jun 11 2008, 23:47) *
GCC не помечает регистры признаком vilatile.
http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00657.html
В посте №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);
aesok
Цитата(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.
singlskv
Цитата(aesok @ Jun 12 2008, 00:39) *
Только если они не используются в прерываниях.
а нафига они тогда вобще нужны smile.gif
Цитата
Во первых безопасно можно использовать только регистры r2-r7, остальные могут
использоваться компилятором.
Да именно так и написанно в доке, но для обсуждаймого примера это не существенно.
Цитата
Во вторых почему нельзя использовать глобальные регистровые переменные в
обработчиках прерываний.
...............................................
Это все понятно, действительно для long long, float и др библиотек можно нарваться,
Ну а если все это не используется ?

Цитата(aesok @ Jun 12 2008, 00:57) *
Чюш!!!! r16 используется для передачи аргументов функции. Это будет работать до тех пор пока в программе не появится функция у которой общий размер аргументов будет превышать 8 байт.
Ну это наверное не ко мне а к Joerg Wunsch ? biggrin.gif
приведу Вам полный файл 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 поведение у регистровой переменной и все тут...
aesok
Цитата(singlskv @ Jun 12 2008, 01:15) *
а нафига они тогда вобще нужны smile.gif

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

Цитата
Это все понятно, действительно для long long, float и др библиотек можно нарваться,
Ну а если все это не используется ?

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

Цитата
Ну это наверное не ко мне а к Joerg Wunsch ? biggrin.gif

Насколько я понял он использовал 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 переменной и компилятор не
оптимизирует к ней доступ, но в какой то момент она превращается в регистр, к
сожалению без атрибута волативности, и вот тут возможна нежелательная
оптимизация.

Анатолий.
singlskv
Цитата(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 ?
_Pasha
Тоже хотел недавно "поджать" компилер в регистрах. Но грабли пришли с другой стороны. Подключил математику. А там prologue_saves/epilogue_restores не позволяют фривольно использовать регистры в прерываниях. Оно-то и понятно, коль на асме переписана libm.a
В общем, глупости все это.
У меня тоже бывает системный таймер 32 бит, и обращение к нему -такое впечатление, что проц только этим и занимается smile.gif - атомарное, и из памяти. Жуть. Но сильно все-таки оно не мешает. Просто выполняется и все. Потому что критические по времени части выводятся так, чтобы все-таки выиграть в регистровых операциях ужЕ после того, как в черновом варианте они худо-бедно заработали в сишном виде. И если на достаточно большом прерывании удается раза в два нагнуть компилятор по быстродействию кода - можно спать спокойно. Все будет работать.
A.l.e.x.
Цитата(Сергей Борщ @ 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 здесь были бы более уместны twak.gif . А как бы компилятору это намекнуть?
alx2
Цитата(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? Хочу такой жеsmile.gif
? не понимаю вопроса. У меня avr-gcc-4.2.2.

Цитата(aesok @ Jun 12 2008, 01:57) *
Во вторых почему нельзя использовать глобальные регистровые переменные в
обработчиках прерываний. r2-r7 - это call-saved регистры, то-есть если есть
большая функция для которой генерируется код использующий эти регистры то при
В таких случаях помогает -ffixed-reg. У меня есть целая линейка проектов, где обмен данными между обработчиком прерываний и основной программой идет именно через регистры, и таких регистров аж 8 штук. Остальным функциям просто запрещено ими пользоваться в своих личных целях.
singlskv
Цитата(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
AHTOXA
Цитата(alx2 @ Jun 12 2008, 17:50) *
Я компилировал код, приведенный в первом посте. Без каких-либо изменений.


А я компилировал код, приведённый в посте №9, там нет volatile smile.gif

Цитата
? не понимаю вопроса. У меня avr-gcc-4.2.2.

Теперь всё понятно, вопрос снятsmile.gif
singlskv
Цитата(AHTOXA @ Jun 12 2008, 22:20) *
А я компилировал код, приведённый в посте №9, там нет volatile smile.gif
Теперь всё понятно, вопрос снятsmile.gif
Да, это я посоветовал попробовать убрать 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
alx2
Цитата(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 на себя.
aesok
сори, ошибочный пост
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.