Is this bug in gcc or...

Go To Last Post
15 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, All!

How to put 16-bit variable into registers?!

For 8-bit it works. For 16-bit variable compiler use difrent registers in difrent functions:

/* mega168/main.c */


#include 
#include 


register volatile unsigned short RingPointer asm("r2");


ISR( TIMER1_CAPT_vect )
{
	++ RingPointer;
}


static unsigned char * ProcPointer;

static void
proc_res( void )
{
	do {
		++ ProcPointer;
	} while ( (unsigned short)ProcPointer != RingPointer );
} // proc_res


__attribute__ ((naked))
int main( void )
{
	RingPointer = 0x100;
	ProcPointer = (unsigned char*)0x100;
	sei();

	do {
		if ( (unsigned short) ProcPointer != RingPointer ) proc_res();
		(void)0;
	} while (1);
} // main

Part of lst file:

0000008a <__vector_10>:
  8a:	1f 92       	push	r1
  8c:	0f 92       	push	r0
  8e:	0f b6       	in	r0, 0x3f	; 63
  90:	0f 92       	push	r0
  92:	11 24       	eor	r1, r1
  94:	08 94       	sec
  96:	21 1c       	adc	r2, r1
  98:	31 1c       	adc	r3, r1
  9a:	0f 90       	pop	r0
  9c:	0f be       	out	0x3f, r0	; 63
  9e:	0f 90       	pop	r0
  a0:	1f 90       	pop	r1
  a2:	18 95       	reti

000000a4 
: a4: 80 e0 ldi r24, 0x00 ; 0 a6: 91 e0 ldi r25, 0x01 ; 1 a8: 90 93 01 01 sts 0x0101, r25 ac: 80 93 00 01 sts 0x0100, r24 b0: 78 94 sei b2: 80 91 00 01 lds r24, 0x0100 b6: 90 91 01 01 lds r25, 0x0101 ba: 21 e0 ldi r18, 0x01 ; 1 bc: 80 30 cpi r24, 0x00 ; 0 be: 92 07 cpc r25, r18 c0: e1 f3 breq .-8 ; 0xba c2: 01 96 adiw r24, 0x01 ; 1 c4: 21 e0 ldi r18, 0x01 ; 1 c6: 80 30 cpi r24, 0x00 ; 0 c8: 92 07 cpc r25, r18 ca: b9 f3 breq .-18 ; 0xba cc: 01 96 adiw r24, 0x01 ; 1 ce: 21 e0 ldi r18, 0x01 ; 1 d0: 80 30 cpi r24, 0x00 ; 0 d2: 92 07 cpc r25, r18 d4: b1 f7 brne .-20 ; 0xc2 d6: f1 cf rjmp .-30 ; 0xba

In main RingPointer is not used.

make.bat:

avr-gcc -O2 -mmcu=atmega168 -Wl,--relax  -ffixed-r2 -ffixed-r3 main.c -o main.elf
avr-objdump -h -s -S main.elf > main.lst
avr-gcc --version
avr-gcc.EXE (WinAVR 20090313) 4.3.2
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.

Ilya

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oops!

This is work:

/* mega168/main.c */


#include 
#include 


register volatile unsigned short RingPointer asm("r2");


void test1( void );
void test2( void );


ISR( TIMER1_CAPT_vect )
{
	++ RingPointer;
}


static unsigned char * ProcPointer;

static void
proc_res( void )
{
	do {
		++ ProcPointer;
		test1();
	} while ( (unsigned short)ProcPointer != RingPointer );
} // proc_res


__attribute__ ((naked))
int main( void )
{
	RingPointer = 0x100;
	ProcPointer = (unsigned char*)0x100;
	sei();

	do {
		if ( (unsigned short) ProcPointer != RingPointer ) proc_res();
		test2();
	} while (1);
} // main

But if test1() and test2() is static function then it is not work again...

Ilya

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can't force a 16 bit value into a single register on the AVR , as it's only an 8 bit MCU.

And ... Why would you force the value into a specific register (that you select) ?

The gcc will do the assignments automaticly , if you just use a variable.
If the variable as here is referenced both inside an interrupt routine & outside , you need to declare the variable volatile.

volatile unsigned short RingPointer;

Ohh ... and when accessing RingPointer , outside the ISR , make sure the access is ATOMIC (interrupts disabled).

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bingo600 wrote:
You can't force a 16 bit value into a single register on the AVR , as it's only an 8 bit MCU.

Hmm... I know this. But gcc put RingPointer into r2:r3 pair (as I want).
Quote:
And ... Why would you force the value into a specific register (that you select) ?

Because the inner loop in that program will be about 230-250 CPU clock. And it will be only one interrupt. So, 4 CPU clock (for save and restore _only_ _one_ register) -- it is about 2% of CPU power.
Quote:
The gcc will do the assignments automaticly , if you just use a variable.
If the variable as here is referenced both inside an interrupt routine & outside , you need to declare the variable volatile.

volatile unsigned short RingPointer;

Ohh ... and when accessing RingPointer , outside the ISR , make sure the access is ATOMIC (interrupts disabled).

/Bingo


Outside the ISR RingPointer will be only read (for check that it changed or not). So, there is no sense in atomic access to it. And interrupt have not to be delayed!

There will be some math and SPI routine also (without cli nor sei).

Ilya

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Outside the ISR RingPointer will be only read (for check that it changed or not). So, there is no sense in atomic access to it. And interrupt have not to be delayed!

