[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-libc-dev] Suggested improvement to <avr/pgmspace.h>
From: |
George Spelvin |
Subject: |
Re: [avr-libc-dev] Suggested improvement to <avr/pgmspace.h> |
Date: |
2 Jan 2017 13:26:45 -0500 |
> 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.)