4 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5 * This file is part of DevLib - See README.devlib for information.
8 * \brief Support for reading program memory on Harvard architectures.
10 * Support is currently provided for AVR microcontrollers only.
12 * These macros allow building code twice, with and without
13 * pgm support (e.g.: strcpy() and strcpy_P()).
15 * Set the _PROGMEM predefine to compile in conditional
16 * program-memory support.
19 * \note This module contains code ripped out from avr-libc,
20 * which is distributed under a 3-clause BSD license.
25 #include <cfg/cpu_detect.h>
26 #include <cfg/compiler.h> /* For intXX_t */
30 #ifdef __AVR_ENHANCED__
31 #define pgm_read_char(addr) \
33 uint16_t __addr16 = (uint16_t)(addr); \
44 #define pgm_read_uint16_t(addr) \
46 uint32_t __addr32 = (uint32_t)(addr); \
50 "out %2, %C1" "\n\t" \
51 "movw r30, %1" "\n\t" \
52 "elpm %A0, Z+" "\n\t" \
53 "elpm %B0, Z" "\n\t" \
56 "I" (_SFR_IO_ADDR(RAMPZ)) \
63 #define pgm_read_uint16_t(addr) \
65 uint16_t __addr16 = (uint16_t)(addr); \
69 "lpm %A0, Z+" "\n\t" \
71 : "=r" (__result), "=z" (__addr16) \
79 #define pgm_read_char(addr) \
81 uint16_t __addr16 = (uint16_t)(addr); \
94 #define pgm_read_uint16_t(addr) \
96 uint32_t __addr32 = (uint32_t)(addr); \
100 "out %2, %C1" "\n\t" \
101 "mov r31, %B1" "\n\t" \
102 "mov r30, %A1" "\n\t" \
104 "mov %A0, r0" "\n\t" \
106 "adiw r30, 1" "\n\t" \
107 "adc r0, __zero_reg__" "\n\t" \
108 "out %2, r0" "\n\t" \
110 "mov %B0, r0" "\n\t" \
113 "I" (_SFR_IO_ADDR(RAMPZ)) \
114 : "r0", "r30", "r31" \
119 #define pgm_read_uint16_t(addr) \
121 uint16_t __addr16 = (uint16_t)(addr); \
126 "mov %A0, r0" "\n\t" \
127 "adiw r30, 1" "\n\t" \
129 "mov %B0, r0" "\n\t" \
130 : "=r" (__result), "=z" (__addr16) \
140 #define PROGMEM __attribute__((__progmem__))
143 #define PSTR(s) ({ static const char __c[] PROGMEM = (s); &__c[0]; })
147 #error Missing CPU support
151 #define PSTR /* nothing */
155 #define PROGMEM /* nothing */
159 * \name Types for variables stored in program memory (harvard processors).
162 typedef PROGMEM char pgm_char;
163 typedef PROGMEM int8_t pgm_int8_t;
164 typedef PROGMEM uint8_t pgm_uint8_t;
165 typedef PROGMEM int16_t pgm_int16_t;
166 typedef PROGMEM uint16_t pgm_uint16_t;
167 typedef PROGMEM int32_t pgm_int32_t;
168 typedef PROGMEM uint32_t pgm_uint32_t;
172 * \name PGM support macros.
174 * These macros enable dual compilation of code for both program
177 * Such a function may be defined like this:
180 * void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str)
183 * while ((c = PGM_READ_CHAR(str++))
188 * The above code can be compiled twice: once with the _PROGMEM preprocessor
189 * symbol defined, and once without. The two object modules can then be
190 * linked in the same application for use by client code:
193 * lcd_puts("Hello, world!");
194 * lcd_puts_P(PSTR("Hello, world!"));
196 * // To be used when invoking inside other PGM_FUNC functions:
197 * PGM_FUNC(lcd_puts)(some_string);
203 #define PGM_READ_CHAR(s) pgm_read_char(s)
204 #define PGM_FUNC(x) x ## _P
205 #define PGM_STR(x) PSTR(x)
206 #define PGM_ATTR PROGMEM
208 #define PGM_READ_CHAR(s) (*(s))
209 #define PGM_FUNC(x) x
211 #define PGM_ATTR /* nothing */
216 #endif /* MWARE_PGM_H */