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

4.115
Last change on this file since b697bc6 was b697bc6, checked in by Joel Sherrill <joel.sherrill@…>, on 01/10/13 at 21:06:42

cpukit: Use Consistent Beginning of Doxygen Group Notation

This is the result of a sed script which converts all uses
of @{ into a consistent form.

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