Skip to content

Commit 0b67266

Browse files
committed
progmem: replace C version of pgm_read_{word,byte} with assembly
See discussion in #3140
1 parent a41f55c commit 0b67266

File tree

1 file changed

+25
-17
lines changed

1 file changed

+25
-17
lines changed

cores/esp8266/pgmspace.h

+25-17
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,31 @@ int vsnprintf_P(char *str, size_t strSize, PGM_P formatP, va_list ap) __attribut
8787
// w1, w0
8888

8989
#ifdef __ets__
90-
#define pgm_read_byte(addr) \
91-
(__extension__({ \
92-
PGM_P __local = (PGM_P)(addr); /* isolate varible for macro expansion */ \
93-
ptrdiff_t __offset = ((uint32_t)__local & 0x00000003); /* byte aligned mask */ \
94-
const uint32_t* __addr32 = (const uint32_t*)((const uint8_t*)(__local)-__offset); \
95-
uint8_t __result = ((*__addr32) >> (__offset * 8)); \
96-
__result; \
97-
}))
98-
99-
#define pgm_read_word(addr) \
100-
(__extension__({ \
101-
PGM_P __local = (PGM_P)(addr); /* isolate varible for macro expansion */ \
102-
ptrdiff_t __offset = ((uint32_t)__local & 0x00000002); /* word aligned mask */ \
103-
const uint32_t* __addr32 = (const uint32_t*)((const uint8_t*)(__local) - __offset); \
104-
uint16_t __result = ((*__addr32) >> (__offset * 8)); \
105-
__result; \
106-
}))
90+
91+
#define pgm_read_with_offset(addr, res) \
92+
asm("extui %0, %1, 0, 2\n" /* Extract offset within word (in bytes) */ \
93+
"sub %1, %1, %0\n" /* Subtract offset from addr, yielding an aligned address */ \
94+
"l32i.n %1, %1, 0x0\n" /* Load word from aligned address */ \
95+
"slli %0, %0, 3\n" /* Mulitiply offset by 8, yielding an offset in bits */ \
96+
"ssr %0\n" /* Prepare to shift by offset (in bits) */ \
97+
"srl %0, %1\n" /* Shift right; now the requested byte is the first one */ \
98+
:"=r"(res), "=r"(addr) \
99+
:"1"(addr) \
100+
:);
101+
102+
static inline uint8_t pgm_read_byte(const void* addr) {
103+
register uint32_t res;
104+
pgm_read_with_offset(addr, res);
105+
return (uint8_t) res; /* This masks the lower byte from the returned word */
106+
}
107+
108+
/* Although this says "word", it's actually 16 bit, i.e. half word on Xtensa */
109+
static inline uint16_t pgm_read_word(const void* addr) {
110+
register uint32_t res;
111+
pgm_read_with_offset(addr, res);
112+
return (uint16_t) res; /* This masks the lower half-word from the returned word */
113+
}
114+
107115
#else //__ets__
108116
#define pgm_read_byte(addr) (*reinterpret_cast<const uint8_t*>(addr))
109117
#define pgm_read_word(addr) (*reinterpret_cast<const uint16_t*>(addr))

0 commit comments

Comments
 (0)