How can you tell if your are compiling for AVR?

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

Hi all,

I'm writing some "portable" C code that will be shared between an AVR and another CPU architecture. Alas, the portable version of what I am trying to accomplish is generating unreasonably long assembly code for an 8-bit micro.

I need to tell by preprocessor macro if the target CPU is an AVR (not some specific part, but AVR in general). This way I can write 8-bit optimized code for that case.

Such a macro must exist - what is its name?

- kwr

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

If its gcc, then its in the makefile but you need to refer to a specific part number.

You will probably NOT be able to get away with a single program that works for ALL AVRs. At the very least, register names change. For some registers, bit names have changed. It will be a challenge.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

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

kwr wrote:
I need to tell by preprocessor macro if the target CPU is an AVR (not some specific part, but AVR in general).

You can use the switch -dM to get a list of all preprocessor macros that are defined.

It appears that any of the macros below might be useful for your purposes.

AVR
__AVR
__AVR_ARCH__
__AVR__

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

dkinzer - thanks, that is what I was looking for

ka7ehk - simply looking for C-source compatability. I'll be compiling the same code on ARM as a shared library for message passing.

FWIW - here is my problem:

I need to marshal / unmarshal little-endian 32-bit values from an array of bytes. On AVR this is trivial - cast the byte pointer to uint32_t and dereference. On ARM I am worried about word-aligned access and (well, not in my case) endianness.

So my code is like this now:

uint32_t to_dword(uint8_t *bytes)
{
#if AVR
  return *(uint32_t *)bytes;
#else
  return
    (uint32_t)bytes[0] |
    (uint32_t)bytes[1] << 8 |
    (uint32_t)bytes[2] << 16 |
    (uint32_t)bytes[3] << 24;
#endif
}

The non-AVR version of this compiled for AVR is pretty huge.

Anybody got a better way?

- kwr

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

kwr wrote:
The non-AVR version of this compiled for AVR is pretty huge. Anybody got a better way?

This may be a place where inline assembly code will be helpful. Are you using gcc for the ARM as well?

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

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

Using gcc on both.

The "AVR" part of my example is not too big at all. Not worth it for me to do in assembly code. I would like to only support a single version of the code, however the code that will work on both CPUs (and x86, et. al.) is what comes out bad when compiled for AVR.

Maybe there is some way to write that code so the optimizer makes it turn out well. If there is a way, I have not found it.

- kwr

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

kwr wrote:
I need to marshal / unmarshal little-endian 32-bit values from an array of bytes. On AVR this is trivial - cast the byte pointer to uint32_t and dereference. On ARM I am worried about word-aligned access and (well, not in my case) endianness.

So my code is like this now:

uint32_t to_dword(uint8_t *bytes)
{
#if AVR
  return *(uint32_t *)bytes;
#else
  return
    (uint32_t)bytes[0] |
    (uint32_t)bytes[1] << 8 |
    (uint32_t)bytes[2] << 16 |
    (uint32_t)bytes[3] << 24;
#endif
}


For the test, iI'd try something like
if( sizeof struct { char c; uint32_t u32 } == 1 + sizeof(uint32_t) )

The condition is a compile-time constant that should be optimized away.

The non-AVR code might be a challenge to the optimizer.
Whether this is better depends on the optimizer:
uint32_t retval=bytes[3];
retval<<=8;
retval|=bytes[2];
...
return retval;

If you don't mind restricting yourself to gcc,
you can use an extension to inquire about the alignment of uint32_t.
I think that you can also use an extension to specify a byte-aligned uint32_t,
but I'm not sure whether the extension will allow a decrease in alignment.
The most thorough way to do it is with the configuration script.
Test whether the short version crashes.
If it does, use the long version.
This will catch the case where unaligned uint32_t's can be handled by the hardware,
but the compiler won't generate them, probably because they are slow.

There is also the possibility of using the big code on platforms you don't recognize,
the small code on platforms on which it will work
and other code, possibly even inline assembler on other platforms.

Iluvatar is the better part of Valar.

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

kwr wrote:
Using gcc on both.

The "AVR" part of my example is not too big at all. Not worth it for me to do in assembly code. I would like to only support a single version of the code, however the code that will work on both CPUs (and x86, et. al.) is what comes out bad when compiled for AVR.

Maybe there is some way to write that code so the optimizer makes it turn out well. If there is a way, I have not found it.

You can use the attribute packed to make gcc fetch an unaligned 4-byte integer.
If the endianness is correct, you are done.

Iluvatar is the better part of Valar.