Fix undefined preprocessor symbol.
[bertos.git] / mware / pgm.h
1 /*!
2  * \file
3  * <!--
4  * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5  * This file is part of DevLib - See README.devlib for information.
6  * -->
7  *
8  * \brief Support for reading program memory on Harvard architectures.
9  *
10  * Support is currently provided for AVR microcontrollers only.
11  *
12  * These macros allow building code twice, with and without
13  * pgm support (e.g.: strcpy() and strcpy_P()).
14  *
15  * Set the _PROGMEM predefine to compile in conditional
16  * program-memory support.
17  *
18  *
19  * \note This module contains code ripped out from avr-libc,
20  *       which is distributed under a 3-clause BSD license.
21  */
22 #ifndef MWARE_PGM_H
23 #define MWARE_PGM_H
24
25 #include <cfg/cpu_detect.h>
26 #include <cfg/compiler.h> /* For intXX_t */
27 #include <cfg/cpu.h> /* For CPU_HARVARD */
28
29 #if CPU_AVR
30
31         #ifdef __AVR_ENHANCED__
32                 #define pgm_read_char(addr) \
33                 ({ \
34                         uint16_t __addr16 = (uint16_t)(addr); \
35                         uint8_t __result; \
36                         __asm__ \
37                         ( \
38                                 "lpm %0, Z" "\n\t" \
39                                 : "=r" (__result) \
40                                 : "z" (__addr16) \
41                         ); \
42                         __result; \
43                 })
44                 #if 0 // 128/103
45                 #define pgm_read_uint16_t(addr) \
46                 ({ \
47                         uint32_t __addr32 = (uint32_t)(addr); \
48                         uint16_t __result; \
49                         __asm__ \
50                         ( \
51                                 "out %2, %C1"   "\n\t" \
52                                 "movw r30, %1"  "\n\t" \
53                                 "elpm %A0, Z+"  "\n\t" \
54                                 "elpm %B0, Z"   "\n\t" \
55                                 : "=r" (__result) \
56                                 : "r" (__addr32), \
57                                   "I" (_SFR_IO_ADDR(RAMPZ)) \
58                                 : "r30", "r31" \
59                         ); \
60                         __result; \
61                 })
62                 #endif
63
64                 #define pgm_read_uint16_t(addr) \
65                 ({ \
66                         uint16_t __addr16 = (uint16_t)(addr); \
67                         uint16_t __result; \
68                         __asm__ \
69                         ( \
70                                 "lpm %A0, Z+"   "\n\t" \
71                                 "lpm %B0, Z"    "\n\t" \
72                                 : "=r" (__result), "=z" (__addr16) \
73                                 : "1" (__addr16) \
74                         ); \
75                         __result; \
76                 })
77
78
79         #else
80                 #define pgm_read_char(addr) \
81                 ({ \
82                         uint16_t __addr16 = (uint16_t)(addr); \
83                         uint8_t __result; \
84                         __asm__ \
85                         ( \
86                                 "lpm" "\n\t" \
87                                 "mov %0, r0" "\n\t" \
88                                 : "=r" (__result) \
89                                 : "z" (__addr16) \
90                                 : "r0" \
91                         ); \
92                         __result; \
93                 })
94                 #if 0 // 128/103
95                 #define pgm_read_uint16_t(addr) \
96                 ({ \
97                         uint32_t __addr32 = (uint32_t)(addr); \
98                         uint16_t __result; \
99                         __asm__ \
100                         ( \
101                                 "out %2, %C1"   "\n\t" \
102                                 "mov r31, %B1"  "\n\t" \
103                                 "mov r30, %A1"  "\n\t" \
104                                 "elpm"          "\n\t" \
105                                 "mov %A0, r0"   "\n\t" \
106                                 "in r0, %2"     "\n\t" \
107                                 "adiw r30, 1"   "\n\t" \
108                                 "adc r0, __zero_reg__" "\n\t" \
109                                 "out %2, r0"    "\n\t" \
110                                 "elpm"          "\n\t" \
111                                 "mov %B0, r0"   "\n\t" \
112                                 : "=r" (__result) \
113                                 : "r" (__addr32), \
114                                   "I" (_SFR_IO_ADDR(RAMPZ)) \
115                                 : "r0", "r30", "r31" \
116                         ); \
117                         __result; \
118                 })
119                 #endif
120                 #define pgm_read_uint16_t(addr) \
121                 ({ \
122                         uint16_t __addr16 = (uint16_t)(addr); \
123                         uint16_t __result; \
124                         __asm__ \
125                         ( \
126                                 "lpm"           "\n\t" \
127                                 "mov %A0, r0"   "\n\t" \
128                                 "adiw r30, 1"   "\n\t" \
129                                 "lpm"           "\n\t" \
130                                 "mov %B0, r0"   "\n\t" \
131                                 : "=r" (__result), "=z" (__addr16) \
132                                 : "1" (__addr16) \
133                                 : "r0" \
134                         ); \
135                         __result; \
136                 })
137
138         #endif
139
140         #ifndef PROGMEM
141         #define PROGMEM  __attribute__((__progmem__))
142         #endif
143         #ifndef PSTR
144         #define PSTR(s) ({ static const char __c[] PROGMEM = (s); &__c[0]; })
145         #endif
146
147 #elif CPU_HARVARD
148         #error Missing CPU support
149 #endif
150
151 #ifndef PSTR
152 #define PSTR            /* nothing */
153 #endif
154
155 #ifndef PROGMEM
156 #define PROGMEM                /* nothing */
157 #endif
158
159 /*!
160  * \name Types for variables stored in program memory (harvard processors).
161  * \{
162  */
163 typedef PROGMEM char pgm_char;
164 typedef PROGMEM int8_t pgm_int8_t;
165 typedef PROGMEM uint8_t pgm_uint8_t;
166 typedef PROGMEM int16_t pgm_int16_t;
167 typedef PROGMEM uint16_t pgm_uint16_t;
168 typedef PROGMEM int32_t pgm_int32_t;
169 typedef PROGMEM uint32_t pgm_uint32_t;
170 /*\}*/
171
172 /*!
173  * \name PGM support macros.
174  *
175  * These macros enable dual compilation of code for both program
176  * and data memory.
177  *
178  * Such a function may be defined like this:
179  *
180  * \code
181  *      void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str)
182  *      {
183  *              char c;
184  *              while ((c = PGM_READ_CHAR(str++))
185  *                      lcd_putchar(c);
186  *      }
187  * \endcode
188  *
189  * The above code can be compiled twice: once with the _PROGMEM preprocessor
190  * symbol defined, and once without.  The two object modules can then be
191  * linked in the same application for use by client code:
192  *
193  * \code
194  *      lcd_puts("Hello, world!");
195  *      lcd_puts_P(PSTR("Hello, world!"));
196  *
197  *      // To be used when invoking inside other PGM_FUNC functions:
198  *      PGM_FUNC(lcd_puts)(some_string);
199  * \endcode
200  *
201  * \{
202  */
203 #ifdef _PROGMEM
204         #define PGM_READ_CHAR(s) pgm_read_char(s)
205         #define PGM_FUNC(x)      x ## _P
206         #define PGM_STR(x)       PSTR(x)
207         #define PGM_ATTR         PROGMEM
208 #else
209         #define PGM_READ_CHAR(s) (*(s))
210         #define PGM_FUNC(x)      x
211         #define PGM_STR(x)       x
212         #define PGM_ATTR         /* nothing */
213 #endif
214 /* \} */
215
216
217 #endif /* MWARE_PGM_H */