avr-gcc-list
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-gcc-list] How to reserve registers


From: Paulo Marques
Subject: Re: [avr-gcc-list] How to reserve registers
Date: Tue, 03 Jan 2012 14:21:20 +0000
User-agent: Thunderbird 2.0.0.23 (X11/20090817)

Omar Choudary wrote:
> That is almost correct. The 2 points:
> 
> 1. You are right that at this point you might almost do it in C. However
> the difference is of about 20-30 cycles which is actually significant since
> the avr-gcc introduces many more instructions to save more registers
> than they are actually needed.
> 
> This is an output from what avrlibc will use to protect registers:
> --------------------
> 610:   1f 92           push    r1
>      612:   0f 92           push    r0
>      614:   0f b6           in  r0, 0x3f    ; 63
>      616:   0f 92           push    r0
>      618:   0b b6           in  r0, 0x3b    ; 59
>      61a:   0f 92           push    r0
>      61c:   11 24           eor r1, r1
>      61e:   2f 93           push    r18
>      620:   3f 93           push    r19
>      622:   4f 93           push    r20
>      624:   5f 93           push    r21
>      626:   6f 93           push    r22
>      628:   7f 93           push    r23
>      62a:   8f 93           push    r24
>      62c:   9f 93           push    r25
>      62e:   af 93           push    r26
>      630:   bf 93           push    r27
>      632:   ef 93           push    r30
>      634:   ff 93           push    r31
> --------------------
> the same in reverse and using pop is used at the end. If you look at my
> code you'll see that actually you save cycles.

If gcc is doing this, it is a missed optimization at best (or a bug).
>From what I remember, gcc only pushed the registers you actually use
unless you call external functions, in which case it has no option but
to push everything.

Are you sure that a function like this:

volatile uint32_t counter;

interrupt_function()
{
        counter++;
}

pushes all those registers?

What compiler version are you using?

> 2. Indeed there might be a bug there if the time2 interrupt modifies
> those registers.
> Thanks for pointing it, I was relying on the fact
> that my interrupt saves the value but I realize that indeed the RAM value will
> be modified within access to the 4 bytes.
> 
> I guess a quick fix to this is to disable interrupts in the assembler 
> functions
> that access the ram value.

Or you could have a look at the atomic.h macros which do exactly that
while allowing you to program in C.

Anyway, if you really want to optimize your counter, check if your
device has "general purpose i/o registers" (GPIORn). These registers act
as ports, so can be addressed with IN/OUT instructions (saving one clock
cycle over RAM accesses) but are actually general purpose 8 bit
registers that can be used to hold any data the application wants to use.

If you look at the datasheet for the atmega168 (for instance), you'll
see it has 3 of these registers which could hold the lower 3 bytes of
the counter. This way you only use one register to access all of them
and only need to push one register.

Something like this (pseudo-code):

push    r0
in      r0, SREG
push    r1
eor     r1, r1
push    r2

sec
in      r2, GPIOR0
adc     r2, r1
out     GPIOR0, r2
in      r2, GPIOR1
adc     r2, r1
out     GPIOR1, r2
in      r2, GPIOR2
adc     r2, r1
out     GPIOR2, r2
lds     r2, high_counter_byte
adc     r2, r1
sts     high_counter_byte, r2

pop     r2
pop     r1
out     SREG, r0
pop     r0
reti

I hope this helps,

-- 
Paulo Marques
Software Development Department - Grupo PIE, S.A.
Phone: +351 252 290600, Fax: +351 252 290601
Web: www.grupopie.com

Pointy-Haired Boss: I don't see anything that could stand in our way.
           Dilbert: Sanity? Reality? The laws of physics?



reply via email to

[Prev in Thread] Current Thread [Next in Thread]