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 */
27 #include <cfg/cpu.h> /* For CPU_HARVARD */
31 #ifdef __AVR_ENHANCED__
32 #define pgm_read_char(addr) \
34 uint16_t __addr16 = (uint16_t)(addr); \
45 #define pgm_read_uint16_t(addr) \
47 uint32_t __addr32 = (uint32_t)(addr); \
51 "out %2, %C1" "\n\t" \
52 "movw r30, %1" "\n\t" \
53 "elpm %A0, Z+" "\n\t" \
54 "elpm %B0, Z" "\n\t" \
57 "I" (_SFR_IO_ADDR(RAMPZ)) \
64 #define pgm_read_uint16_t(addr) \
66 uint16_t __addr16 = (uint16_t)(addr); \
70 "lpm %A0, Z+" "\n\t" \
72 : "=r" (__result), "=z" (__addr16) \
79 #else /* !__AVR_ENHANCED__ */
81 #define pgm_read_char(addr) \
83 uint16_t __addr16 = (uint16_t)(addr); \
96 #define pgm_read_uint16_t(addr) \
98 uint32_t __addr32 = (uint32_t)(addr); \
102 "out %2, %C1" "\n\t" \
103 "mov r31, %B1" "\n\t" \
104 "mov r30, %A1" "\n\t" \
106 "mov %A0, r0" "\n\t" \
108 "adiw r30, 1" "\n\t" \
109 "adc r0, __zero_reg__" "\n\t" \
110 "out %2, r0" "\n\t" \
112 "mov %B0, r0" "\n\t" \
115 "I" (_SFR_IO_ADDR(RAMPZ)) \
116 : "r0", "r30", "r31" \
121 #define pgm_read_uint16_t(addr) \
123 uint16_t __addr16 = (uint16_t)(addr); \
128 "mov %A0, r0" "\n\t" \
129 "adiw r30, 1" "\n\t" \
131 "mov %B0, r0" "\n\t" \
132 : "=r" (__result), "=z" (__addr16) \
139 #endif /* !__AVR_ENHANCED__ */
142 #define pgm_read_int(addr) ((int)pgm_read_uint16_t(addr))
144 #error Missing support for CPU word size != 16bit
148 #define PROGMEM __attribute__((__progmem__))
151 #define PSTR(s) ({ static const char __c[] PROGMEM = (s); &__c[0]; })
155 #error Missing CPU support
159 #define PSTR /* nothing */
163 #define PROGMEM /* nothing */
167 * \name Types for variables stored in program memory (harvard processors).
170 typedef PROGMEM char pgm_char;
171 typedef PROGMEM int8_t pgm_int8_t;
172 typedef PROGMEM uint8_t pgm_uint8_t;
173 typedef PROGMEM int16_t pgm_int16_t;
174 typedef PROGMEM uint16_t pgm_uint16_t;
175 typedef PROGMEM int32_t pgm_int32_t;
176 typedef PROGMEM uint32_t pgm_uint32_t;
180 * \name PGM support macros.
182 * These macros enable dual compilation of code for both program
185 * Such a function may be defined like this:
188 * void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str)
191 * while ((c = PGM_READ_CHAR(str++))
196 * The above code can be compiled twice: once with the _PROGMEM preprocessor
197 * symbol defined, and once without. The two object modules can then be
198 * linked in the same application for use by client code:
201 * lcd_puts("Hello, world!");
202 * lcd_puts_P(PSTR("Hello, world!"));
204 * // To be used when invoking inside other PGM_FUNC functions:
205 * PGM_FUNC(lcd_puts)(some_string);
211 #define PGM_READ_CHAR(s) pgm_read_char(s)
212 #define PGM_FUNC(x) x ## _P
213 #define PGM_STR(x) PSTR(x)
214 #define PGM_ATTR PROGMEM
216 #define PGM_READ_CHAR(s) (*(s))
217 #define PGM_FUNC(x) x
219 #define PGM_ATTR /* nothing */
224 #endif /* MWARE_PGM_H */