Skip to content

Commit

Permalink
sys/pgmspace.h: Refactor inline asm (#7510)
Browse files Browse the repository at this point in the history
* Refactor asm tabs for `.S` cosmetics

* Avoid fixed regname (`a14`) allocation

* Remove unnecessary explicit cast and word masking
  • Loading branch information
jjsuwa committed Aug 9, 2020
1 parent 79fc0b3 commit fc2426a
Showing 1 changed file with 22 additions and 21 deletions.
43 changes: 22 additions & 21 deletions tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,42 +61,43 @@ extern "C" {
// 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 */ \
"ssa8l %0\n" /* Prepare to shift by offset (in bits) */ \
"src %0, %1, %1\n" /* Shift right; now the requested byte is the first one */ \
:"=r"(res), "=r"(addr) \
:"1"(addr) \
:);
__asm__( \
"extui\t%0, %1, 0, 2\n\t" /* Extract offset within word (in bytes) */ \
"sub\t%1, %1, %0\n\t" /* Subtract offset from addr, yielding an aligned address */ \
"l32i.n\t%1, %1, 0\n\t" /* Load word from aligned address */ \
"ssa8l\t%0\n\t" /* Prepare to shift by offset (in bits) */ \
"src\t%0, %1, %1" /* Shift right; now the requested byte is the first one */ \
: "=r"(res), "+r"(addr))

#define pgm_read_dword_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 a14, %1, 0\n" \
"l32i %1, %1, 4\n" \
"ssa8l %0\n" \
"src %0, %1, a14\n" \
:"=r"(res), "=r"(addr) \
:"1"(addr) \
:"a14");
do { \
uint32_t temp; \
__asm__( \
"extui\t%0, %1, 0, 2\n\t" /* Extract offset within word (in bytes) */ \
"sub\t%1, %1, %0\n\t" /* Subtract offset from addr, yielding an aligned address */ \
"l32i.n\t%2, %1, 0\n\t" /* Load 2 words */ \
"l32i.n\t%1, %1, 4\n\t" /* from aligned address */ \
"ssa8l\t%0\n\t" /* Prepare to shift by offset (in bits) */ \
"src\t%0, %1, %2" /* Shift right in order to extract the requested dword */ \
: "=r"(res), "+r"(addr), "=r"(temp)); \
} while(0)

static inline uint8_t pgm_read_byte_inlined(const void* addr) {
uint32_t res;
pgm_read_with_offset(addr, res);
return (uint8_t) res; /* This masks the lower byte from the returned word */
return res; /* Implicit cast to uint8_t 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) {
uint32_t res;
pgm_read_with_offset(addr, res);
return (uint16_t) res; /* This masks the lower half-word from the returned word */
return res; /* Implicit cast to uint16_t masks the lower half-word from the returned word */
}

/* Can't legally cast bits of uint32_t to a float w/o conversion or std::memcpy, which is inefficient. */
/* The ASM block doesn't care the type, so just pass in what C thinks is a float and return in custom fcn. */
static inline float pgm_read_float_unaligned(const void *addr) {
static inline float pgm_read_float_unaligned(const void* addr) {
float res;
pgm_read_with_offset(addr, res);
return res;
Expand All @@ -121,7 +122,7 @@ static inline uint32_t pgm_read_dword_unaligned(const void *addr) {
}

#define pgm_read_ptr_unaligned(addr) ((void*)pgm_read_dword_unaligned(addr))
#define pgm_read_word_unaligned(addr) ((uint16_t)(pgm_read_dword_unaligned(addr) & 0xffff))
#define pgm_read_word_unaligned(addr) ((uint16_t)pgm_read_dword_unaligned(addr))


// Allow selection of _aligned or _unaligned, but default to _unaligned for Arduino compatibility
Expand Down

0 comments on commit fc2426a

Please sign in to comment.