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) \
80 #define pgm_read_char(addr) \
82 uint16_t __addr16 = (uint16_t)(addr); \
95 #define pgm_read_uint16_t(addr) \
97 uint32_t __addr32 = (uint32_t)(addr); \
101 "out %2, %C1" "\n\t" \
102 "mov r31, %B1" "\n\t" \
103 "mov r30, %A1" "\n\t" \
105 "mov %A0, r0" "\n\t" \
107 "adiw r30, 1" "\n\t" \
108 "adc r0, __zero_reg__" "\n\t" \
109 "out %2, r0" "\n\t" \
111 "mov %B0, r0" "\n\t" \
114 "I" (_SFR_IO_ADDR(RAMPZ)) \
115 : "r0", "r30", "r31" \
120 #define pgm_read_uint16_t(addr) \
122 uint16_t __addr16 = (uint16_t)(addr); \
127 "mov %A0, r0" "\n\t" \
128 "adiw r30, 1" "\n\t" \
130 "mov %B0, r0" "\n\t" \
131 : "=r" (__result), "=z" (__addr16) \
141 #define PROGMEM __attribute__((__progmem__))
144 #define PSTR(s) ({ static const char __c[] PROGMEM = (s); &__c[0]; })
148 #error Missing CPU support
152 #define PSTR /* nothing */
156 #define PROGMEM /* nothing */
160 * \name Types for variables stored in program memory (harvard processors).
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;
173 * \name PGM support macros.
175 * These macros enable dual compilation of code for both program
178 * Such a function may be defined like this:
181 * void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str)
184 * while ((c = PGM_READ_CHAR(str++))
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:
194 * lcd_puts("Hello, world!");
195 * lcd_puts_P(PSTR("Hello, world!"));
197 * // To be used when invoking inside other PGM_FUNC functions:
198 * PGM_FUNC(lcd_puts)(some_string);
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
209 #define PGM_READ_CHAR(s) (*(s))
210 #define PGM_FUNC(x) x
212 #define PGM_ATTR /* nothing */
217 #endif /* MWARE_PGM_H */