progmem.h


#ifndef _PROGMEM_H_
#define _PROGMEM_H_

#define __need_size_t
#include <stddef.h>

#include <io.h>

typedef char prog_char __attribute__ ((progmem));
typedef int prog_int __attribute__ ((progmem));
typedef long prog_long __attribute__ ((progmem));
typedef long long prog_long_long __attribute__ ((progmem));

#define PROGMEM __attribute__ ((progmem))
#define PSTR(s) ({static char c[] __attribute__ ((progmem)) = s;c;})

/* workaround for egcs-1.1.2 bug:
   load r31:r30 yourself, don't let the compiler do it */
#define __lpm_old_macro(addr) ({		\
	char t;					\
	asm volatile (				\
		"mov	r30, %A1" "\n\t"	\
		"mov	r31, %B1" "\n\t"	\
		"lpm" "\n\t"			\
		"mov	%0, r0"			\
		: "=r" (t)			\
		: "r" (addr)			\
		: "r30", "r31"			\
	);					\
	t;					\
})

/* this macro seems to work OK with gcc-2.95.1 -
   if not, use the one above */
#define __lpm_macro(addr) ({			\
	char t;					\
	asm volatile (				\
		"lpm" "\n\t"			\
		"mov	%0,r0"			\
		: "=r" (t)			\
		: "z" (addr)			\
	);					\
	t;					\
})

/* use this for access to >64K program memory (ATmega103),
   addr = RAMPZ:r31:r30 (if possible, put your constant tables in the
   lower 64K and use "lpm" - it is more efficient that way, and you can
   still use the upper 64K for executable code).  */
#define __elpm_macro(addr) ({			\
	char t;					\
	asm volatile (				\
		"mov	r30, %A1" "\n\t"	\
		"mov	r31, %B1" "\n\t"	\
		"out	%2, %C1" "\n\t"		\
		"elpm" "\n\t"			\
		"mov	%0, r0"			\
		: "=r" (t)			\
		: "r" (addr), "I" (RAMPZ)	\
		: "r30", "r31"			\
	);					\
	t;					\
})

static inline char __lpm_inline(unsigned int addr) __attribute__((const));
static inline char __lpm_inline(unsigned int addr)
{
	return __lpm_macro(addr);
}

#if (FLASHEND > 0xFFFFUL)  /* >64K program memory (ATmega103) */

static inline char __elpm_inline(unsigned long addr) __attribute__((const));
static inline char __elpm_inline(unsigned long addr)
{
	return __elpm_macro(addr);
}

#endif

// #define PRG_RDB(addr) __elpm_inline(addr)

#define PRG_RDB(addr) __lpm_macro(addr)


extern void progmem_read_block(void *dest, const prog_char *src, size_t n);

#endif /* _PROGMEM_H_ */

Back