There will be some math and SPI routine also (without cli nor sei).

So you want to access a 16 bit variable outside an ISR , that can be changed inside an ISR. Without doing it ATOMIC.

Happy coding :? ... I hope it's not for something critical.

/Bingo

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
register volatile unsigned short RingPointer asm("r2"); 

GCC cannot correctly handle "register volatile". And very likely you got a warning about that from the compiler.

Quote:
Outside the ISR RingPointer will be only read (for check that it changed or not). So, there is no sense in atomic access to it.
For the atomicity it doesn't really matter whether it is a read/write or read-only access. Without atomic protection the read WILL return nonsense from time to time.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, All!

Someone change subject to [solved..] but problem is not solved. "volatile" present in the first message.

Problem is in that fact: gcc turn out access to volatile register variable if there is only static functions.

sternst wrote:

register volatile unsigned short RingPointer asm("r2"); 

GCC cannot correctly handle "register volatile". And very likely you got a warning about that from the compiler.


I wrote make.bat file. There is no any message from compiler.

And I prefer to write 'register const volatile unsigned short RingPointer asm("r2");' but I need to initialize RingPointer in main() function, so... I get lack.

Quote:

Quote:
Outside the ISR RingPointer will be only read (for check that it changed or not). So, there is no sense in atomic access to it.
For the atomicity it doesn't really matter whether it is a read/write or read-only access. Without atomic protection the read WILL return nonsense from time to time.

:-)
If we cyclic poll variable to know that it is changed or not, then we cannot get nonsense result. We may get delay, it is true. But there is ring buffer, so it's ok.

Ilya

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
And I prefer to write 'register const volatile unsigned short RingPointer asm("r2");'
The more words the better? What is the sense of "const volatile"?

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sternst wrote:

register volatile

GCC cannot correctly handle "register volatile".

You depicted from the standard the meaning of "register volatile"? Really?

"volatile" is for static storage, not for storage in storage class "register". So it's undefined, and GCC might ignore it without being incorrect.

"const volatile" is fine. "const" means read-only and "volatile" that the access has side effects.

A use case is reading from a read-only SFR that might be changed by hardware.

An other use case is const data for which you provide a standard initializer and overwrite it later, for example after a calibration process. Even though the compiler knows the data, e.g. it sees that a[0]=42, it must not replace that value in an instruction like x=a[0] by x=42. There are other way of hiding the information, but I say customers use it that way.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB wrote:
You depicted from the standard the meaning of "register volatile"? Really?
The meaning of "volatile" in the standard is quite simple:
Quote:
volatile
No cacheing through this lvalue: each operation in the abstract semantics must be performed (that is, no cacheing assumptions may be made, since the location is not guaranteed to contain any previous value). In the absence of this qualifier, the contents of the designated location may be assumed to be unchanged except for possible aliasing.
What problem do you see in combining this with "register"?

SprinterSB wrote:
"volatile" is for static storage, not for storage in storage class "register". So it's undefined, and GCC might ignore it without being incorrect.
Can you give a quote for that? I don't find in the standard any restriction of "volatile" to a specific storage class. Of course "volatile" is used in almost all cases for static storage, but I can easily create an example where "volatile" makes sense for an automatic.

SprinterSB wrote:
"const volatile" is fine.
Yes, I see it now, thank you.

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are right for the storage class.

For volatile accesses, there is

C99 6.7.3 wrote:
What constitutes an access to an object that has volatile-qualified type is implementation-defined.

Then, "asm" together with "register" is a GNU extension not covered by the standard, so I wouldn't expect a definite statement from the standard or from GCC's statement on implementation defined behaviour with respect to the standard.

At least from the doc of global register vars there is

GCC wrote:
Stores into this register are never deleted even if they would appear to be dead, but references may be deleted or moved or simplified.
I agree that the documentation of volatile+register asm GNU extension needs improvement.

BTW, what is a sensible example for volatile auto? The only case I can imagine is banging the compiler to not optimize an auto so you can see it in the debugger or being moved around in the code.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Then, "asm" together with "register" is a GNU extension not covered by the standard, so I wouldn't expect a definite statement from the standard or from GCC's statement on implementation defined behaviour with respect to the standard.
Ok, at the moment I don't want to test what happens with a "volatile register" without the "asm" (is almost irrelevant anyway), so I take back my "cannot correctly handle" comment (for now). ;-)

Quote:
BTW, what is a sensible example for volatile auto?

void someFunc (void) {

    volatile bool flag = false;
    AttachEventFlag(SOME_EVENT,&flag);
    ...
    while(!flag);
    ...
    DetachEventFlag(&flag);
}

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!

sternst wrote:
Without atomic protection the read WILL return nonsense from time to time.

Interesting thought occurred to me. If we will use only 'movw' command for access to 16-bit volatile variable, then we will made atomic access to it. So, it is another coin for putting 16-bit volatile variable into register pair.

Ilya

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As written above, there is nothing like volatile for explicit register variables. So writing such stuff just serves to confuse yourself.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!

SprinterSB wrote:
As written above, there is nothing like volatile for explicit register variables.

For C code it is true. But if one need to work with 16-bit variable in assembler code, then he can make consistent access to 16-bit (volatile) register pair without cli/sei commands.

Quote:
So writing such stuff just serves to confuse yourself.

So... it recall to me that this value may changed arbitrarily.

Ilya