source: rtems/cpukit/score/cpu/avr/avr/pgmspace.h @ 04a62dce

4.104.11
Last change on this file since 04a62dce was 04a62dce, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 6, 2009 at 2:52:07 PM

2009-08-05 Josh Switnicki <josh.switnicki@…>

  • Makefile.am: added AVR specific Header files to score/cpu/avr/avr. These are from avr-libc 1.6 and assumed to exist by AVR applications.
  • preinstall.am: Regenerated.
  • Property mode set to 100644
File size: 30.6 KB
Line 
1/* Copyright (c) 2002 - 2007  Marek Michalkiewicz
2   All rights reserved.
3
4   Redistribution and use in source and binary forms, with or without
5   modification, are permitted provided that the following conditions are met:
6
7   * Redistributions of source code must retain the above copyright
8     notice, this list of conditions and the following disclaimer.
9   * Redistributions in binary form must reproduce the above copyright
10     notice, this list of conditions and the following disclaimer in
11     the documentation and/or other materials provided with the
12     distribution.
13   * Neither the name of the copyright holders nor the names of
14     contributors may be used to endorse or promote products derived
15     from this software without specific prior written permission.
16
17  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  POSSIBILITY OF SUCH DAMAGE. */
28
29/* $Id$ */
30
31/*
32   pgmspace.h
33
34   Contributors:
35     Created by Marek Michalkiewicz <marekm@linux.org.pl>
36     Eric B. Weddington <eric@ecentral.com>
37     Wolfgang Haidinger <wh@vmars.tuwien.ac.at> (pgm_read_dword())
38     Ivanov Anton <anton@arc.com.ru> (pgm_read_float())
39 */
40
41/** \file */
42/** \defgroup avr_pgmspace <avr/pgmspace.h>: Program Space Utilities
43    \code
44    #include <avr/io.h>
45    #include <avr/pgmspace.h>
46    \endcode
47
48    The functions in this module provide interfaces for a program to access
49    data stored in program space (flash memory) of the device.  In order to
50    use these functions, the target device must support either the \c LPM or
51    \c ELPM instructions.
52
53    \note These functions are an attempt to provide some compatibility with
54    header files that come with IAR C, to make porting applications between
55    different compilers easier.  This is not 100% compatibility though (GCC
56    does not have full support for multiple address spaces yet).
57
58    \note If you are working with strings which are completely based in ram,
59    use the standard string functions described in \ref avr_string.
60
61    \note If possible, put your constant tables in the lower 64 KB and use
62    pgm_read_byte_near() or pgm_read_word_near() instead of
63    pgm_read_byte_far() or pgm_read_word_far() since it is more efficient that
64    way, and you can still use the upper 64K for executable code.
65    All functions that are suffixed with a \c _P \e require their
66    arguments to be in the lower 64 KB of the flash ROM, as they do
67    not use ELPM instructions.  This is normally not a big concern as
68    the linker setup arranges any program space constants declared
69    using the macros from this header file so they are placed right after
70    the interrupt vectors, and in front of any executable code.  However,
71    it can become a problem if there are too many of these constants, or
72    for bootloaders on devices with more than 64 KB of ROM.
73    <em>All these functions will not work in that situation.</em>
74*/
75
76#ifndef __PGMSPACE_H_
77#define __PGMSPACE_H_ 1
78
79#define __need_size_t
80#include <inttypes.h>
81#include <stddef.h>
82#include <avr/io.h>
83
84#ifndef __ATTR_CONST__
85#define __ATTR_CONST__ __attribute__((__const__))
86#endif
87
88#ifndef __ATTR_PROGMEM__
89#define __ATTR_PROGMEM__ __attribute__((__progmem__))
90#endif
91
92#ifndef __ATTR_PURE__
93#define __ATTR_PURE__ __attribute__((__pure__))
94#endif
95
96/**
97   \ingroup avr_pgmspace
98   \def PROGMEM
99
100   Attribute to use in order to declare an object being located in
101   flash ROM.
102 */
103#define PROGMEM __ATTR_PROGMEM__
104
105#ifdef __cplusplus
106extern "C" {
107#endif
108
109#if defined(__DOXYGEN__)
110/*
111 * Doxygen doesn't grok the appended attribute syntax of
112 * GCC, and confuses the typedefs with function decls, so
113 * supply a doxygen-friendly view.
114 */
115/**
116   \ingroup avr_pgmspace
117   \typedef prog_void
118
119   Type of a "void" object located in flash ROM.  Does not make much
120   sense by itself, but can be used to declare a "void *" object in
121   flash ROM.
122*/
123typedef void PROGMEM prog_void;
124/**
125   \ingroup avr_pgmspace
126   \typedef prog_char
127
128   Type of a "char" object located in flash ROM.
129*/
130typedef char PROGMEM prog_char;
131
132/**
133   \ingroup avr_pgmspace
134   \typedef prog_uchar
135
136   Type of an "unsigned char" object located in flash ROM.
137*/
138typedef unsigned char PROGMEM prog_uchar;
139
140
141/**
142   \ingroup avr_pgmspace
143   \typedef prog_int8_t
144
145   Type of an "int8_t" object located in flash ROM.
146*/
147typedef int8_t PROGMEM prog_int8_t;
148
149/**
150   \ingroup avr_pgmspace
151   \typedef prog_uint8_t
152
153   Type of an "uint8_t" object located in flash ROM.
154*/
155typedef uint8_t PROGMEM prog_uint8_t;
156
157/**
158   \ingroup avr_pgmspace
159   \typedef prog_int16_t
160
161   Type of an "int16_t" object located in flash ROM.
162*/
163typedef int16_t PROGMEM prog_int16_t;
164
165/**
166   \ingroup avr_pgmspace
167   \typedef prog_uint16_t
168
169   Type of an "uint16_t" object located in flash ROM.
170*/
171typedef uint16_t PROGMEM prog_uint16_t;
172
173/**
174   \ingroup avr_pgmspace
175   \typedef prog_int32_t
176
177   Type of an "int32_t" object located in flash ROM.
178*/
179typedef int32_t PROGMEM prog_int32_t;
180
181/**
182   \ingroup avr_pgmspace
183   \typedef prog_uint32_t
184
185   Type of an "uint32_t" object located in flash ROM.
186*/
187typedef uint32_t PROGMEM prog_uint32_t;
188
189/**
190   \ingroup avr_pgmspace
191   \typedef prog_int64_t
192
193   Type of an "int64_t" object located in flash ROM.
194
195   \note This type is not available when the compiler
196   option -mint8 is in effect.
197*/
198typedef int64_t PROGMEM prog_int64_t;
199
200/**
201   \ingroup avr_pgmspace
202   \typedef prog_uint64_t
203
204   Type of an "uint64_t" object located in flash ROM.
205
206   \note This type is not available when the compiler
207   option -mint8 is in effect.
208*/
209typedef uint64_t PROGMEM prog_uint64_t;
210#else  /* !DOXYGEN */
211typedef void prog_void PROGMEM;
212typedef char prog_char PROGMEM;
213typedef unsigned char prog_uchar PROGMEM;
214
215typedef int8_t    prog_int8_t   PROGMEM;
216typedef uint8_t   prog_uint8_t  PROGMEM;
217typedef int16_t   prog_int16_t  PROGMEM;
218typedef uint16_t  prog_uint16_t PROGMEM;
219typedef int32_t   prog_int32_t  PROGMEM;
220typedef uint32_t  prog_uint32_t PROGMEM;
221#if !__USING_MINT8
222typedef int64_t   prog_int64_t  PROGMEM;
223typedef uint64_t  prog_uint64_t PROGMEM;
224#endif
225#endif /* defined(__DOXYGEN__) */
226
227/* Although in C, we can get away with just using __c, it does not work in
228   C++. We need to use &__c[0] to avoid the compiler puking. Dave Hylands
229   explaned it thusly,
230
231     Let's suppose that we use PSTR("Test"). In this case, the type returned
232     by __c is a prog_char[5] and not a prog_char *. While these are
233     compatible, they aren't the same thing (especially in C++). The type
234     returned by &__c[0] is a prog_char *, which explains why it works
235     fine. */
236
237#if defined(__DOXYGEN__)
238/*
239 * The #define below is just a dummy that serves documentation
240 * purposes only.
241 */
242/** \ingroup avr_pgmspace
243    \def PSTR(s)
244
245    Used to declare a static pointer to a string in program space. */
246# define PSTR(s) ((const PROGMEM char *)(s))
247#else  /* !DOXYGEN */
248/* The real thing. */
249# define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))
250#endif /* DOXYGEN */
251
252#define __LPM_classic__(addr)   \
253(__extension__({                \
254    uint16_t __addr16 = (uint16_t)(addr); \
255    uint8_t __result;           \
256    __asm__                     \
257    (                           \
258        "lpm" "\n\t"            \
259        "mov %0, r0" "\n\t"     \
260        : "=r" (__result)       \
261        : "z" (__addr16)        \
262        : "r0"                  \
263    );                          \
264    __result;                   \
265}))
266
267#define __LPM_enhanced__(addr)  \
268(__extension__({                \
269    uint16_t __addr16 = (uint16_t)(addr); \
270    uint8_t __result;           \
271    __asm__                     \
272    (                           \
273        "lpm %0, Z" "\n\t"      \
274        : "=r" (__result)       \
275        : "z" (__addr16)        \
276    );                          \
277    __result;                   \
278}))
279
280#define __LPM_word_classic__(addr)          \
281(__extension__({                            \
282    uint16_t __addr16 = (uint16_t)(addr);   \
283    uint16_t __result;                      \
284    __asm__                                 \
285    (                                       \
286        "lpm"           "\n\t"              \
287        "mov %A0, r0"   "\n\t"              \
288        "adiw r30, 1"   "\n\t"              \
289        "lpm"           "\n\t"              \
290        "mov %B0, r0"   "\n\t"              \
291        : "=r" (__result), "=z" (__addr16)  \
292        : "1" (__addr16)                    \
293        : "r0"                              \
294    );                                      \
295    __result;                               \
296}))
297
298#define __LPM_word_enhanced__(addr)         \
299(__extension__({                            \
300    uint16_t __addr16 = (uint16_t)(addr);   \
301    uint16_t __result;                      \
302    __asm__                                 \
303    (                                       \
304        "lpm %A0, Z+"   "\n\t"              \
305        "lpm %B0, Z"    "\n\t"              \
306        : "=r" (__result), "=z" (__addr16)  \
307        : "1" (__addr16)                    \
308    );                                      \
309    __result;                               \
310}))
311
312#define __LPM_dword_classic__(addr)         \
313(__extension__({                            \
314    uint16_t __addr16 = (uint16_t)(addr);   \
315    uint32_t __result;                      \
316    __asm__                                 \
317    (                                       \
318        "lpm"           "\n\t"              \
319        "mov %A0, r0"   "\n\t"              \
320        "adiw r30, 1"   "\n\t"              \
321        "lpm"           "\n\t"              \
322        "mov %B0, r0"   "\n\t"              \
323        "adiw r30, 1"   "\n\t"              \
324        "lpm"           "\n\t"              \
325        "mov %C0, r0"   "\n\t"              \
326        "adiw r30, 1"   "\n\t"              \
327        "lpm"           "\n\t"              \
328        "mov %D0, r0"   "\n\t"              \
329        : "=r" (__result), "=z" (__addr16)  \
330        : "1" (__addr16)                    \
331        : "r0"                              \
332    );                                      \
333    __result;                               \
334}))
335
336#define __LPM_dword_enhanced__(addr)        \
337(__extension__({                            \
338    uint16_t __addr16 = (uint16_t)(addr);   \
339    uint32_t __result;                      \
340    __asm__                                 \
341    (                                       \
342        "lpm %A0, Z+"   "\n\t"              \
343        "lpm %B0, Z+"   "\n\t"              \
344        "lpm %C0, Z+"   "\n\t"              \
345        "lpm %D0, Z"    "\n\t"              \
346        : "=r" (__result), "=z" (__addr16)  \
347        : "1" (__addr16)                    \
348    );                                      \
349    __result;                               \
350}))
351
352#define __LPM_float_classic__(addr)         \
353(__extension__({                            \
354    uint16_t __addr16 = (uint16_t)(addr);   \
355    float __result;                         \
356    __asm__                                 \
357    (                                       \
358        "lpm"           "\n\t"              \
359        "mov %A0, r0"   "\n\t"              \
360        "adiw r30, 1"   "\n\t"              \
361        "lpm"           "\n\t"              \
362        "mov %B0, r0"   "\n\t"              \
363        "adiw r30, 1"   "\n\t"              \
364        "lpm"           "\n\t"              \
365        "mov %C0, r0"   "\n\t"              \
366        "adiw r30, 1"   "\n\t"              \
367        "lpm"           "\n\t"              \
368        "mov %D0, r0"   "\n\t"              \
369        : "=r" (__result), "=z" (__addr16)  \
370        : "1" (__addr16)                    \
371        : "r0"                              \
372    );                                      \
373    __result;                               \
374}))
375
376#define __LPM_float_enhanced__(addr)        \
377(__extension__({                            \
378    uint16_t __addr16 = (uint16_t)(addr);   \
379    float __result;                         \
380    __asm__                                 \
381    (                                       \
382        "lpm %A0, Z+"   "\n\t"              \
383        "lpm %B0, Z+"   "\n\t"              \
384        "lpm %C0, Z+"   "\n\t"              \
385        "lpm %D0, Z"    "\n\t"              \
386        : "=r" (__result), "=z" (__addr16)  \
387        : "1" (__addr16)                    \
388    );                                      \
389    __result;                               \
390}))
391
392#if defined (__AVR_HAVE_LPMX__)
393#define __LPM(addr)         __LPM_enhanced__(addr)
394#define __LPM_word(addr)    __LPM_word_enhanced__(addr)
395#define __LPM_dword(addr)   __LPM_dword_enhanced__(addr)
396#define __LPM_float(addr)   __LPM_float_enhanced__(addr)
397#else
398#define __LPM(addr)         __LPM_classic__(addr)
399#define __LPM_word(addr)    __LPM_word_classic__(addr)
400#define __LPM_dword(addr)   __LPM_dword_classic__(addr)
401#define __LPM_float(addr)   __LPM_float_classic__(addr)
402#endif
403
404/** \ingroup avr_pgmspace
405    \def pgm_read_byte_near(address_short)
406    Read a byte from the program space with a 16-bit (near) address.
407    \note The address is a byte address.
408    The address is in the program space. */
409
410#define pgm_read_byte_near(address_short) __LPM((uint16_t)(address_short))
411
412/** \ingroup avr_pgmspace
413    \def pgm_read_word_near(address_short)
414    Read a word from the program space with a 16-bit (near) address.
415    \note The address is a byte address.
416    The address is in the program space. */
417
418#define pgm_read_word_near(address_short) __LPM_word((uint16_t)(address_short))
419
420/** \ingroup avr_pgmspace
421    \def pgm_read_dword_near(address_short)
422    Read a double word from the program space with a 16-bit (near) address.
423    \note The address is a byte address.
424    The address is in the program space. */
425
426#define pgm_read_dword_near(address_short) \
427    __LPM_dword((uint16_t)(address_short))
428
429/** \ingroup avr_pgmspace
430    \def pgm_read_float_near(address_short)
431    Read a float from the program space with a 16-bit (near) address.
432    \note The address is a byte address.
433    The address is in the program space. */
434
435#define pgm_read_float_near(address_short) \
436    __LPM_float((uint16_t)(address_short))
437
438#if defined(RAMPZ) || defined(__DOXYGEN__)
439
440/* Only for devices with more than 64K of program memory.
441   RAMPZ must be defined (see iom103.h, iom128.h).
442*/
443
444/* The classic functions are needed for ATmega103. */
445
446#define __ELPM_classic__(addr)      \
447(__extension__({                    \
448    uint32_t __addr32 = (uint32_t)(addr); \
449    uint8_t __result;               \
450    __asm__                         \
451    (                               \
452        "out %2, %C1" "\n\t"        \
453        "mov r31, %B1" "\n\t"       \
454        "mov r30, %A1" "\n\t"       \
455        "elpm" "\n\t"               \
456        "mov %0, r0" "\n\t"         \
457        : "=r" (__result)           \
458        : "r" (__addr32),           \
459          "I" (_SFR_IO_ADDR(RAMPZ)) \
460        : "r0", "r30", "r31"        \
461    );                              \
462    __result;                       \
463}))
464
465#define __ELPM_enhanced__(addr)     \
466(__extension__({                    \
467    uint32_t __addr32 = (uint32_t)(addr); \
468    uint8_t __result;               \
469    __asm__                         \
470    (                               \
471        "out %2, %C1" "\n\t"        \
472        "movw r30, %1" "\n\t"       \
473        "elpm %0, Z+" "\n\t"        \
474        : "=r" (__result)           \
475        : "r" (__addr32),           \
476          "I" (_SFR_IO_ADDR(RAMPZ)) \
477        : "r30", "r31"              \
478    );                              \
479    __result;                       \
480}))
481
482#define __ELPM_xmega__(addr)        \
483(__extension__({                    \
484    uint32_t __addr32 = (uint32_t)(addr); \
485    uint8_t __result;               \
486    __asm__                         \
487    (                               \
488        "in __tmp_reg__, %2" "\n\t" \
489        "out %2, %C1" "\n\t"        \
490        "movw r30, %1" "\n\t"       \
491        "elpm %0, Z+" "\n\t"        \
492        "out %2, __tmp_reg__"       \
493        : "=r" (__result)           \
494        : "r" (__addr32),           \
495          "I" (_SFR_IO_ADDR(RAMPZ)) \
496        : "r30", "r31"              \
497    );                              \
498    __result;                       \
499}))
500
501#define __ELPM_word_classic__(addr)     \
502(__extension__({                        \
503    uint32_t __addr32 = (uint32_t)(addr); \
504    uint16_t __result;                  \
505    __asm__                             \
506    (                                   \
507        "out %2, %C1"   "\n\t"          \
508        "mov r31, %B1"  "\n\t"          \
509        "mov r30, %A1"  "\n\t"          \
510        "elpm"          "\n\t"          \
511        "mov %A0, r0"   "\n\t"          \
512        "in r0, %2"     "\n\t"          \
513        "adiw r30, 1"   "\n\t"          \
514        "adc r0, __zero_reg__" "\n\t"   \
515        "out %2, r0"    "\n\t"          \
516        "elpm"          "\n\t"          \
517        "mov %B0, r0"   "\n\t"          \
518        : "=r" (__result)               \
519        : "r" (__addr32),               \
520          "I" (_SFR_IO_ADDR(RAMPZ))     \
521        : "r0", "r30", "r31"            \
522    );                                  \
523    __result;                           \
524}))
525
526#define __ELPM_word_enhanced__(addr)    \
527(__extension__({                        \
528    uint32_t __addr32 = (uint32_t)(addr); \
529    uint16_t __result;                  \
530    __asm__                             \
531    (                                   \
532        "out %2, %C1"   "\n\t"          \
533        "movw r30, %1"  "\n\t"          \
534        "elpm %A0, Z+"  "\n\t"          \
535        "elpm %B0, Z"   "\n\t"          \
536        : "=r" (__result)               \
537        : "r" (__addr32),               \
538          "I" (_SFR_IO_ADDR(RAMPZ))     \
539        : "r30", "r31"                  \
540    );                                  \
541    __result;                           \
542}))
543
544#define __ELPM_word_xmega__(addr)       \
545(__extension__({                        \
546    uint32_t __addr32 = (uint32_t)(addr); \
547    uint16_t __result;                  \
548    __asm__                             \
549    (                                   \
550        "in __tmp_reg__, %2" "\n\t"     \
551        "out %2, %C1"   "\n\t"          \
552        "movw r30, %1"  "\n\t"          \
553        "elpm %A0, Z+"  "\n\t"          \
554        "elpm %B0, Z"   "\n\t"          \
555        "out %2, __tmp_reg__"           \
556        : "=r" (__result)               \
557        : "r" (__addr32),               \
558          "I" (_SFR_IO_ADDR(RAMPZ))     \
559        : "r30", "r31"                  \
560    );                                  \
561    __result;                           \
562}))
563
564#define __ELPM_dword_classic__(addr)      \
565(__extension__({                          \
566    uint32_t __addr32 = (uint32_t)(addr); \
567    uint32_t __result;                    \
568    __asm__                               \
569    (                                     \
570        "out %2, %C1"          "\n\t"     \
571        "mov r31, %B1"         "\n\t"     \
572        "mov r30, %A1"         "\n\t"     \
573        "elpm"                 "\n\t"     \
574        "mov %A0, r0"          "\n\t"     \
575        "in r0, %2"            "\n\t"     \
576        "adiw r30, 1"          "\n\t"     \
577        "adc r0, __zero_reg__" "\n\t"     \
578        "out %2, r0"           "\n\t"     \
579        "elpm"                 "\n\t"     \
580        "mov %B0, r0"          "\n\t"     \
581        "in r0, %2"            "\n\t"     \
582        "adiw r30, 1"          "\n\t"     \
583        "adc r0, __zero_reg__" "\n\t"     \
584        "out %2, r0"           "\n\t"     \
585        "elpm"                 "\n\t"     \
586        "mov %C0, r0"          "\n\t"     \
587        "in r0, %2"            "\n\t"     \
588        "adiw r30, 1"          "\n\t"     \
589        "adc r0, __zero_reg__" "\n\t"     \
590        "out %2, r0"           "\n\t"     \
591        "elpm"                 "\n\t"     \
592        "mov %D0, r0"          "\n\t"     \
593        : "=r" (__result)                 \
594        : "r" (__addr32),                 \
595          "I" (_SFR_IO_ADDR(RAMPZ))       \
596        : "r0", "r30", "r31"              \
597    );                                    \
598    __result;                             \
599}))
600
601#define __ELPM_dword_enhanced__(addr)     \
602(__extension__({                          \
603    uint32_t __addr32 = (uint32_t)(addr); \
604    uint32_t __result;                    \
605    __asm__                               \
606    (                                     \
607        "out %2, %C1"   "\n\t"            \
608        "movw r30, %1"  "\n\t"            \
609        "elpm %A0, Z+"  "\n\t"            \
610        "elpm %B0, Z+"  "\n\t"            \
611        "elpm %C0, Z+"  "\n\t"            \
612        "elpm %D0, Z"   "\n\t"            \
613        : "=r" (__result)                 \
614        : "r" (__addr32),                 \
615          "I" (_SFR_IO_ADDR(RAMPZ))       \
616        : "r30", "r31"                    \
617    );                                    \
618    __result;                             \
619}))
620
621#define __ELPM_dword_xmega__(addr)        \
622(__extension__({                          \
623    uint32_t __addr32 = (uint32_t)(addr); \
624    uint32_t __result;                    \
625    __asm__                               \
626    (                                     \
627        "in __tmp_reg__, %2" "\n\t"       \
628        "out %2, %C1"   "\n\t"            \
629        "movw r30, %1"  "\n\t"            \
630        "elpm %A0, Z+"  "\n\t"            \
631        "elpm %B0, Z+"  "\n\t"            \
632        "elpm %C0, Z+"  "\n\t"            \
633        "elpm %D0, Z"   "\n\t"            \
634        "out %2, __tmp_reg__"             \
635        : "=r" (__result)                 \
636        : "r" (__addr32),                 \
637          "I" (_SFR_IO_ADDR(RAMPZ))       \
638        : "r30", "r31"                    \
639    );                                    \
640    __result;                             \
641}))
642
643#define __ELPM_float_classic__(addr)      \
644(__extension__({                          \
645    uint32_t __addr32 = (uint32_t)(addr); \
646    float __result;                       \
647    __asm__                               \
648    (                                     \
649        "out %2, %C1"          "\n\t"     \
650        "mov r31, %B1"         "\n\t"     \
651        "mov r30, %A1"         "\n\t"     \
652        "elpm"                 "\n\t"     \
653        "mov %A0, r0"          "\n\t"     \
654        "in r0, %2"            "\n\t"     \
655        "adiw r30, 1"          "\n\t"     \
656        "adc r0, __zero_reg__" "\n\t"     \
657        "out %2, r0"           "\n\t"     \
658        "elpm"                 "\n\t"     \
659        "mov %B0, r0"          "\n\t"     \
660        "in r0, %2"            "\n\t"     \
661        "adiw r30, 1"          "\n\t"     \
662        "adc r0, __zero_reg__" "\n\t"     \
663        "out %2, r0"           "\n\t"     \
664        "elpm"                 "\n\t"     \
665        "mov %C0, r0"          "\n\t"     \
666        "in r0, %2"            "\n\t"     \
667        "adiw r30, 1"          "\n\t"     \
668        "adc r0, __zero_reg__" "\n\t"     \
669        "out %2, r0"           "\n\t"     \
670        "elpm"                 "\n\t"     \
671        "mov %D0, r0"          "\n\t"     \
672        : "=r" (__result)                 \
673        : "r" (__addr32),                 \
674          "I" (_SFR_IO_ADDR(RAMPZ))       \
675        : "r0", "r30", "r31"              \
676    );                                    \
677    __result;                             \
678}))
679
680#define __ELPM_float_enhanced__(addr)     \
681(__extension__({                          \
682    uint32_t __addr32 = (uint32_t)(addr); \
683    float __result;                       \
684    __asm__                               \
685    (                                     \
686        "out %2, %C1"   "\n\t"            \
687        "movw r30, %1"  "\n\t"            \
688        "elpm %A0, Z+"  "\n\t"            \
689        "elpm %B0, Z+"  "\n\t"            \
690        "elpm %C0, Z+"  "\n\t"            \
691        "elpm %D0, Z"   "\n\t"            \
692        : "=r" (__result)                 \
693        : "r" (__addr32),                 \
694          "I" (_SFR_IO_ADDR(RAMPZ))       \
695        : "r30", "r31"                    \
696    );                                    \
697    __result;                             \
698}))
699
700#define __ELPM_float_xmega__(addr)        \
701(__extension__({                          \
702    uint32_t __addr32 = (uint32_t)(addr); \
703    float __result;                       \
704    __asm__                               \
705    (                                     \
706        "in __tmp_reg__, %2" "\n\t"       \
707        "out %2, %C1"   "\n\t"            \
708        "movw r30, %1"  "\n\t"            \
709        "elpm %A0, Z+"  "\n\t"            \
710        "elpm %B0, Z+"  "\n\t"            \
711        "elpm %C0, Z+"  "\n\t"            \
712        "elpm %D0, Z"   "\n\t"            \
713        "out %2, __tmp_reg__"             \
714        : "=r" (__result)                 \
715        : "r" (__addr32),                 \
716          "I" (_SFR_IO_ADDR(RAMPZ))       \
717        : "r30", "r31"                    \
718    );                                    \
719    __result;                             \
720}))
721
722/*
723Check for architectures that implement RAMPD (avrxmega3, avrxmega5,
724avrxmega7) as they need to save/restore RAMPZ for ELPM macros so it does
725not interfere with data accesses.
726*/
727#if defined (__AVR_HAVE_RAMPD__)
728
729#define __ELPM(addr)        __ELPM_xmega__(addr)
730#define __ELPM_word(addr)   __ELPM_word_xmega__(addr)
731#define __ELPM_dword(addr)  __ELPM_dword_xmega__(addr)
732#define __ELPM_float(addr)  __ELPM_float_xmega__(addr)
733
734#else
735
736#if defined (__AVR_HAVE_LPMX__)
737
738#define __ELPM(addr)        __ELPM_enhanced__(addr)
739#define __ELPM_word(addr)   __ELPM_word_enhanced__(addr)
740#define __ELPM_dword(addr)  __ELPM_dword_enhanced__(addr)
741#define __ELPM_float(addr)  __ELPM_float_enhanced__(addr)
742
743#else
744
745#define __ELPM(addr)        __ELPM_classic__(addr)
746#define __ELPM_word(addr)   __ELPM_word_classic__(addr)
747#define __ELPM_dword(addr)  __ELPM_dword_classic__(addr)
748#define __ELPM_float(addr)  __ELPM_float_classic__(addr)
749
750#endif  /* __AVR_HAVE_LPMX__ */
751
752#endif  /* __AVR_HAVE_RAMPD__ */
753
754
755/** \ingroup avr_pgmspace
756    \def pgm_read_byte_far(address_long)
757    Read a byte from the program space with a 32-bit (far) address.
758
759    \note The address is a byte address.
760    The address is in the program space. */
761
762#define pgm_read_byte_far(address_long)  __ELPM((uint32_t)(address_long))
763
764/** \ingroup avr_pgmspace
765    \def pgm_read_word_far(address_long)
766    Read a word from the program space with a 32-bit (far) address.
767
768    \note The address is a byte address.
769    The address is in the program space. */
770
771#define pgm_read_word_far(address_long)  __ELPM_word((uint32_t)(address_long))
772
773/** \ingroup avr_pgmspace
774    \def pgm_read_dword_far(address_long)
775    Read a double word from the program space with a 32-bit (far) address.
776
777    \note The address is a byte address.
778    The address is in the program space. */
779
780#define pgm_read_dword_far(address_long) __ELPM_dword((uint32_t)(address_long))
781
782/** \ingroup avr_pgmspace
783    \def pgm_read_float_far(address_long)
784    Read a float from the program space with a 32-bit (far) address.
785
786    \note The address is a byte address.
787    The address is in the program space. */
788
789#define pgm_read_float_far(address_long) __ELPM_float((uint32_t)(address_long))
790
791#endif /* RAMPZ or __DOXYGEN__ */
792
793/** \ingroup avr_pgmspace
794    \def pgm_read_byte(address_short)
795    Read a byte from the program space with a 16-bit (near) address.
796
797    \note The address is a byte address.
798    The address is in the program space. */
799
800#define pgm_read_byte(address_short)    pgm_read_byte_near(address_short)
801
802/** \ingroup avr_pgmspace
803    \def pgm_read_word(address_short)
804    Read a word from the program space with a 16-bit (near) address.
805
806    \note The address is a byte address.
807    The address is in the program space. */
808
809#define pgm_read_word(address_short)    pgm_read_word_near(address_short)
810
811/** \ingroup avr_pgmspace
812    \def pgm_read_dword(address_short)
813    Read a double word from the program space with a 16-bit (near) address.
814
815    \note The address is a byte address.
816    The address is in the program space. */
817
818#define pgm_read_dword(address_short)   pgm_read_dword_near(address_short)
819
820/** \ingroup avr_pgmspace
821    \def pgm_read_float(address_short)
822    Read a float from the program space with a 16-bit (near) address.
823
824    \note The address is a byte address.
825    The address is in the program space. */
826
827#define pgm_read_float(address_short)   pgm_read_float_near(address_short)
828
829/** \ingroup avr_pgmspace
830    \def PGM_P
831
832    Used to declare a variable that is a pointer to a string in program
833    space. */
834
835#ifndef PGM_P
836#define PGM_P const prog_char *
837#endif
838
839/** \ingroup avr_pgmspace
840    \def PGM_VOID_P
841
842    Used to declare a generic pointer to an object in program space. */
843
844#ifndef PGM_VOID_P
845#define PGM_VOID_P const prog_void *
846#endif
847
848extern PGM_VOID_P memchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__;
849extern int memcmp_P(const void *, PGM_VOID_P, size_t) __ATTR_PURE__;
850extern void *memcpy_P(void *, PGM_VOID_P, size_t);
851extern void *memmem_P(const void *, size_t, PGM_VOID_P, size_t) __ATTR_PURE__;
852extern PGM_VOID_P memrchr_P(PGM_VOID_P, int __val, size_t __len) __ATTR_CONST__;
853extern char *strcat_P(char *, PGM_P);
854extern PGM_P strchr_P(PGM_P, int __val) __ATTR_CONST__;
855extern PGM_P strchrnul_P(PGM_P, int __val) __ATTR_CONST__;
856extern int strcmp_P(const char *, PGM_P) __ATTR_PURE__;
857extern char *strcpy_P(char *, PGM_P);
858extern int strcasecmp_P(const char *, PGM_P) __ATTR_PURE__;
859extern char *strcasestr_P(const char *, PGM_P) __ATTR_PURE__;
860extern size_t strcspn_P(const char *__s, PGM_P __reject) __ATTR_PURE__;
861extern size_t strlcat_P (char *, PGM_P, size_t );
862extern size_t strlcpy_P (char *, PGM_P, size_t );
863extern size_t strlen_P(PGM_P) __ATTR_CONST__; /* program memory can't change */
864extern size_t strnlen_P(PGM_P, size_t) __ATTR_CONST__; /* program memory can't change */
865extern int strncmp_P(const char *, PGM_P, size_t) __ATTR_PURE__;
866extern int strncasecmp_P(const char *, PGM_P, size_t) __ATTR_PURE__;
867extern char *strncat_P(char *, PGM_P, size_t);
868extern char *strncpy_P(char *, PGM_P, size_t);
869extern char *strpbrk_P(const char *__s, PGM_P __accept) __ATTR_PURE__;
870extern PGM_P strrchr_P(PGM_P, int __val) __ATTR_CONST__;
871extern char *strsep_P(char **__sp, PGM_P __delim);
872extern size_t strspn_P(const char *__s, PGM_P __accept) __ATTR_PURE__;
873extern char *strstr_P(const char *, PGM_P) __ATTR_PURE__;
874
875#ifdef __cplusplus
876}
877#endif
878
879#endif /* __PGMSPACE_H_ */
Note: See TracBrowser for help on using the repository browser.