> I started with a simple "hello world" program that outputs a 
> NUL-terminated string to the UART:
>
> static void msg(const char* PROGMEM msg)
> {
>   char c;
>   while ((c = pgm_read_byte_postinc (&msg))) {
>     UDR0 = c;
>     loop_until_bit_is_set(UCSR0A, UDRE0);
>   }
> }
> 
> For optimal AVR implementation, this would require some inline assembly:

You could also try using a compiler feature and skipping the pgm_read
function entirely.

static void msg(const char __flash *msg)
{
  char c;
  while ((c = *msg++)) {
    UDR0 = c;
    loop_until_bit_is_set(UCSR0A, UDRE0);
  }
}

Of course, GCC is generating terrible code for me on this (not only
is it not using Z+, it's copying the pointer to a different register to
increment it and using a subi/sbci sequence to do it), but it's definitely
more legible source code.

I also wonder if we could do something like:

static inline char pgm_read_byte(char const * PROGMEM p)
{
        char c;
        asm("lpm %0,%1" : "=r" (c) : "m<>" (*p));
        return c;
}

which would tell GCC how to make "pgm_read_byte(msg++)" use
a postincrement addressing mode, without having to add another
function.


(We should also update inttypes.h and pgmspace.h to use
__int24/__uint24 for far addresses.)

_______________________________________________
AVR-libc-dev mailing list
AVR-libc-dev@nongnu.org
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev

Reply via email to