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>
29 #ifdef __AVR_ENHANCED__
30 #define pgm_read_char(addr) \
32 uint16_t __addr16 = (uint16_t)(addr); \
43 #define pgm_read_uint16_t(addr) \
45 uint32_t __addr32 = (uint32_t)(addr); \
49 "out %2, %C1" "\n\t" \
50 "movw r30, %1" "\n\t" \
51 "elpm %A0, Z+" "\n\t" \
52 "elpm %B0, Z" "\n\t" \
55 "I" (_SFR_IO_ADDR(RAMPZ)) \
62 #define pgm_read_uint16_t(addr) \
64 uint16_t __addr16 = (uint16_t)(addr); \
68 "lpm %A0, Z+" "\n\t" \
70 : "=r" (__result), "=z" (__addr16) \
78 #define pgm_read_char(addr) \
80 uint16_t __addr16 = (uint16_t)(addr); \
93 #define pgm_read_uint16_t(addr) \
95 uint32_t __addr32 = (uint32_t)(addr); \
99 "out %2, %C1" "\n\t" \
100 "mov r31, %B1" "\n\t" \
101 "mov r30, %A1" "\n\t" \
103 "mov %A0, r0" "\n\t" \
105 "adiw r30, 1" "\n\t" \
106 "adc r0, __zero_reg__" "\n\t" \
107 "out %2, r0" "\n\t" \
109 "mov %B0, r0" "\n\t" \
112 "I" (_SFR_IO_ADDR(RAMPZ)) \
113 : "r0", "r30", "r31" \
118 #define pgm_read_uint16_t(addr) \
120 uint16_t __addr16 = (uint16_t)(addr); \
125 "mov %A0, r0" "\n\t" \
126 "adiw r30, 1" "\n\t" \
128 "mov %B0, r0" "\n\t" \
129 : "=r" (__result), "=z" (__addr16) \
138 #define PROGMEM __attribute__((__progmem__))
139 #define PSTR(s) ({ static const char __c[] PROGMEM = (s); &__c[0]; })
142 #error Missing CPU support
146 #define PSTR /* nothing */
150 #define PROGMEM /* nothing */
154 * \name Types for variables stored in program memory (harvard processors).
157 typedef PROGMEM char pgm_char;
158 typedef PROGMEM int8_t pgm_int8_t;
159 typedef PROGMEM uint8_t pgm_uint8_t;
160 typedef PROGMEM int16_t pgm_int16_t;
161 typedef PROGMEM uint16_t pgm_uint16_t;
162 typedef PROGMEM int32_t pgm_int32_t;
163 typedef PROGMEM uint32_t pgm_uint32_t;
167 * \name PGM support macros.
169 * These macros enable dual compilation of code for both program
172 * Such a function may be defined like this:
175 * void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str)
178 * while ((c = PGM_READ_CHAR(str++))
183 * The above code can be compiled twice: once with the _PROGMEM preprocessor
184 * symbol defined, and once without. The two object modules can then be
185 * linked in the same application for use by client code:
188 * lcd_puts("Hello, world!");
189 * lcd_puts_P(PSTR("Hello, world!"));
191 * // To be used when invoking inside other PGM_FUNC functions:
192 * PGM_FUNC(lcd_puts)(some_string);
198 #define PGM_READ_CHAR(s) pgm_read_char(s)
199 #define PGM_FUNC(x) x ## _P
200 #define PGM_ATTR PROGMEM
202 #define PGM_READ_CHAR(s) (*(s))
203 #define PGM_FUNC(x) x
204 #define PGM_ATTR /* nothing */
209 #endif /* MWARE_PGM_H */