source: rtems/cpukit/score/cpu/avr/avr/pgmspace.h @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

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