[Top][All Lists]

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

Re: [avr-gcc-list] Time-efficient read of high byte in two-bytevariable

From: David Brown
Subject: Re: [avr-gcc-list] Time-efficient read of high byte in two-bytevariable
Date: Fri, 9 May 2003 09:46:28 +0200

You are on the right track with unions, but I think it could be a little
First off, if you want to make a type that combines a 16-bit and two 8-bit
data, you can do it a bit neater with anonymous unions:

typedef union {
    uint16_t w;
    struct {
        unsigned char lo, hi;
} combo;

It is best to avoid making your normal variables of type "combo" - you'll
make a mess of the rest of your program just for the sake of a couple of
clock cycles (changing "encPosDetentsNow ++" into "encPosDetentsNow.w ++" is
not good).

I found the most efficient method is to use a typecast from int to a pair of
bytes (or a "combo").  However, as far as I know it is impossible to force
the compiler to do that directly - we can only force a convertion of pointer
types.  As long as you want to take the high or low byte of something that
is not a local variable in a register, the best arrangement seems to be:

typedef struct { unsigned char lo, hi; } bytePair;
#define LoByte(x) ((*(bytePair*) &(x)).lo)
#define HiByte(x) ((*(bytePair*) &(x)).hi)

signed int encPosDetentsNow;
UDR = HiByte(encPosDetentsNow);

This produces optimal code under all optomisations.  But it forces the
compiler to generate addressable objects, so code like:

void test(void) {
    int encPosDetentsNow = 0x123;
    UDR = HiByte(encPosDetentsNow);

is going to be awful - encPosDetentsNow gets put on the stack.  Of course,
if gcc knew that registers are also directly addressable on the AVR, then
that would not be a problem.

So for local variables, the best code is using a local "combo" variable to
do the convertion.  If you want to wrap that in an inline function, remember
to use "static inline" to avoid an extra copy of the function being
generated - "static inline" can generally be used in header files just like
#define macros.  Also, don't worry about signed or unsigned integers - as
long as you are not using comparisons, shifts, multiplies or divides, you
can freely mix them.

> E. Weddington wrote:
> > There's been a lot of discussion and it seems the most efficient way
> > is to use a union.
> >
> > #include <inttypes.h>
> >
> > typedef struct
> > {
> > unsigned char lo;
> > unsigned char hi;
> > } hilow_t;
> >
> > typedef union
> > {
> > uint16_t word;
> > hilow_t byte;
> > } mytype ;
> >
> > mytype encPosDetentsNow;
> >
> > ...
> > {
> > ....
> > encPosDetentsNow.word = 0xFFFF;
> > UDR = encPosDetentsNow.byte.hi;
> > ....
> > }
> >
> > See what you get with this.
> That indeed works well. Cool.
> Let's see, my variable in question is a signed int... so I could change
> the typedef union
> typedef union
> {
> int16_t word;
> hilow_t byte;
> } mytype ;
> and tack on .word to all my references to that variable... that should
> be fine, right?
> Thanks,
> Wallace
> _______________________________________________
> avr-gcc-list mailing list
> address@hidden
> http://www.avr1.org/mailman/listinfo/avr-gcc-list

reply via email to

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