Macros for program memory access.
[bertos.git] / mware / pgm.h
1 /*!
2  * \file
3  * <!--
4  * Copyright 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2004 Giovanni Bajo
6  * This file is part of DevLib - See README.devlib for information.
7  * -->
8  *
9  * \brief Support for reading program memory on Harvard architectures.
10  *
11  * Support is currently provided for AVR microcontrollers only.
12  *
13  * These macros allow building code twice, with and without
14  * pgm support (e.g.: strcpy() and strcpy_P()).
15  *
16  * Set the _PROGMEM predefine to compile in conditional
17  * program-memory support.
18  *
19  *
20  * \note This module contains code ripped out from avr-libc,
21  *       which is distributed under a 3-clause BSD license.
22  */
23 #ifndef MWARE_PGM_H
24 #define MWARE_PGM_H
25
26 #include <cpu_detect.h>
27
28 #if CPU_AVR
29
30         #ifdef __AVR_ENHANCED__
31                 #define pgm_read_char(addr) \
32                 ({ \
33                         uint16_t __addr16 = (uint16_t)(addr); \
34                         uint8_t __result; \
35                         __asm__ \
36                         ( \
37                                 "lpm %0, Z" "\n\t" \
38                                 : "=r" (__result) \
39                                 : "z" (__addr16) \
40                         ); \
41                         __result; \
42                 })
43         #else
44                 #define pgm_read_char(addr) \
45                 ({ \
46                         uint16_t __addr16 = (uint16_t)(addr); \
47                         uint8_t __result; \
48                         __asm__ \
49                         ( \
50                                 "lpm" "\n\t" \
51                                 "mov %0, r0" "\n\t" \
52                                 : "=r" (__result) \
53                                 : "z" (__addr16) \
54                                 : "r0" \
55                         ); \
56                         __result; \
57                 })
58         #endif
59
60         #define PROGMEM  __attribute__((__progmem__))
61         #define PSTR(s) ({static const char __c[] PROGMEM = (s); __c;})
62
63 #elif CPU_HARVARD
64         #error Missing CPU support
65 #endif
66
67 #ifndef PSTR
68 #define PSTR            /* nothing */
69 #endif
70
71 #ifndef PROGMEM
72 #define PROGMEM                /* nothing */
73 #endif
74
75 /*!
76  * \name Types for variables stored in program memory (harvard processors).
77  * \{
78  */
79 typedef PROGMEM char pgm_char;
80 typedef PROGMEM int8_t pgm_int8_t;
81 typedef PROGMEM uint8_t pgm_uint8_t;
82 typedef PROGMEM int16_t pgm_int16_t;
83 typedef PROGMEM uint16_t pgm_uint16_t;
84 typedef PROGMEM int32_t pgm_int32_t;
85 typedef PROGMEM uint32_t pgm_uint32_t;
86 /*\}*/
87
88 /*!
89  * \def PGM_READ_CHAR
90  * \def PGM_FUNC
91  * \def PGM_ATTR
92  *
93  * These macros enable dual compilation of code for both program
94  * and data memory.
95  *
96  * Such a function may be defined like this:
97  *
98  * \code
99  *      void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str)
100  *      {
101  *              char c;
102  *              while ((c = PGM_READ_CHAR(str++))
103  *                      lcd_putchar(c);
104  *      }
105  * \endcode
106  *
107  * The above code can be compiled twice: once with the _PROGMEM preprocessor
108  * symbol defined, and once without.  The two object modules can then be
109  * linked in the same application for use by client code:
110  *
111  * \code
112  *      lcd_puts("Hello, world!");
113  *      lcd_puts_P(PSTR("Hello, world!"));
114  *
115  *      // To be used when invoking inside other PGM_FUNC functions:
116  *      PGM_FUNC(lcd_puts)(some_string);
117  * \endcode
118  */
119 #ifdef _PROGMEM
120         #define PGM_READ_CHAR(s) pgm_read_char(s)
121         #define PGM_FUNC(x)      x ## _P
122         #define PGM_ATTR         PROGMEM
123 #else
124         #define PGM_READ_CHAR(s) (*(s))
125         #define PGM_FUNC(x)      x
126         #define PGM_ATTR         /* nothing */
127 #endif
128
129
130 #endif /* MWARE_PGM_H */