Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion ext/gcc/modm_atomic.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ __atomic_compare_exchange_{{len//8}}(volatile void *ptr, void *expected, {{len|u
%% endmacro

// ================================ lock free =================================
#ifndef __clang__
extern "C" [[gnu::always_inline]] inline bool
__atomic_is_lock_free (unsigned int object_size, const volatile void *ptr)
{
Expand All @@ -161,7 +162,7 @@ __atomic_is_lock_free (unsigned int object_size, const volatile void *ptr)
return ((uintptr_t)ptr & (object_size - 1)) == 0;
return false;
}

#endif // __clang__

%% macro atomic_fetch(len)
%% for name, op in [("and", "&"), ("or", "|"), ("xor", "^"), ("nand", "&")]
Expand Down
9 changes: 9 additions & 0 deletions src/modm/architecture/interface/interrupt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,20 @@
# define MODM_ISR_CALL(vector) \
MODM_ISR_VALIDATE(#vector, vector); \
vector ## _IRQHandler()

#ifdef MODM_COMPILER_CLANG
# define MODM_ISR(vector, ...) \
MODM_ISR_VALIDATE(#vector, vector); \
modm_extern_c void vector ## _IRQHandler(void) \
__attribute__((used)) __VA_ARGS__; \
void vector ## _IRQHandler(void)
#else
# define MODM_ISR(vector, ...) \
MODM_ISR_VALIDATE(#vector, vector); \
modm_extern_c void vector ## _IRQHandler(void) \
__attribute__((externally_visible)) __VA_ARGS__; \
void vector ## _IRQHandler(void)
#endif // MODM_COMPILER_CLANG

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add modm_externally_visible to the utils file, which is meant to abstract these compiler/platform differences.


#else

Expand Down
10 changes: 10 additions & 0 deletions src/modm/io/iostream.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -192,13 +192,23 @@ public:
%% endif

%% if core.startswith("cortex-m")
#ifdef __clang__
// For ARM 'int32_t' is of type 'int'. Therefore there is no
// function here for the default type 'long'. As 'long' has the same
// width as 'int32_t' we just use a typedef here.
inline IOStream& operator << (const long& v)
{ writeIntegerMode(static_cast<int32_t>(v)); return *this; }
inline IOStream& operator << (const unsigned long& v)
{ writeIntegerMode(static_cast<uint32_t>(v)); return *this; }
#else
// For ARM 'int32_t' is of type 'long'. Therefore there is no
// function here for the default type 'int'. As 'int' has the same
// width as 'int32_t' we just use a typedef here.
inline IOStream& operator << (const int& v)
{ writeIntegerMode(static_cast<int32_t>(v)); return *this; }
inline IOStream& operator << (const unsigned int& v)
{ writeIntegerMode(static_cast<uint32_t>(v)); return *this; }
#endif
Comment thread
salkinium marked this conversation as resolved.
%% endif

%% if options.with_float
Expand Down
36 changes: 20 additions & 16 deletions src/modm/math/utils/arithmetic_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Copyright (c) 2012, 2014, Niklas Hauser
* Copyright (c) 2013, 2015, Sascha Schade
* Copyright (c) 2015, Kevin Läufer
* Copyright (c) 2018, Christopher Durand
* Copyright (c) 2018, 2026, Christopher Durand
* Copyright (c) 2022, Raphael Lehmann
*
* This file is part of the modm project.
Expand All @@ -18,11 +18,14 @@
#ifndef MODM_ARITHMETIC_TRAITS_HPP
#define MODM_ARITHMETIC_TRAITS_HPP

#include <concepts>
#include <cstdint>
#include <limits>
#include <type_traits>
#include <cmath>

#include <modm/math/utils/cmath.hpp>

namespace modm
{

Expand Down Expand Up @@ -97,13 +100,9 @@ namespace detail
struct WideType<unsigned long long>
{ using type = double; };

template<typename T, typename = std::enable_if_t<
std::is_integral_v<T> && !std::is_same_v<std::decay_t<T>, bool>
> >
using enable_if_int = T;

template<typename T>
struct WideType<enable_if_int<T>>
template<std::integral T>
requires (!std::is_same_v<std::remove_cv_t<T>, bool>)
struct WideType<T>
{
static constexpr bool isNextIntLarger =
std::numeric_limits<typename NextInt<T>::type>::max() > std::numeric_limits<T>::max();
Expand All @@ -123,8 +122,9 @@ namespace detail
using type = T;
};

template<typename T>
struct MakeSigned<enable_if_int<T>>
template<std::integral T>
requires (!std::is_same_v<std::remove_cv_t<T>, bool>)
struct MakeSigned<T>
{
using type = std::make_signed_t<T>;
};
Expand All @@ -135,8 +135,9 @@ namespace detail
using type = T;
};

template<typename T>
struct MakeUnsigned<enable_if_int<T>>
template<std::integral T>
requires (!std::is_same_v<std::remove_cv_t<T>, bool>)
struct MakeUnsigned<T>
{
using type = std::make_unsigned_t<T>;
};
Expand All @@ -149,10 +150,10 @@ template<typename T>
using WideType = typename detail::WideType<T>::type;

template<typename T>
using SignedType = typename detail::MakeSigned<T>::type;
using SignedType [[deprecated("use std::make_signed_t")]] = typename detail::MakeSigned<T>::type; // DEPRECATED: 2026q3

template<typename T>
using UnsignedType = typename detail::MakeUnsigned<T>::type;
using UnsignedType [[deprecated("use std::make_unsigned_t")]] = typename detail::MakeUnsigned<T>::type; // DEPRECATED: 2026q3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
using UnsignedType [[deprecated("use std::make_unsigned_t")]] = typename detail::MakeUnsigned<T>::type; // DEPRECATED: 2026q3
using UnsignedType [[deprecated("use std::make_unsigned_t")]] = typename detail::MakeUnsigned<T>::type; // DEPRECATED: 2027q2

Historically we've given people 1y before we remove deprecation notices, due to them maybe skipping a few releases.


/**
* Arithmetic Traits
Expand All @@ -176,13 +177,16 @@ using UnsignedType = typename detail::MakeUnsigned<T>::type;
* @endcode
*/
template<typename T>
struct ArithmeticTraits
struct [[deprecated("use std::numeric_limits instead")]] ArithmeticTraits // DEPRECATED: 2026q3
{
static constexpr bool isInteger = std::is_integral_v<T>
&& !std::is_same_v<std::decay_t<T>, bool>;

// log10(2), not constexpr yet with clang
static constexpr auto log10_2 = 0.3010299956639812;

static constexpr unsigned char decimalDigits =
std::ceil(std::numeric_limits<T>::digits * log10(2)) + (std::is_signed_v<T> ? 1 : 0);
modm::ceil(std::numeric_limits<T>::digits * log10_2) + (std::is_signed_v<T> ? 1 : 0);
};
/// @}

Expand Down
161 changes: 161 additions & 0 deletions src/modm/math/utils/cmath.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2026, Christopher Durand
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include <cmath>
#include <concepts>
#include <limits>
#include <modm/architecture/detect.hpp>

namespace modm::detail
{

template<std::floating_point T>
consteval T
consteval_ceil(T value)
{
static_assert(std::numeric_limits<T>::is_iec559);

// handle NaN
if (value != value) return value;

constexpr auto mantissaDigits = std::numeric_limits<T>::digits;
static_assert(std::numeric_limits<long long>::digits >= mantissaDigits);

// calculate magnitude limit outside which all values must be integral
constexpr auto limit = T{1ll << (mantissaDigits - 1)};
if (value >= limit || value <= -limit) {
return value;
}

const auto truncated = static_cast<T>(static_cast<long long>(value));
if (value <= T{0}) {
// preserve sign of zero, e.g. ceil(-0.5f) = -0.0f
if (truncated == 0) {
return value * 0;
}

return truncated;
} else {
return (value > truncated) ? (truncated + T{1}) : truncated;
}
}

template<std::floating_point T>
consteval T
consteval_floor(T value)
{
// handle NaN
if (value != value) return value;

constexpr auto mantissaDigits = std::numeric_limits<T>::digits;
static_assert(std::numeric_limits<long long>::digits >= mantissaDigits);

// calculate magnitude limit outside which all values must be integral
constexpr auto limit = T{1ll << (mantissaDigits - 1)};
if (value >= limit || value <= -limit) {
return value;
}

// preserve sign of zero, floor(-0.0f) = -0.0f
if (value == T{0}) {
return value;
}

const auto truncated = static_cast<T>(static_cast<long long>(value));
if (value >= T{0}) {
return truncated;
} else {
return (value < truncated) ? (truncated - T{1}) : truncated;
}
}

template <std::floating_point T>
consteval T
consteval_round(T value)
{
// handle NaN
if (value != value) return value;

constexpr auto mantissaDigits = std::numeric_limits<T>::digits;
static_assert(std::numeric_limits<long long>::digits >= mantissaDigits);

// calculate magnitude limit outside which all values must be integral
constexpr auto limit = T{1ll << (mantissaDigits - 1)};
if (value >= limit || value <= -limit) {
return value;
}

const auto truncated = static_cast<T>(static_cast<long long>(value));
const auto fraction = value - truncated;

if (std::signbit(value)) {
if (fraction <= T{-0.5}) return truncated - T{1};
if (truncated == 0) return value * T{0};
return truncated;
} else {
if (fraction >= T{0.5}) return truncated + T{1};
return truncated;
}
}

} // namespace modm::detail

namespace modm
{

template<std::floating_point T>
constexpr T
ceil(T value)
{
#ifdef MODM_COMPILER_CLANG
if consteval {
return detail::consteval_ceil(value);
} else {
return std::ceil(value);
}
#else
return std::ceil(value);
#endif
}

template<std::floating_point T>
constexpr T
floor(T value)
{
#ifdef MODM_COMPILER_CLANG
if consteval {
return detail::consteval_floor(value);
} else {
return std::floor(value);
}
#else
return std::floor(value);
#endif
}

template<std::floating_point T>
constexpr T
round(T value)
{
#ifdef MODM_COMPILER_CLANG
if consteval {
return detail::consteval_round(value);
} else {
return std::round(value);
}
#else
return std::round(value);
#endif
}

} // namespace modm
6 changes: 4 additions & 2 deletions src/modm/platform/clock/sam/gclk_impl.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <limits>
#include <bit>

#include <modm/math/utils/cmath.hpp>

namespace modm::platform
{
extern "C" uint32_t SystemCoreClock;
Expand Down Expand Up @@ -97,7 +99,7 @@ GenericClockController::enableDfll48mClosedLoop(uint32_t waitCycles)
{
static_assert(reference > 732_Hz, "DFLL48 reference frequency must be larger than 732 Hz");
static_assert(reference < 43_kHz, "DFLL48 reference frequency must be less than 33 kHz");
constexpr auto multiplier = uint16_t(std::round(48_MHz / double(reference)));
constexpr auto multiplier = uint16_t(modm::round(48_MHz / double(reference)));

%% if target.family == "d1x/d2x/dax"
// Errata 1.2.1: Disable OnDemand mode
Expand Down Expand Up @@ -389,7 +391,7 @@ findDpllConfig(double inputClock, double target, bool fractional)
}
// f_pll = f_reference * (1 + N_int + N_frac/(2^frac_bits))
const auto idealMultiplier = (target / inputClock) - 1;
const uint32_t multplier = std::min<uint32_t>(maxMultiplier, std::round(idealMultiplier));
const uint32_t multplier = std::min<uint32_t>(maxMultiplier, modm::round(idealMultiplier));
if (fractional) {
const auto output = inputClock * (multplier + 1) / (1u << DpllConfig::MultiplierFractionalBits);
return DpllConfigCalculation {
Expand Down
2 changes: 1 addition & 1 deletion src/modm/platform/clock/sam/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def prepare(module, options):
if not options[":target"].has_driver("gclk:sam"):
return False

module.depends(":cmsis:device", ":architecture:delay", ":platform:clock")
module.depends(":cmsis:device", ":architecture:delay", ":math:utils", ":platform:clock")
return True

def build(env):
Expand Down
4 changes: 3 additions & 1 deletion src/modm/platform/core/cortex/delay_impl.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include <modm/architecture/interface/assert.hpp>
%% endif

#include <modm/math/utils/cmath.hpp>

/// @cond
#define MODM_DELAY_NS_IS_ACCURATE 1

Expand All @@ -34,7 +36,7 @@ extern uint16_t delay_fcpu_MHz;

constexpr uint8_t delay_fcpu_MHz_shift({{us_shift}});
constexpr uint16_t computeDelayMhz(uint32_t hz)
{ return std::round(hz / 1'000'000.f * (1ul << delay_fcpu_MHz_shift)); }
{ return modm::round(hz / 1'000'000.f * (1ul << delay_fcpu_MHz_shift)); }
}

modm_always_inline
Expand Down
4 changes: 2 additions & 2 deletions src/modm/platform/core/cortex/delay_ns.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
// ----------------------------------------------------------------------------

#pragma once
#include <cmath>
#include <modm/math/utils/cmath.hpp>

/// @cond
namespace modm::platform
Expand All @@ -21,7 +21,7 @@ void delay_ns(uint32_t ns);
constexpr uint16_t
computeDelayNsPerLoop(uint32_t hz)
{
return std::round({{loop}}'000'000'000.0 / hz);
return modm::round({{loop}}'000'000'000.0 / hz);
}

}
Expand Down
Loading
Loading