From d77c39e352c17bc69fafd84cf745da7c186d2e38 Mon Sep 17 00:00:00 2001 From: MCUdude Date: Sat, 21 Jan 2023 19:40:51 +0100 Subject: [PATCH] Squashed 'avr/cores/MCUdude_corefiles/' changes from 0d56ecc53..55de1dc14 55de1dc14 ISO c++ doesn't support binary contants however GNU c++ does c3890dc86 Fix weak attributions on operator new and delete 22d364ecc Mute unused variable warnings 2ffc04d4f Update abi and new It's now up to date with the one ArduinoCore-avr uses 133dcfd3d Fix unused variable and guard warning 7827dd8b3 Improve how TXCn bit is cleared in USCRnA register Preserve values of configuration bits MPCMn and U2Xn. Avoid setting other read-only bits for datasheet conformance. See https://github.com/arduino/ArduinoCore-avr/issues/120 for details 6103f33f3 Formatting c8bef0bf5 Improvements to HardwareSerial.cpp 45437133d Add null pointer check to String destructor 811b51677 Adding parenthesis around 'bitvalue' allowing correct macro expansion when using with ternary operator such as bitWrite(value, bit, some_computed_value == 5 ? 1: 0); e16f14c78 Add bitToggle macro 221900dc9 Removes unnecessary if branch(because length is checked in while statement below the if-clause). 13d1f7607 Improve wiring_shift function 64786bc16 Use ADC instead of combining ADCL and ADCH git-subtree-dir: avr/cores/MCUdude_corefiles git-subtree-split: 55de1dc14dc8c530388cb162564b6e1c95eb7a39 --- Arduino.h | 3 +- HardwareSerial.cpp | 62 ++++++++++++++++++++-------- Stream.cpp | 1 - Tone.cpp | 34 +++++++-------- WString.cpp | 3 +- abi.cpp | 15 +++---- new | 66 ++++++++++++++++++++++++++++++ new.cpp | 100 +++++++++++++++++++++++++++++++++++++-------- new.h | 39 ++---------------- wiring_analog.c | 24 ++++------- wiring_shift.c | 14 ++++--- 11 files changed, 242 insertions(+), 119 deletions(-) mode change 100755 => 100644 abi.cpp create mode 100644 new mode change 100755 => 100644 new.cpp mode change 100755 => 100644 new.h diff --git a/Arduino.h b/Arduino.h index 4796f2197..8f66e32fb 100755 --- a/Arduino.h +++ b/Arduino.h @@ -152,7 +152,8 @@ void yield(void); #define bitRead(value, bit) (((value) >> (bit)) & 0x01) #define bitSet(value, bit) ((value) |= (1UL << (bit))) #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) -#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) +#define bitToggle(value, bit) ((value) ^= (1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) // avr-libc defines _NOP() since 1.6.2 #ifndef _NOP diff --git a/HardwareSerial.cpp b/HardwareSerial.cpp index 048ea69ef..095bd1cb0 100755 --- a/HardwareSerial.cpp +++ b/HardwareSerial.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "Arduino.h" #include "HardwareSerial.h" @@ -76,6 +77,13 @@ void serialEventRun(void) #endif } +// macro to guard critical sections when needed for large TX buffer sizes +#if (SERIAL_TX_BUFFER_SIZE>256) +#define TX_BUFFER_ATOMIC ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#else +#define TX_BUFFER_ATOMIC +#endif + // Actual interrupt handlers ////////////////////////////////////////////////////////////// void HardwareSerial::_tx_udr_empty_irq(void) @@ -89,8 +97,14 @@ void HardwareSerial::_tx_udr_empty_irq(void) // clear the TXC bit -- "can be cleared by writing a one to its bit // location". This makes sure flush() won't return until the bytes - // actually got written - *_ucsra |= _BV(TXC0); + // actually got written. Other r/w bits are preserved, and zeroes + // written to the rest. + + #ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); + #else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); + #endif if (_tx_buffer_head == _tx_buffer_tail) { // Buffer empty, so disable interrupts @@ -174,15 +188,13 @@ int HardwareSerial::read(void) int HardwareSerial::availableForWrite(void) { -#if (SERIAL_TX_BUFFER_SIZE>256) - uint8_t oldSREG = SREG; - cli(); -#endif - tx_buffer_index_t head = _tx_buffer_head; - tx_buffer_index_t tail = _tx_buffer_tail; -#if (SERIAL_TX_BUFFER_SIZE>256) - SREG = oldSREG; -#endif + tx_buffer_index_t head; + tx_buffer_index_t tail; + + TX_BUFFER_ATOMIC { + head = _tx_buffer_head; + tail = _tx_buffer_tail; + } if (head >= tail) return SERIAL_TX_BUFFER_SIZE - 1 - head + tail; return tail - head - 1; } @@ -215,8 +227,22 @@ size_t HardwareSerial::write(uint8_t c) // significantly improve the effective datarate at high (> // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) { - *_udr = c; - *_ucsra |= _BV(TXC0); + // If TXC is cleared before writing UDR and the previous byte + // completes before writing to UDR, TXC will be set but a byte + // is still being transmitted causing flush() to return too soon. + // So writing UDR must happen first. + // Writing UDR and clearing TC must be done atomically, otherwise + // interrupts might delay the TXC clear so the byte written to UDR + // is transmitted (setting TXC) before clearing TXC. Then TXC will + // be cleared when no bytes are left, causing flush() to hang + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + *_udr = c; + #ifdef MPCM0 + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << MPCM0))) | (1 << TXC0); + #else + *_ucsra = ((*_ucsra) & ((1 << U2X0) | (1 << TXC0))); + #endif + } return 1; } tx_buffer_index_t i = (_tx_buffer_head + 1) % SERIAL_TX_BUFFER_SIZE; @@ -237,9 +263,13 @@ size_t HardwareSerial::write(uint8_t c) } _tx_buffer[_tx_buffer_head] = c; - _tx_buffer_head = i; - - *_ucsrb |= _BV(UDRIE0); + // make atomic to prevent execution of ISR between setting the + // head pointer and setting the interrupt flag resulting in buffer + // retransmission + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + _tx_buffer_head = i; + *_ucsrb |= _BV(UDRIE0); + } return 1; } diff --git a/Stream.cpp b/Stream.cpp index f66546532..e717fc154 100755 --- a/Stream.cpp +++ b/Stream.cpp @@ -218,7 +218,6 @@ size_t Stream::readBytes(char *buffer, size_t length) size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { - if (length < 1) return 0; size_t index = 0; while (index < length) { int c = timedRead(); diff --git a/Tone.cpp b/Tone.cpp index d113e32eb..ed289afa2 100755 --- a/Tone.cpp +++ b/Tone.cpp @@ -279,7 +279,7 @@ static int8_t toneBegin(uint8_t _pin) void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) { - uint8_t prescalarbits = 0b001; + uint8_t prescalarbits = 0x01; long toggle_count = 0; uint32_t ocr = 0; int8_t _timer; @@ -295,38 +295,38 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) if (_timer == 0 || _timer == 2) { ocr = F_CPU / frequency / 2 - 1; - prescalarbits = 0b001; // ck/1: same for both timers + prescalarbits = 0x01; // ck/1: same for both timers if (ocr > 255) { ocr = F_CPU / frequency / 2 / 8 - 1; - prescalarbits = 0b010; // ck/8: same for both timers + prescalarbits = 0x02; // ck/8: same for both timers if (_timer == TIMER_WITH_FULL_PRESCALER && ocr > 255) { ocr = F_CPU / frequency / 2 / 32 - 1; - prescalarbits = 0b011; + prescalarbits = 0x03; } if (ocr > 255) { ocr = F_CPU / frequency / 2 / 64 - 1; - prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0b011 : 0b100; + prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0x03 : 0x04; if (_timer == TIMER_WITH_FULL_PRESCALER && ocr > 255) { ocr = F_CPU / frequency / 2 / 128 - 1; - prescalarbits = 0b101; + prescalarbits = 0x05; } if (ocr > 255) { ocr = F_CPU / frequency / 2 / 256 - 1; - prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0b100 : 0b110; + prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0x04 : 0x06; if (ocr > 255) { // Can't do any better than /1024 ocr = F_CPU / frequency / 2 / 1024 - 1; - prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0b101 : 0b111; + prescalarbits = _timer != TIMER_WITH_FULL_PRESCALER ? 0x05 : 0x07; } } } @@ -335,13 +335,13 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) #if defined(TCCR0B) if (_timer == 0) { - TCCR0B = (TCCR0B & 0b11111000) | prescalarbits; + TCCR0B = (TCCR0B & 0xf8) | prescalarbits; } else #endif #if defined(TCCR2B) { - TCCR2B = (TCCR2B & 0b11111000) | prescalarbits; + TCCR2B = (TCCR2B & 0xf8) | prescalarbits; } #else { @@ -354,30 +354,30 @@ void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) // two choices for the 16 bit timers: ck/1 or ck/64 ocr = F_CPU / frequency / 2 - 1; - prescalarbits = 0b001; + prescalarbits = 0x01; if (ocr > 0xffff) { ocr = F_CPU / frequency / 2 / 64 - 1; - prescalarbits = 0b011; + prescalarbits = 0x03; } if (_timer == 1) { #if defined(TCCR1B) - TCCR1B = (TCCR1B & 0b11111000) | prescalarbits; + TCCR1B = (TCCR1B & 0xf8) | prescalarbits; #endif } #if defined(TCCR3B) else if (_timer == 3) - TCCR3B = (TCCR3B & 0b11111000) | prescalarbits; + TCCR3B = (TCCR3B & 0xf8) | prescalarbits; #endif #if defined(TCCR4B) else if (_timer == 4) - TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; + TCCR4B = (TCCR4B & 0xf8) | prescalarbits; #endif #if defined(TCCR5B) else if (_timer == 5) - TCCR5B = (TCCR5B & 0b11111000) | prescalarbits; + TCCR5B = (TCCR5B & 0xf8) | prescalarbits; #endif } @@ -486,7 +486,7 @@ void disableTimer(uint8_t _timer) TCCR2A = (1 << WGM20); #endif #if defined(TCCR2B) && defined(CS22) - TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); + TCCR2B = (TCCR2B & 0xf8) | (1 << CS22); #endif #if defined(OCR2A) OCR2A = 0; diff --git a/WString.cpp b/WString.cpp index 2e2a7aff4..ca06d4eea 100755 --- a/WString.cpp +++ b/WString.cpp @@ -121,7 +121,8 @@ String::String(double value, unsigned char decimalPlaces) String::~String() { - free(buffer); + if(buffer) + free(buffer); } /*********************************************/ diff --git a/abi.cpp b/abi.cpp old mode 100755 new mode 100644 index 8d719b8e6..6e1b0f8af --- a/abi.cpp +++ b/abi.cpp @@ -21,15 +21,16 @@ extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__)); extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__)); +namespace std { + [[gnu::weak, noreturn]] void terminate() { + abort(); + } +} + void __cxa_pure_virtual(void) { - // We might want to write some diagnostics to uart in this case - //std::terminate(); - abort(); + std::terminate(); } void __cxa_deleted_virtual(void) { - // We might want to write some diagnostics to uart in this case - //std::terminate(); - abort(); + std::terminate(); } - diff --git a/new b/new new file mode 100644 index 000000000..8f2fa0e43 --- /dev/null +++ b/new @@ -0,0 +1,66 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef NEW_H +#define NEW_H + +#include + +namespace std { + struct nothrow_t {}; + extern const nothrow_t nothrow; + + // These are not actually implemented, to prevent overhead and + // complexity. They are still declared to allow implementing + // them in user code if needed. + typedef void (*new_handler)(); + new_handler set_new_handler(new_handler new_p) noexcept; + new_handler get_new_handler() noexcept; + + // This is normally declared in various headers that we do not have + // available, so just define it here. We could also use ::size_t + // below, but then anyone including can no longer assume + // std::size_t is available. + using size_t = ::size_t; +} // namespace std + +void * operator new(std::size_t size); +void * operator new[](std::size_t size); + +void * operator new(std::size_t size, const std::nothrow_t tag) noexcept; +void * operator new[](std::size_t size, const std::nothrow_t& tag) noexcept; + +void * operator new(std::size_t size, void *place) noexcept; +void * operator new[](std::size_t size, void *place) noexcept; + +void operator delete(void * ptr) noexcept; +void operator delete[](void * ptr) noexcept; + +#if __cplusplus >= 201402L +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete[](void * ptr, std::size_t size) noexcept; +#endif // __cplusplus >= 201402L + +void operator delete(void* ptr, const std::nothrow_t& tag) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept; + +void operator delete(void* ptr, void* place) noexcept; +void operator delete[](void* ptr, void* place) noexcept; + +#endif + diff --git a/new.cpp b/new.cpp old mode 100755 new mode 100644 index 614e4e5e9..768bf0f88 --- a/new.cpp +++ b/new.cpp @@ -16,36 +16,102 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include +#include "new.h" -void *operator new(size_t size) { - return malloc(size); +// The C++ spec dictates that allocation failure should cause the +// (non-nothrow version of the) operator new to throw an exception. +// Since we expect to have exceptions disabled, it would be more +// appropriate (and probably standards-compliant) to terminate instead. +// Historically failure causes null to be returned, but this define +// allows switching to more robust terminating behaviour (that might +// become the default at some point in the future). Note that any code +// that wants null to be returned can (and should) use the nothrow +// versions of the new statement anyway and is unaffected by this. +// #define NEW_TERMINATES_ON_FAILURE + +namespace std { + // Defined in abi.cpp + void terminate(); + + const nothrow_t nothrow; } -void *operator new[](size_t size) { +static void * new_helper(std::size_t size) { + // Even zero-sized allocations should return a unique pointer, but + // malloc does not guarantee this + if (size == 0) + size = 1; return malloc(size); } +[[gnu::weak]] void * operator new(std::size_t size) { + void *res = new_helper(size); +#if defined(NEW_TERMINATES_ON_FAILURE) + if (!res) + std::terminate(); +#endif + return res; +} -void operator delete(void * ptr) { - free(ptr); +[[gnu::weak]] void * operator new[](std::size_t size) { + return operator new(size); } -void operator delete[](void * ptr) { - free(ptr); +[[gnu::weak]] void * operator new(std::size_t size, [[gnu::unused]] const std::nothrow_t tag) noexcept { +#if defined(NEW_TERMINATES_ON_FAILURE) + // Cannot call throwing operator new as standard suggests, so call + // new_helper directly then + return new_helper(size); +#else + return operator new(size); +#endif +} +[[gnu::weak]] void * operator new[](std::size_t size, [[gnu::unused]] const std::nothrow_t& tag) noexcept { +#if defined(NEW_TERMINATES_ON_FAILURE) + // Cannot call throwing operator new[] as standard suggests, so call + // malloc directly then + return new_helper(size); +#else + return operator new[](size); +#endif +} + +void * operator new(std::size_t size, void *place) noexcept { + // Nothing to do + (void)size; // unused + return place; +} +void * operator new[](std::size_t size, void *place) noexcept { + return operator new(size, place); } +[[gnu::weak]] void operator delete(void * ptr) noexcept { + free(ptr); +} +[[gnu::weak]] void operator delete[](void * ptr) noexcept { + operator delete(ptr); +} -// C++14 introduces additional delete operators #if __cplusplus >= 201402L - -void operator delete(void * ptr, size_t) -{ - ::operator delete(ptr); +[[gnu::weak]] void operator delete(void* ptr, [[gnu::unused]] std::size_t size) noexcept { + operator delete(ptr); } +[[gnu::weak]] void operator delete[](void * ptr, [[gnu::unused]] std::size_t size) noexcept { + operator delete[](ptr); +} +#endif // __cplusplus >= 201402L -void operator delete[](void * ptr, size_t) -{ - ::operator delete(ptr); +[[gnu::weak]] void operator delete(void* ptr, [[gnu::unused]] const std::nothrow_t& tag) noexcept { + operator delete(ptr); +} +[[gnu::weak]] void operator delete[](void* ptr, [[gnu::unused]] const std::nothrow_t& tag) noexcept { + operator delete[](ptr); } -#endif // end language is C++14 or greater +void operator delete(void* ptr, void* place) noexcept { + (void)ptr; (void)place; // unused + // Nothing to do +} +void operator delete[](void* ptr, void* place) noexcept { + (void)ptr; (void)place; // unused + // Nothing to do +} diff --git a/new.h b/new.h old mode 100755 new mode 100644 index a8a270502..d52985368 --- a/new.h +++ b/new.h @@ -1,36 +1,3 @@ -/* - Copyright (c) 2014 Arduino. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef NEW_H -#define NEW_H - -#include - -void * operator new(size_t size); -void * operator new[](size_t size); -void operator delete(void * ptr); -void operator delete[](void * ptr); - -// C++14 introduces additional delete operators -#if __cplusplus >= 201402L -void operator delete(void * ptr, size_t); -void operator delete[](void * ptr, size_t); -#endif // end language is C++14 or greater - -#endif - +// This file originally used a non-standard name for this Arduino core +// only, so still expose the old new.h name for compatibility. +#include "new" diff --git a/wiring_analog.c b/wiring_analog.c index 640100316..8f6c2a9ca 100755 --- a/wiring_analog.c +++ b/wiring_analog.c @@ -43,7 +43,6 @@ void analogReference(uint8_t mode) int analogRead(uint8_t pin) { - uint8_t low, high; // Macro located in the pins_arduino.h file #ifdef analogPinToChannel @@ -72,27 +71,19 @@ int analogRead(uint8_t pin) // without a delay, we seem to read from the wrong channel //delay(1); -#if defined(ADCSRA) && defined(ADCL) +#if defined(ADCSRA) && defined(ADC) // start the conversion ADCSRA |= _BV(ADSC); // ADSC is cleared when the conversion finishes - while (ADCSRA & _BV(ADSC)); - - // we have to read ADCL first; doing so locks both ADCL - // and ADCH until ADCH is read. reading ADCL second would - // cause the results of each conversion to be discarded, - // as ADCL and ADCH would be locked when it completed. - low = ADCL; - high = ADCH; + while (ADCSRA & _BV(ADSC)) {}; + + // ADC macro takes care of reading ADC register. + // avr-gcc implements the proper reading order: ADCL is read first. + return ADC; #else - // we dont have an ADC, return 0 - low = 0; - high = 0; + return 0; #endif - - // combine the two bytes - return (high << 8) | low; } @@ -306,4 +297,3 @@ void analogWrite(uint8_t pin, int val) } } } - diff --git a/wiring_shift.c b/wiring_shift.c index 83ab448c4..2aefa6bef 100755 --- a/wiring_shift.c +++ b/wiring_shift.c @@ -42,12 +42,14 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) uint8_t i; for (i = 0; i < 8; i++) { - if (bitOrder == LSBFIRST) - digitalWrite(dataPin, !!(val & (1 << i))); - else - digitalWrite(dataPin, !!(val & (1 << (7 - i)))); - + if (bitOrder == LSBFIRST) { + digitalWrite(dataPin, val & 1); + val >>= 1; + } else { + digitalWrite(dataPin, (val & 0x80) != 0); + val <<= 1; + } digitalWrite(clockPin, HIGH); - digitalWrite(clockPin, LOW); + digitalWrite(clockPin, LOW); } }