From ffa0a2b825a897740398ac28baecc14c38a9a08b Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 3 Oct 2019 07:39:11 -0700 Subject: [PATCH] Fix pgm_read_float_unaligned macro Fixes #6590 The ASM block that implements the read-uint32-unaligned returns a uint32_t. The old code was doing a cast like `(float)(uint32_t ret) which actually goes and creates a new float of the positive uint value (approx, of course due to exponent and sign bits) which is not correct. C and C++ don't have a concise way to convert the bits in a register from int to float interpretation, so avoid the whole issue by making a new function which uses the same ASM block as the read-uint32-unaligned, just make the destination and return values as floats. --- tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h b/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h index 3613455bb8..ce0dc78b3e 100644 --- a/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h +++ b/tools/sdk/libc/xtensa-lx106-elf/include/sys/pgmspace.h @@ -80,6 +80,14 @@ static inline uint16_t pgm_read_word_inlined(const void* addr) { return (uint16_t) res; /* This 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) { + register float res; + pgm_read_with_offset(addr, res); + return res; +} + #define pgm_read_byte(addr) pgm_read_byte_inlined(addr) #define pgm_read_word_aligned(addr) pgm_read_word_inlined(addr) #ifdef __cplusplus @@ -98,7 +106,6 @@ static inline uint32_t pgm_read_dword_unaligned(const void *addr) { return res; } -#define pgm_read_float_unaligned(addr) ((float)pgm_read_dword_unaligned(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))