[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-libc-dev] Can pgmspace.h __LPM_xxx__ macros become inlinefn's?
From: |
Bill Somerville |
Subject: |
Re: [avr-libc-dev] Can pgmspace.h __LPM_xxx__ macros become inlinefn's? |
Date: |
Fri, 01 Oct 2004 03:44:48 +0100 |
"Theodore A. Roth" wrote:
>
> On Thu, 30 Sep 2004, Bill Somerville wrote:
>
> > > Those seem like pretty good reasons for switching to inline functions to
> > > me.
> > >
> > > If no one comes up with a strong reason against this, I have no
> > > major objections.
> > >
> > > My only (very weak) objection is that I've found that gdb can not step
> > > over an inlined function. That makes debugging a bit of a pain some
> > > times.
> >
> > True, but this is a problem with gdb!
>
> That's why it's a weak objection. ;-)
>
> >
> > >
> > > Although, other advantages are type checking and the ability to step
> > > through an inline function in the debugger when you need to see what it
> > > is doing.
> > >
> > > One nit: should the function definition be "static __inline__ ..."
> > > instead of just "__inline__ ..."?
> >
> > I'm not sure on this. The gcc man page implies that static is not
> > recommended and definitely not required when C99 inline semantics are
> > implemented. Perhaps the compiler guru's can give a definiitive answer.
>
> I don't see anywhere that using static is not recommended. Do you have a
> reference for that?
The penultimate para of the gcc man page "5.34 An Inline Function is As
Fast As a Macro" seemed to imply this, but after comments from Geoffrey
Wossum and some tests it seems that static __inline__ or extern
__inline__ are the only options in header files otherwise multiple
definitions occur.
Unfortunately this has become academic as I cannot get the inline fn's
to generate the same code as the macros, also the inline versions
sometimes are bigger. This seems to be an optimiser problem where the
register choices made around inlined fn's are not as smart as they might
be. I suspect this is a quite obscure gcc bug/feature. The gcc man page
says that inlines may generate different code from macros (both larger
and smaller).
Since I haven't found an example that generates smaller code, I suspect
that a community of embedded programmers are not going to be happy with
this change!
Here is a test program I used to show this issue:
#include <avr/io.h>
#include <avr/pgmspace.h>
static prog_uint8_t data[] = { 1, 2 };
int
main( void )
{
return pgm_read_byte( &data[0] ) + ( pgm_read_byte( &data[1] ) - (
pgm_read_byte( &data[1] ) >> 2 ) );
}
I compiled it for at90s8515 using -O2 with macros then with inlines and
got the following results:
Macros ->
===========================================================================================
src/lpm_test.elf-avr: file format elf32-avr
Disassembly of section .text:
00000000 <__vectors>:
0: 0e c0 rjmp .+28 ; 0x1e
2: 28 c0 rjmp .+80 ; 0x54
4: 27 c0 rjmp .+78 ; 0x54
6: 26 c0 rjmp .+76 ; 0x54
8: 25 c0 rjmp .+74 ; 0x54
a: 24 c0 rjmp .+72 ; 0x54
c: 23 c0 rjmp .+70 ; 0x54
e: 22 c0 rjmp .+68 ; 0x54
10: 21 c0 rjmp .+66 ; 0x54
12: 20 c0 rjmp .+64 ; 0x54
14: 1f c0 rjmp .+62 ; 0x54
16: 1e c0 rjmp .+60 ; 0x54
18: 1d c0 rjmp .+58 ; 0x54
0000001a <__ctors_end>:
1a: 01 02 muls r16, r17
1c: 03 04 cpc r0, r3
0000001e <__init>:
1e: 11 24 eor r1, r1
20: 1f be out 0x3f, r1 ; 63
22: cf e5 ldi r28, 0x5F ; 95
24: d2 e0 ldi r29, 0x02 ; 2
26: de bf out 0x3e, r29 ; 62
28: cd bf out 0x3d, r28 ; 61
0000002a <__do_copy_data>:
2a: 10 e0 ldi r17, 0x00 ; 0
2c: a0 e6 ldi r26, 0x60 ; 96
2e: b0 e0 ldi r27, 0x00 ; 0
30: e0 e8 ldi r30, 0x80 ; 128
32: f0 e0 ldi r31, 0x00 ; 0
34: 03 c0 rjmp .+6 ; 0x3c
00000036 <.do_copy_data_loop>:
36: c8 95 lpm
38: 31 96 adiw r30, 0x01 ; 1
3a: 0d 92 st X+, r0
0000003c <.do_copy_data_start>:
3c: a0 36 cpi r26, 0x60 ; 96
3e: b1 07 cpc r27, r17
40: d1 f7 brne .-12 ; 0x36
00000042 <__do_clear_bss>:
42: 10 e0 ldi r17, 0x00 ; 0
44: a0 e6 ldi r26, 0x60 ; 96
46: b0 e0 ldi r27, 0x00 ; 0
48: 01 c0 rjmp .+2 ; 0x4c
0000004a <.do_clear_bss_loop>:
4a: 1d 92 st X+, r1
0000004c <.do_clear_bss_start>:
4c: a0 36 cpi r26, 0x60 ; 96
4e: b1 07 cpc r27, r17
50: e1 f7 brne .-8 ; 0x4a
52: 01 c0 rjmp .+2 ; 0x56
00000054 <__bad_interrupt>:
54: d5 cf rjmp .-86 ; 0x0
00000056 <main>:
static prog_uint8_t data[] = { 1, 2, 3, 4 };
int
main( void )
{
56: cf e5 ldi r28, 0x5F ; 95
58: d2 e0 ldi r29, 0x02 ; 2
5a: de bf out 0x3e, r29 ; 62
5c: cd bf out 0x3d, r28 ; 61
return pgm_read_byte( &data[0] ) + ( pgm_read_byte( &data[1] ) - (
pgm_read_byte( &data[1] ) >> 2 ) );
5e: ea e1 ldi r30, 0x1A ; 26
60: f0 e0 ldi r31, 0x00 ; 0
62: c8 95 lpm
64: 30 2d mov r19, r0
66: 31 96 adiw r30, 0x01 ; 1
68: c8 95 lpm
6a: 20 2d mov r18, r0
6c: 82 2f mov r24, r18
6e: 99 27 eor r25, r25
70: 26 95 lsr r18
72: 26 95 lsr r18
74: 82 1b sub r24, r18
76: 91 09 sbc r25, r1
}
78: 83 0f add r24, r19
7a: 91 1d adc r25, r1
7c: 00 c0 rjmp .+0 ; 0x7e
0000007e <_exit>:
7e: ff cf rjmp .-2 ; 0x7e
================================================================================================
Inlines ->
================================================================================================
src/lpm_test.elf-avr: file format elf32-avr
Disassembly of section .text:
00000000 <__vectors>:
0: 0e c0 rjmp .+28 ; 0x1e
2: 28 c0 rjmp .+80 ; 0x54
4: 27 c0 rjmp .+78 ; 0x54
6: 26 c0 rjmp .+76 ; 0x54
8: 25 c0 rjmp .+74 ; 0x54
a: 24 c0 rjmp .+72 ; 0x54
c: 23 c0 rjmp .+70 ; 0x54
e: 22 c0 rjmp .+68 ; 0x54
10: 21 c0 rjmp .+66 ; 0x54
12: 20 c0 rjmp .+64 ; 0x54
14: 1f c0 rjmp .+62 ; 0x54
16: 1e c0 rjmp .+60 ; 0x54
18: 1d c0 rjmp .+58 ; 0x54
0000001a <__ctors_end>:
1a: 01 02 muls r16, r17
1c: 03 04 cpc r0, r3
0000001e <__init>:
1e: 11 24 eor r1, r1
20: 1f be out 0x3f, r1 ; 63
22: cf e5 ldi r28, 0x5F ; 95
24: d2 e0 ldi r29, 0x02 ; 2
26: de bf out 0x3e, r29 ; 62
28: cd bf out 0x3d, r28 ; 61
0000002a <__do_copy_data>:
2a: 10 e0 ldi r17, 0x00 ; 0
2c: a0 e6 ldi r26, 0x60 ; 96
2e: b0 e0 ldi r27, 0x00 ; 0
30: e4 e8 ldi r30, 0x84 ; 132
32: f0 e0 ldi r31, 0x00 ; 0
34: 03 c0 rjmp .+6 ; 0x3c
00000036 <.do_copy_data_loop>:
36: c8 95 lpm
38: 31 96 adiw r30, 0x01 ; 1
3a: 0d 92 st X+, r0
0000003c <.do_copy_data_start>:
3c: a0 36 cpi r26, 0x60 ; 96
3e: b1 07 cpc r27, r17
40: d1 f7 brne .-12 ; 0x36
00000042 <__do_clear_bss>:
42: 10 e0 ldi r17, 0x00 ; 0
44: a0 e6 ldi r26, 0x60 ; 96
46: b0 e0 ldi r27, 0x00 ; 0
48: 01 c0 rjmp .+2 ; 0x4c
0000004a <.do_clear_bss_loop>:
4a: 1d 92 st X+, r1
0000004c <.do_clear_bss_start>:
4c: a0 36 cpi r26, 0x60 ; 96
4e: b1 07 cpc r27, r17
50: e1 f7 brne .-8 ; 0x4a
52: 01 c0 rjmp .+2 ; 0x56
00000054 <__bad_interrupt>:
54: d5 cf rjmp .-86 ; 0x0
00000056 <main>:
static prog_uint8_t data[] = { 1, 2, 3, 4 };
int
main( void )
{
56: cf e5 ldi r28, 0x5F ; 95
58: d2 e0 ldi r29, 0x02 ; 2
5a: de bf out 0x3e, r29 ; 62
5c: cd bf out 0x3d, r28 ; 61
uint8_t
__LPM_classic__ (prog_uint8_t const * const __addr)
{
uint8_t __result;
__asm__
5e: ea e1 ldi r30, 0x1A ; 26
60: f0 e0 ldi r31, 0x00 ; 0
62: c8 95 lpm
64: 40 2d mov r20, r0
66: 31 96 adiw r30, 0x01 ; 1
68: c8 95 lpm
6a: 80 2d mov r24, r0
6c: 28 2f mov r18, r24
6e: 33 27 eor r19, r19
70: 82 2f mov r24, r18
72: 99 27 eor r25, r25
74: 26 95 lsr r18
76: 26 95 lsr r18
78: 82 1b sub r24, r18
7a: 91 09 sbc r25, r1
return pgm_read_byte( &data[0] ) + ( pgm_read_byte( &data[1] ) - (
pgm_read_byte( &data[1] ) >> 2 ) );
}
7c: 84 0f add r24, r20
7e: 91 1d adc r25, r1
80: 00 c0 rjmp .+0 ; 0x82
00000082 <_exit>:
82: ff cf rjmp .-2 ; 0x82
================================================================================================
In the inline version the second LPM result does an unnecessary register
shuffle that the macro version avoids. Note that the first LPM is OK so
the compiler can get it right sometimes.
>
> ---
> Ted Roth
> PGP Key ID: 0x18F846E9
> Jabber ID: address@hidden
Bill Somerville
Index: include/avr/pgmspace.h
===================================================================
RCS file: /cvsroot/avr-libc/avr-libc/include/avr/pgmspace.h,v
retrieving revision 1.22
diff -u -r1.22 pgmspace.h
--- include/avr/pgmspace.h 19 Sep 2004 19:11:06 -0000 1.22
+++ include/avr/pgmspace.h 1 Oct 2004 02:27:33 -0000
@@ -81,6 +81,10 @@
#define __ATTR_PURE__ __attribute__((__pure__))
#endif
+#ifndef __ATTR_ALWAYS_INLINE__
+#define __ATTR_ALWAYS_INLINE__ __attribute__((__always_inline__))
+#endif
+
#define PROGMEM __ATTR_PROGMEM__
#ifdef __cplusplus
@@ -121,105 +125,123 @@
#define PSTR(s) ({static char __c[] PROGMEM = (s); &__c[0];})
-#define __LPM_classic__(addr) \
-({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint8_t __result; \
- __asm__ \
- ( \
- "lpm" "\n\t" \
- "mov %0, r0" "\n\t" \
- : "=r" (__result) \
- : "z" (__addr16) \
- : "r0" \
- ); \
- __result; \
-})
+static __inline__ uint8_t __LPM_classic__ (prog_uint8_t const * const
__addr) __ATTR_ALWAYS_INLINE__;
+static __inline__ uint8_t __LPM_enhanced__ (prog_uint8_t const * const
__addr) __ATTR_ALWAYS_INLINE__;
+static __inline__ uint16_t __LPM_word_classic__ (prog_uint16_t const *
__addr) __ATTR_ALWAYS_INLINE__;
+static __inline__ uint16_t __LPM_word_enhanced__ (prog_uint16_t const *
__addr) __ATTR_ALWAYS_INLINE__;
+
+static __inline__
+uint8_t
+__LPM_classic__ (prog_uint8_t const * const __addr)
+{
+ uint8_t __result;
+ __asm__
+ (
+ "lpm" "\n\t"
+ "mov %0, r0" "\n\t"
+ : "=r" (__result)
+ : "z" (__addr)
+ : "r0"
+ );
+ return __result;
+}
-#define __LPM_enhanced__(addr) \
-({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint8_t __result; \
- __asm__ \
- ( \
- "lpm %0, Z" "\n\t" \
- : "=r" (__result) \
- : "z" (__addr16) \
- ); \
- __result; \
-})
+static __inline__
+uint8_t
+__LPM_enhanced__ (prog_uint8_t const * const __addr)
+{
+ uint8_t __result;
+ __asm__
+ (
+ "lpm %0, Z" "\n\t"
+ : "=r" (__result)
+ : "z" (__addr)
+ );
+ return __result;
+}
-#define __LPM_word_classic__(addr) \
-({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint16_t __result; \
- __asm__ \
- ( \
- "lpm" "\n\t" \
- "mov %A0, r0" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "lpm" "\n\t" \
- "mov %B0, r0" "\n\t" \
- : "=r" (__result), "=z" (__addr16) \
- : "1" (__addr16) \
- : "r0" \
- ); \
- __result; \
-})
+static __inline__
+uint16_t
+__LPM_word_classic__ (prog_uint16_t const * __addr)
+{
+ uint16_t __result;
+ __asm__
+ (
+ "lpm" "\n\t"
+ "mov %A0, r0" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "lpm" "\n\t"
+ "mov %B0, r0" "\n\t"
+ : "=r" (__result), "=z" (__addr)
+ : "1" (__addr)
+ : "r0"
+ );
+ return __result;
+}
-#define __LPM_word_enhanced__(addr) \
-({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint16_t __result; \
- __asm__ \
- ( \
- "lpm %A0, Z+" "\n\t" \
- "lpm %B0, Z" "\n\t" \
- : "=r" (__result), "=z" (__addr16) \
- : "1" (__addr16) \
- ); \
- __result; \
-})
+static __inline__
+uint16_t
+__LPM_word_enhanced__ (prog_uint16_t const * __addr)
+{
+ uint16_t __result;
+ __asm__
+ (
+ "lpm %A0, Z+" "\n\t"
+ "lpm %B0, Z" "\n\t"
+ : "=r" (__result), "=z" (__addr)
+ : "1" (__addr)
+ );
+ return __result;
+}
-#define __LPM_dword_classic__(addr) \
-({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint32_t __result; \
- __asm__ \
- ( \
- "lpm" "\n\t" \
- "mov %A0, r0" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "lpm" "\n\t" \
- "mov %B0, r0" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "lpm" "\n\t" \
- "mov %C0, r0" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "lpm" "\n\t" \
- "mov %D0, r0" "\n\t" \
- : "=r" (__result), "=z" (__addr16) \
- : "1" (__addr16) \
- : "r0" \
- ); \
- __result; \
-})
+#if defined(__HAS_INT32_T__)
-#define __LPM_dword_enhanced__(addr) \
-({ \
- uint16_t __addr16 = (uint16_t)(addr); \
- uint32_t __result; \
- __asm__ \
- ( \
- "lpm %A0, Z+" "\n\t" \
- "lpm %B0, Z+" "\n\t" \
- "lpm %C0, Z+" "\n\t" \
- "lpm %D0, Z" "\n\t" \
- : "=r" (__result), "=z" (__addr16) \
- : "1" (__addr16) \
- ); \
- __result; \
-})
+static __inline__ uint32_t __LPM_dword_classic__ (prog_uint32_t const *
__addr) __ATTR_ALWAYS_INLINE__;
+static __inline__ uint32_t __LPM_dword_enhanced__ (prog_uint32_t const
* __addr) __ATTR_ALWAYS_INLINE__;
+
+static __inline__
+uint32_t
+__LPM_dword_classic__ (prog_uint32_t const * __addr)
+{
+ uint32_t __result;
+ __asm__
+ (
+ "lpm" "\n\t"
+ "mov %A0, r0" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "lpm" "\n\t"
+ "mov %B0, r0" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "lpm" "\n\t"
+ "mov %C0, r0" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "lpm" "\n\t"
+ "mov %D0, r0" "\n\t"
+ : "=r" (__result), "=z" (__addr)
+ : "1" (__addr)
+ : "r0"
+ );
+ return __result;
+}
+
+static __inline__
+uint32_t
+__LPM_dword_enhanced__ (prog_uint32_t const * __addr)
+{
+ uint32_t __result;
+ __asm__
+ (
+ "lpm %A0, Z+" "\n\t"
+ "lpm %B0, Z+" "\n\t"
+ "lpm %C0, Z+" "\n\t"
+ "lpm %D0, Z" "\n\t"
+ : "=r" (__result), "=z" (__addr)
+ : "1" (__addr)
+ );
+ return __result;
+}
+
+#endif /* __HAS_INT32_T__ */
#if defined (__AVR_ENHANCED__)
#define __LPM(addr) __LPM_enhanced__(addr)
@@ -237,7 +259,7 @@
\note The address is a byte address.
The address is in the program space. */
-#define pgm_read_byte_near(address_short)
__LPM((uint16_t)(address_short))
+#define pgm_read_byte_near(address_short) (uint8_t)__LPM(address_short)
/** \ingroup avr_pgmspace
\def pgm_read_word_near(address_short)
@@ -245,7 +267,7 @@
\note The address is a byte address.
The address is in the program space. */
-#define pgm_read_word_near(address_short)
__LPM_word((uint16_t)(address_short))
+#define pgm_read_word_near(address_short) __LPM_word(address_short)
/** \ingroup avr_pgmspace
\def pgm_read_dword_near(address_short)
@@ -253,8 +275,7 @@
\note The address is a byte address.
The address is in the program space. */
-#define pgm_read_dword_near(address_short) \
- __LPM_dword((uint16_t)(address_short))
+#define pgm_read_dword_near(address_short) __LPM_dword(address_short)
#if defined(RAMPZ) && !defined(__USING_MINT8)
@@ -266,140 +287,153 @@
/* The classic functions are needed for ATmega103. */
-#define __ELPM_classic__(addr) \
-({ \
- uint32_t __addr32 = (uint32_t)(addr); \
- uint8_t __result; \
- __asm__ \
- ( \
- "out %2, %C1" "\n\t" \
- "mov r31, %B1" "\n\t" \
- "mov r30, %A1" "\n\t" \
- "elpm" "\n\t" \
- "mov %0, r0" "\n\t" \
- : "=r" (__result) \
- : "r" (__addr32), \
- "I" (_SFR_IO_ADDR(RAMPZ)) \
- : "r0", "r30", "r31" \
- ); \
- __result; \
-})
+static __inline__ uint8_t __ELPM_classic__ (uint32_t __addr)
__ATTR_ALWAYS_INLINE__;
+static __inline__ uint8_t __ELPM_enhanced__ (uint32_t __addr)
__ATTR_ALWAYS_INLINE__;
+static __inline__ uint16_t __ELPM_word_classic__ (uint32_t __addr)
__ATTR_ALWAYS_INLINE__;
+static __inline__ uint16_t __ELPM_word_enhanced__ (uint32_t __addr)
__ATTR_ALWAYS_INLINE__;
+static __inline__ uint32_t __ELPM_dword_classic__ (uint32_t __addr)
__ATTR_ALWAYS_INLINE__;
+static __inline__ uint32_t __ELPM_dword_enhanced__ (uint32_t __addr)
__ATTR_ALWAYS_INLINE__;
+
+static __inline__
+uint8_t
+__ELPM_classic__ (uint32_t __addr)
+{
+ uint8_t __result;
+ __asm__
+ (
+ "out %2, %C1" "\n\t"
+ "mov r31, %B1" "\n\t"
+ "mov r30, %A1" "\n\t"
+ "elpm" "\n\t"
+ "mov %0, r0" "\n\t"
+ : "=r" (__result)
+ : "r" (__addr),
+ "I" (_SFR_IO_ADDR(RAMPZ))
+ : "r0", "r30", "r31"
+ );
+ return __result;
+}
-#define __ELPM_enhanced__(addr) \
-({ \
- uint32_t __addr32 = (uint32_t)(addr); \
- uint8_t __result; \
- __asm__ \
- ( \
- "out %2, %C1" "\n\t" \
- "movw r30, %1" "\n\t" \
- "elpm %0, Z+" "\n\t" \
- : "=r" (__result) \
- : "r" (__addr32), \
- "I" (_SFR_IO_ADDR(RAMPZ)) \
- : "r30", "r31" \
- ); \
- __result; \
-})
+static __inline__
+uint8_t
+__ELPM_enhanced__ (uint32_t __addr)
+{
+ uint8_t __result;
+ __asm__
+ (
+ "out %2, %C1" "\n\t"
+ "movw r30, %1" "\n\t"
+ "elpm %0, Z+" "\n\t"
+ : "=r" (__result)
+ : "r" (__addr),
+ "I" (_SFR_IO_ADDR(RAMPZ))
+ : "r30", "r31"
+ );
+ return __result;
+}
-#define __ELPM_word_classic__(addr) \
-({ \
- uint32_t __addr32 = (uint32_t)(addr); \
- uint16_t __result; \
- __asm__ \
- ( \
- "out %2, %C1" "\n\t" \
- "mov r31, %B1" "\n\t" \
- "mov r30, %A1" "\n\t" \
- "elpm" "\n\t" \
- "mov %A0, r0" "\n\t" \
- "in r0, %2" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "adc r0, __zero_reg__" "\n\t" \
- "out %2, r0" "\n\t" \
- "elpm" "\n\t" \
- "mov %B0, r0" "\n\t" \
- : "=r" (__result) \
- : "r" (__addr32), \
- "I" (_SFR_IO_ADDR(RAMPZ)) \
- : "r0", "r30", "r31" \
- ); \
- __result; \
-})
+static __inline__
+uint16_t
+__ELPM_word_classic__ (uint32_t __addr)
+{
+ uint16_t __result;
+ __asm__
+ (
+ "out %2, %C1" "\n\t"
+ "mov r31, %B1" "\n\t"
+ "mov r30, %A1" "\n\t"
+ "elpm" "\n\t"
+ "mov %A0, r0" "\n\t"
+ "in r0, %2" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "adc r0, __zero_reg__" "\n\t"
+ "out %2, r0" "\n\t"
+ "elpm" "\n\t"
+ "mov %B0, r0" "\n\t"
+ : "=r" (__result)
+ : "r" (__addr),
+ "I" (_SFR_IO_ADDR(RAMPZ))
+ : "r0", "r30", "r31"
+ );
+ return __result;
+}
-#define __ELPM_word_enhanced__(addr) \
-({ \
- uint32_t __addr32 = (uint32_t)(addr); \
- uint16_t __result; \
- __asm__ \
- ( \
- "out %2, %C1" "\n\t" \
- "movw r30, %1" "\n\t" \
- "elpm %A0, Z+" "\n\t" \
- "elpm %B0, Z" "\n\t" \
- : "=r" (__result) \
- : "r" (__addr32), \
- "I" (_SFR_IO_ADDR(RAMPZ)) \
- : "r30", "r31" \
- ); \
- __result; \
-})
+static __inline__
+uint16_t
+__ELPM_word_enhanced__ (uint32_t __addr)
+{
+ uint16_t __result;
+ __asm__
+ (
+ "out %2, %C1" "\n\t"
+ "movw r30, %1" "\n\t"
+ "elpm %A0, Z+" "\n\t"
+ "elpm %B0, Z" "\n\t"
+ : "=r" (__result)
+ : "r" (__addr),
+ "I" (_SFR_IO_ADDR(RAMPZ))
+ : "r30", "r31"
+ );
+ return __result;
+}
-#define __ELPM_dword_classic__(addr) \
-({ \
- uint32_t __addr32 = (uint32_t)(addr); \
- uint32_t __result; \
- __asm__ \
- ( \
- "out %2, %C1" "\n\t" \
- "mov r31, %B1" "\n\t" \
- "mov r30, %A1" "\n\t" \
- "elpm" "\n\t" \
- "mov %A0, r0" "\n\t" \
- "in r0, %2" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "adc r0, __zero_reg__" "\n\t" \
- "out %2, r0" "\n\t" \
- "elpm" "\n\t" \
- "mov %B0, r0" "\n\t" \
- "in r0, %2" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "adc r0, __zero_reg__" "\n\t" \
- "out %2, r0" "\n\t" \
- "elpm" "\n\t" \
- "mov %C0, r0" "\n\t" \
- "in r0, %2" "\n\t" \
- "adiw r30, 1" "\n\t" \
- "adc r0, __zero_reg__" "\n\t" \
- "out %2, r0" "\n\t" \
- "elpm" "\n\t" \
- "mov %D0, r0" "\n\t" \
- : "=r" (__result) \
- : "r" (__addr32), \
- "I" (_SFR_IO_ADDR(RAMPZ)) \
- : "r0", "r30", "r31" \
- ); \
- __result; \
-})
+static __inline__
+uint32_t
+__ELPM_dword_classic__ (uint32_t __addr)
+{
+ uint32_t __result;
+ __asm__
+ (
+ "out %2, %C1" "\n\t"
+ "mov r31, %B1" "\n\t"
+ "mov r30, %A1" "\n\t"
+ "elpm" "\n\t"
+ "mov %A0, r0" "\n\t"
+ "in r0, %2" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "adc r0, __zero_reg__" "\n\t"
+ "out %2, r0" "\n\t"
+ "elpm" "\n\t"
+ "mov %B0, r0" "\n\t"
+ "in r0, %2" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "adc r0, __zero_reg__" "\n\t"
+ "out %2, r0" "\n\t"
+ "elpm" "\n\t"
+ "mov %C0, r0" "\n\t"
+ "in r0, %2" "\n\t"
+ "adiw r30, 1" "\n\t"
+ "adc r0, __zero_reg__" "\n\t"
+ "out %2, r0" "\n\t"
+ "elpm" "\n\t"
+ "mov %D0, r0" "\n\t"
+ : "=r" (__result)
+ : "r" (__addr),
+ "I" (_SFR_IO_ADDR(RAMPZ))
+ : "r0", "r30", "r31"
+ );
+ return __result;
+}
-#define __ELPM_dword_enhanced__(addr) \
-({ \
- uint32_t __addr32 = (uint32_t)(addr); \
- uint32_t __result; \
- __asm__ \
- ( \
- "out %2, %C1" "\n\t" \
- "movw r30, %1" "\n\t" \
- "elpm %A0, Z+" "\n\t" \
- "elpm %B0, Z+" "\n\t" \
- "elpm %C0, Z+" "\n\t" \
- "elpm %D0, Z" "\n\t" \
- : "=r" (__result) \
- : "r" (__addr32), \
- "I" (_SFR_IO_ADDR(RAMPZ)) \
- : "r30", "r31" \
- ); \
- __result; \
+static __inline__
+uint32_t
+__ELPM_dword_enhanced__ (uint32_t __addr)
+{
+ uint32_t __result;
+ __asm__
+ (
+ "out %2, %C1" "\n\t"
+ "movw r30, %1" "\n\t"
+ "elpm %A0, Z+" "\n\t"
+ "elpm %B0, Z+" "\n\t"
+ "elpm %C0, Z+" "\n\t"
+ "elpm %D0, Z" "\n\t"
+ : "=r" (__result)
+ : "r" (__addr),
+ "I" (_SFR_IO_ADDR(RAMPZ))
+ : "r30", "r31"
+ );
+ return __result;
})
#if defined (__AVR_ENHANCED__)
@@ -419,7 +453,7 @@
\note The address is a byte address.
The address is in the program space. */
-#define pgm_read_byte_far(address_long)
__ELPM((uint32_t)(address_long))
+#define pgm_read_byte_far(address_long) __ELPM(address_long)
/** \ingroup avr_pgmspace
\def pgm_read_word_far(address_long)
@@ -428,7 +462,7 @@
\note The address is a byte address.
The address is in the program space. */
-#define pgm_read_word_far(address_long)
__ELPM_word((uint32_t)(address_long))
+#define pgm_read_word_far(address_long) __ELPM_word(address_long)
/** \ingroup avr_pgmspace
\def pgm_read_dword_far(address_long)
@@ -437,7 +471,7 @@
\note The address is a byte address.
The address is in the program space. */
-#define pgm_read_dword_far(address_long)
__ELPM_dword((uint32_t)(address_long))
+#define pgm_read_dword_far(address_long) __ELPM_dword(address_long)
#endif /* RAMPZ and ! __USING_MINT8 */
RE: [avr-libc-dev] Can pgmspace.h __LPM_xxx__ macros become inlinefn's?, Bernard Fouche, 2004/09/30
Re: [avr-libc-dev] Can pgmspace.h __LPM_xxx__ macros become inlinefn's?, Bill Somerville, 2004/09/30
Re: [avr-libc-dev] Can pgmspace.h __LPM_xxx__ macros become inline fn's?, Theodore A. Roth, 2004/09/30