Forcing 16 or 32 bits global variable to use register in gcc

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

I've been using registers for global variable for many projects.

Instead of using :

volatile uint8_t timer;

I use

register uint8_t timer asm("r3");

That has the benefits of much much faster and smaller code.

But does someone knows how to define 16 or 32 bits variables that way ?

Syntax like :

register uint16_t counter asm("r4");

generate a compile error: conflicting types for 'counter'

Any idea ?

Thanks.

Chris.

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

I have the same problem (see my post [url]https://www.avrfreaks.net/index.p... [/url])
I tried to do

register uint8_t i asm("r3") ;
register uint8_t i1 asm("r4") ;
int *qwer;
int main()
{
qwer = &i;
}

but it isn't work: "error: address of global register variable 'i' requested"

And so, realisation of direct placing into registers is bad, see my post.

Maybe it is not possible, maybe it will be corrected later

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

I'm no expert so this is a honest question. Could you use a union to do that?

Edward

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

I don't think unions or pointers will do the trick as registers have no pointers...

I've seen a code example on the net that use the same syntax

register uint16_t counter asm("r4"); 

but that was with gcc 2.x...
Maybe gcc 3.x just can't do it, but I would be surprised.

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

As I said in that other thread I think this is to do with the registers you are choosing. The registers from R16 onwards are useable in a lot more AVR opcodes than the low numbered ones. Now for 16 bits the ultimate registers to use are R24:R25 and X, Y and Z but you can't use these as the compiler will want to use them for other purposes but using R16 I got:

register uint16_t counter asm("r16");

int main(void) { 
  bc:	80 91 84 00 	lds	r24, 0x0084
  c0:	90 91 85 00 	lds	r25, 0x0085
  c4:	8c 01       	movw	r16, r24

	counter = TCNT1;

Which DOES appear to have used R16 (and R17) for 'counter'

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

Whoaw you're right, it works.
I don't have much time to dig into the assembly opcodes, but it definitely proves it's better to know more about the lower level stuff.

Thanks for your help, I gained quite a few bytes there ;-)

Chris.

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

If you're binding global variables to registers, then be carefut using any precompiled library functions (including any floating-point stuff), especially if you're using any interrupts.

Any precompiled libraries (or functions otherwise defined in any C files that aren't made aware of your register variables at compile-time) are liable to make use of any registers, regardless of your decision to locate a global variable there in some other C file.

Any function that's not aware of your register variable binding, and makes use of registers r2 up to r17 for local purposes, is guaranteed to save the previous state of that register and restore it before returning. However, if an interrupt occurs in the middle of such a function, there's no telling what might be stored there, and it's likely not the global variable you were expecting.

Registers r18 up to r27 are a different story entirely -- no precompiled library (or C file compiled without explicit knowledge of your register binding) has any obligation to preserve the values of any registers in that range.

As well, you'll want to do some experimentation before binding any register variables to registers from r25 down to r8, since those registers are reserved for function call arguments.

In short, you're only "safe" if you limit yourself to register variables in the range from r2 up to r7. Furthermore, you must make sure that the registers are explicitly reserved in the source code of every C file you plan to link into the application. Additionally, you must either:
1) Never make use of any precompiled libraries from avr-libc, or
2) Never make use of your register-bound variables inside ISRs, or
3) Temporarily inhibit interrupts before entering any precompiled avr-libc library function, and restore interrupts afterwords.