forked from esp8266/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathpgmspace.h
151 lines (127 loc) · 5.79 KB
/
pgmspace.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* PGMSPACE.H - Accessor utilities/types for accessing PROGMEM data */
#ifndef _PGMSPACE_H_
#define _PGMSPACE_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ICACHE_RODATA_ATTR
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
#endif
#ifndef PROGMEM
// The following two macros cause a parameter to be enclosed in quotes
// by the preopressor (i.e. for concatenating ints to strings)
#define __STRINGIZE_NX(A) #A
#define __STRINGIZE(A) __STRINGIZE_NX(A)
// Since __section__ is supposed to be only use for global variables,
// there could be conflicts when a static/inlined function has them in the
// same file as a non-static PROGMEM object.
// Ref: https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html
// Place each progmem object into its own named section, avoiding conflicts
#define PROGMEM __attribute__((section( "\".irom.text." __FILE__ "." __STRINGIZE(__LINE__) "." __STRINGIZE(__COUNTER__) "\"")))
#endif
#ifndef PGM_P
#define PGM_P const char *
#endif
#ifndef PGM_VOID_P
#define PGM_VOID_P const void *
#endif
// PSTR() macro modified to start on a 32-bit boundary. This adds on average
// 1.5 bytes/string, but in return memcpy_P and strcpy_P will work 4~8x faster
#ifndef PSTR
#define PSTR(s) (__extension__({static const char __c[] __attribute__((__aligned__(4))) PROGMEM = (s); &__c[0];}))
#endif
// Flash memory must be read using 32 bit aligned addresses else a processor
// exception will be triggered.
// The order within the 32 bit values are:
// --------------
// b3, b2, b1, b0
// w1, w0
#define pgm_read_with_offset(addr, res) \
asm("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ \
"sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ \
"l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ \
"slli %0, %0, 3\n" /* Mulitiply offset by 8, yielding an offset in bits */ \
"ssr %0\n" /* Prepare to shift by offset (in bits) */ \
"srl %0, %1\n" /* Shift right; now the requested byte is the first one */ \
:"=r"(res), "=r"(addr) \
:"1"(addr) \
:);
static inline uint8_t pgm_read_byte_inlined(const void* addr) {
register uint32_t res;
pgm_read_with_offset(addr, res);
return (uint8_t) res; /* This masks the lower byte from the returned word */
}
/* Although this says "word", it's actually 16 bit, i.e. half word on Xtensa */
static inline uint16_t pgm_read_word_inlined(const void* addr) {
register uint32_t res;
pgm_read_with_offset(addr, res);
return (uint16_t) res; /* This masks the lower half-word from the returned word */
}
#define pgm_read_byte(addr) pgm_read_byte_inlined(addr)
#define pgm_read_word_aligned(addr) pgm_read_word_inlined(addr)
#ifdef __cplusplus
#define pgm_read_dword_aligned(addr) (*reinterpret_cast<const uint32_t*>(addr))
#define pgm_read_float_aligned(addr) (*reinterpret_cast<const float*>(addr))
#define pgm_read_ptr_aligned(addr) (*reinterpret_cast<const void* const*>(addr))
#else
#define pgm_read_dword_aligned(addr) (*(const uint32_t*)(addr))
#define pgm_read_float_aligned(addr) (*(const float*)(addr))
#define pgm_read_ptr_aligned(addr) (*(const void* const*)(addr))
#endif
__attribute__((optimize("-O3"), always_inline)) static inline uint32_t pgm_read_dword_unaligned(const void *addr) {
if (!(((int)addr)&3)) return *(const uint32_t *)addr;
int off = (((int)addr) & 3) << 3;
const uint32_t *p = (const uint32_t *)((int)addr & (~3));
uint32_t a = *p++;
uint32_t b = *p;
return (a>>off) | (b <<(32-off));
}
__attribute__((optimize("-O3"), always_inline)) static inline float pgm_read_float_unaligned(const void *addr) {
return (float)pgm_read_dword_unaligned(addr);
}
__attribute__((optimize("-O3"), always_inline)) static inline void *pgm_read_ptr_unaligned(const void *addr) {
return (void *)pgm_read_dword_unaligned(addr);
}
__attribute__((optimize("-O3"), always_inline)) static inline uint16_t pgm_read_word_unaligned(const void *addr) {
return pgm_read_dword_unaligned(addr) & 0xffff;
}
// Allow manual selection of _aligned or _unaligned, but default to _unaligned for Arduino compatibility
#define PGM_READ_UNALIGNED_DEFAULT
#ifdef PGM_READ_UNALIGNED_DEFAULT
#define pgm_read_word(a) pgm_read_word_unaligned(a)
#define pgm_read_dword(a) pgm_read_dword_unaligned(a)
#define pgm_read_float(a) pgm_read_float_unaligned(a)
#define pgm_read_ptr(a) pgm_read_ptr_unaligned(a)
#else
#define pgm_read_word(a) pgm_read_word_aligned(a)
#define pgm_read_dword(a) pgm_read_dword_aligned(a)
#define pgm_read_float(a) pgm_read_float_aligned(a)
#define pgm_read_ptr(a) pgm_read_ptr_aligned(a)
#endif
#define pgm_read_byte_near(addr) pgm_read_byte(addr)
#define pgm_read_word_near(addr) pgm_read_word(addr)
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
#define pgm_read_float_near(addr) pgm_read_float(addr)
#define pgm_read_ptr_near(addr) pgm_read_ptr(addr)
#define pgm_read_byte_far(addr) pgm_read_byte(addr)
#define pgm_read_word_far(addr) pgm_read_word(addr)
#define pgm_read_dword_far(addr) pgm_read_dword(addr)
#define pgm_read_float_far(addr) pgm_read_float(addr)
#define pgm_read_ptr_far(addr) pgm_read_ptr(addr)
#define _SFR_BYTE(n) (n)
#ifdef __PROG_TYPES_COMPAT__
typedef void prog_void;
typedef char prog_char;
typedef unsigned char prog_uchar;
typedef int8_t prog_int8_t;
typedef uint8_t prog_uint8_t;
typedef int16_t prog_int16_t;
typedef uint16_t prog_uint16_t;
typedef int32_t prog_int32_t;
typedef uint32_t prog_uint32_t;
#endif // defined(__PROG_TYPES_COMPAT__)
#ifdef __cplusplus
}
#endif
#endif