X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fmware%2Fpgm.h;fp=bertos%2Fmware%2Fpgm.h;h=eebe87fe1107a8a716f5ce63632a5303759d82e5;hb=791e167e053bdd9250d34a9a5ccae6ccde4d6679;hp=0000000000000000000000000000000000000000;hpb=faf2f6bfd5933ff75e6cc01e3d48f9277f731d8f;p=bertos.git diff --git a/bertos/mware/pgm.h b/bertos/mware/pgm.h new file mode 100644 index 00000000..eebe87fe --- /dev/null +++ b/bertos/mware/pgm.h @@ -0,0 +1,211 @@ +/** + * \file + * + * + * \brief Support for reading program memory on Harvard architectures. + * + * Support is currently provided for AVR microcontrollers only. + * + * These macros allow building code twice, with and without + * pgm support (e.g.: strcpy() and strcpy_P()). + * + * Set the _PROGMEM predefine to compile in conditional + * program-memory support. + * + * + * \note This module contains code ripped out from avr-libc, + * which is distributed under a 3-clause BSD license. + */ +#ifndef MWARE_PGM_H +#define MWARE_PGM_H + +#include /* For intXX_t */ +#include +#include /* For CPU_HARVARD */ +#include /* For SIZEOF_INT */ + +#if CPU_AVR + + #ifdef __AVR_ENHANCED__ + #define pgm_read_char(addr) \ + ({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "lpm %0, Z" "\n\t" \ + : "=r" (__result) \ + : "z" (__addr16) \ + ); \ + __result; \ + }) + #define pgm_read_uint16_t(addr) \ + ({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "lpm %A0, Z+" "\n\t" \ + "lpm %B0, Z" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + ); \ + __result; \ + }) + + + #else /* !__AVR_ENHANCED__ */ + + #define pgm_read_char(addr) \ + ({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint8_t __result; \ + __asm__ \ + ( \ + "lpm" "\n\t" \ + "mov %0, r0" "\n\t" \ + : "=r" (__result) \ + : "z" (__addr16) \ + : "r0" \ + ); \ + __result; \ + }) + #define pgm_read_uint16_t(addr) \ + ({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint16_t __result; \ + __asm__ \ + ( \ + "lpm" "\n\t" \ + "mov %A0, r0" "\n\t" \ + "adiw r30, 1" "\n\t" \ + "lpm" "\n\t" \ + "mov %B0, r0" "\n\t" \ + : "=r" (__result), "=z" (__addr16) \ + : "1" (__addr16) \ + : "r0" \ + ); \ + __result; \ + }) + + #endif /* !__AVR_ENHANCED__ */ + + #if SIZEOF_INT == 2 + #define pgm_read_int(addr) ((int)pgm_read_uint16_t(addr)) + #else + #error Missing support for CPU word size != 16bit + #endif + + #ifndef PROGMEM + #define PROGMEM __attribute__((__progmem__)) + #endif + #ifndef PSTR + #define PSTR(s) ({ static const char __c[] PROGMEM = (s); &__c[0]; }) + #endif + #ifndef PFUNC + #define PFUNC(x) x ## _P + #endif + +#elif CPU_HARVARD + #error Missing CPU support +#endif + +#ifndef PSTR +#define PSTR /* nothing */ +#endif + +#ifndef PFUNC +#define PFUNC(x) x +#endif + +#ifndef PROGMEM +#define PROGMEM /* nothing */ +#endif + +/** + * \name Types for variables stored in program memory (harvard processors). + * \{ + */ +typedef PROGMEM char pgm_char; +typedef PROGMEM int8_t pgm_int8_t; +typedef PROGMEM uint8_t pgm_uint8_t; +typedef PROGMEM int16_t pgm_int16_t; +typedef PROGMEM uint16_t pgm_uint16_t; +typedef PROGMEM int32_t pgm_int32_t; +typedef PROGMEM uint32_t pgm_uint32_t; +/*\}*/ + +/** + * \name PGM support macros. + * + * These macros enable dual compilation of code for both program + * and data memory. + * + * Such a function may be defined like this: + * + * \code + * void PGM_FUNC(lcd_puts)(PGM_ATTR const char *str) + * { + * char c; + * while ((c = PGM_READ_CHAR(str++)) + * lcd_putchar(c); + * } + * \endcode + * + * The above code can be compiled twice: once with the _PROGMEM preprocessor + * symbol defined, and once without. The two object modules can then be + * linked in the same application for use by client code: + * + * \code + * lcd_puts("Hello, world!"); + * lcd_puts_P(PSTR("Hello, world!")); + * + * // To be used when invoking inside other PGM_FUNC functions: + * PGM_FUNC(lcd_puts)(some_string); + * \endcode + * + * \{ + */ +#ifdef _PROGMEM + #define PGM_READ_CHAR(s) pgm_read_char(s) + #define PGM_FUNC(x) PFUNC(x) + #define PGM_STR(x) PSTR(x) + #define PGM_ATTR PROGMEM +#else + #define PGM_READ_CHAR(s) (*(s)) + #define PGM_FUNC(x) x + #define PGM_STR(x) x + #define PGM_ATTR /* nothing */ +#endif +/* \} */ + + +#endif /* MWARE_PGM_H */