From c4700ed824db0257681a8ec4ff1839a537889da8 Mon Sep 17 00:00:00 2001 From: BlackMark Date: Sat, 10 Aug 2019 14:12:10 +0200 Subject: [PATCH] Fixed non-compliant use of constexpr for pointers --- hardware.hpp | 38 +++++++++++++++++++++++--------------- hardware0.hpp | 27 +++++++++++++++++++++------ hardware1.hpp | 27 +++++++++++++++++++++------ uart.hpp | 2 +- 4 files changed, 66 insertions(+), 28 deletions(-) diff --git a/hardware.hpp b/hardware.hpp index 945e4cd..abbc535 100644 --- a/hardware.hpp +++ b/hardware.hpp @@ -23,6 +23,14 @@ enum class Driven { namespace detail { +using reg_ptr_t = volatile uint8_t *; + +template +static inline reg_ptr_t getRegPtr() +{ + return reinterpret_cast(Address); +} + template class Hardware { @@ -31,8 +39,8 @@ class Hardware { { constexpr auto baudVal = calcBaud(); - *Registers::BAUD_REG_H = static_cast(baudVal >> 8); - *Registers::BAUD_REG_L = static_cast(baudVal); + *getRegPtr() = static_cast(baudVal >> 8); + *getRegPtr() = static_cast(baudVal); constexpr auto dataBitsVal = calcDataBits(); constexpr auto parityVal = calcParity(); @@ -45,14 +53,14 @@ class Hardware { constexpr uint8_t controlRegB = dataBitsVal.regBVal | enableRx | enableTx | interruptVal; constexpr uint8_t controlRegC = dataBitsVal.regCVal | parityVal | stopBitsVal | modeVal; - *Registers::CTRL_STAT_REG_B = controlRegB; - *Registers::CTRL_STAT_REG_C = controlRegC; + *getRegPtr() = controlRegB; + *getRegPtr() = controlRegC; } static bool rxByteBlocking(typename cfg::data_t &byte) FORCE_INLINE { - if (*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) { - byte = *Registers::IO_REG; + if (*getRegPtr() & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) { + byte = *getRegPtr(); return true; } @@ -61,22 +69,22 @@ class Hardware { static typename cfg::data_t rxByteInterrupt() FORCE_INLINE { - return *Registers::IO_REG; + return *getRegPtr(); } static bool txEmpty() FORCE_INLINE { - return *Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::DATA_REG_EMPTY); + return *getRegPtr() & (1 << CtrlFlagsA::DATA_REG_EMPTY); } static bool txComplete() FORCE_INLINE { - return *Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::TRANSMIT_COMPLETE); + return *getRegPtr() & (1 << CtrlFlagsA::TRANSMIT_COMPLETE); } static void clearTxComplete() FORCE_INLINE { - *Registers::CTRL_STAT_REG_A |= (1 << CtrlFlagsA::TRANSMIT_COMPLETE); + *getRegPtr() |= (1 << CtrlFlagsA::TRANSMIT_COMPLETE); } static void txByteBlocking(const typename cfg::data_t &byte) FORCE_INLINE @@ -84,17 +92,17 @@ class Hardware { while (!txEmpty()) ; - *Registers::IO_REG = byte; + *getRegPtr() = byte; } static void txByteInterrupt(volatile const typename cfg::data_t &byte) FORCE_INLINE { - *Registers::IO_REG = byte; + *getRegPtr() = byte; } static bool peekBlocking() FORCE_INLINE { - if (*Registers::CTRL_STAT_REG_A & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) { + if (*getRegPtr() & (1 << CtrlFlagsA::RECEIVE_COMPLETE)) { return true; } @@ -103,12 +111,12 @@ class Hardware { static void enableDataRegEmptyInt() FORCE_INLINE { - *Registers::CTRL_STAT_REG_B |= (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE); + *getRegPtr() |= (1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE); } static void disableDataRegEmptyInt() FORCE_INLINE { - *Registers::CTRL_STAT_REG_B &= ~(1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE); + *getRegPtr() &= ~(1 << CtrlFlagsB::DATA_REG_EMPTY_INT_ENABLE); } private: diff --git a/hardware0.hpp b/hardware0.hpp index f46080e..93c5f4d 100644 --- a/hardware0.hpp +++ b/hardware0.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "config.hpp" #include "hardware.hpp" @@ -16,15 +17,29 @@ namespace detail { #if defined(__AVR_ATmega1284P__) +/* +The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's + constexpr auto *foo = ptr; + +Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site +For this to work we need to temporarily disable the _SFR_MEM8 macro so that the register macro just gives the address +*/ + +#undef _SFR_MEM8 +#define _SFR_MEM8 + struct Registers0 { - static constexpr volatile auto *IO_REG = &UDR0; - static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR0A; - static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR0B; - static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR0C; - static constexpr volatile auto *BAUD_REG_L = &UBRR0L; - static constexpr volatile auto *BAUD_REG_H = &UBRR0H; + static constexpr uintptr_t IO_REG_ADDR = UDR0; + static constexpr uintptr_t CTRL_STAT_REG_A_ADDR = UCSR0A; + static constexpr uintptr_t CTRL_STAT_REG_B_ADDR = UCSR0B; + static constexpr uintptr_t CTRL_STAT_REG_C_ADDR = UCSR0C; + static constexpr uintptr_t BAUD_REG_L_ADDR = UBRR0L; + static constexpr uintptr_t BAUD_REG_H_ADDR = UBRR0H; }; +#undef _SFR_MEM8 +#define _SFR_MEM8(mem_addr) _MMIO_BYTE(mem_addr) + enum class ControlFlagsA0 { MULTI_PROC_COMM_MODE = MPCM0, SPEED_2X = U2X0, diff --git a/hardware1.hpp b/hardware1.hpp index 925e878..b666379 100644 --- a/hardware1.hpp +++ b/hardware1.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "config.hpp" #include "hardware.hpp" @@ -16,15 +17,29 @@ namespace detail { #if defined(__AVR_ATmega1284P__) +/* +The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's + constexpr auto *foo = ptr; + +Workaround is to store the the address of the ptr in a uintptr_t and reinterpret_cast it at call site +For this to work we need to temporarily disable the _SFR_MEM8 macro so that the register macro just gives the address +*/ + +#undef _SFR_MEM8 +#define _SFR_MEM8 + struct Registers1 { - static constexpr volatile auto *IO_REG = &UDR1; - static constexpr volatile auto *CTRL_STAT_REG_A = &UCSR1A; - static constexpr volatile auto *CTRL_STAT_REG_B = &UCSR1B; - static constexpr volatile auto *CTRL_STAT_REG_C = &UCSR1C; - static constexpr volatile auto *BAUD_REG_L = &UBRR1L; - static constexpr volatile auto *BAUD_REG_H = &UBRR1H; + static constexpr uintptr_t IO_REG_ADDR = UDR1; + static constexpr uintptr_t CTRL_STAT_REG_A_ADDR = UCSR1A; + static constexpr uintptr_t CTRL_STAT_REG_B_ADDR = UCSR1B; + static constexpr uintptr_t CTRL_STAT_REG_C_ADDR = UCSR1C; + static constexpr uintptr_t BAUD_REG_L_ADDR = UBRR1L; + static constexpr uintptr_t BAUD_REG_H_ADDR = UBRR1H; }; +#undef _SFR_MEM8 +#define _SFR_MEM8(mem_addr) _MMIO_BYTE(mem_addr) + enum class ControlFlagsA1 { MULTI_PROC_COMM_MODE = MPCM1, SPEED_2X = U2X1, diff --git a/uart.hpp b/uart.hpp index 8e199ef..77aa096 100644 --- a/uart.hpp +++ b/uart.hpp @@ -258,7 +258,7 @@ class Uart { Uart &operator<<(const void *val) { txString(F("0x")); - txNumber(reinterpret_cast(val)); + txNumber(reinterpret_cast(val)); return *this; }