diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 183fbb2c7..3f8247226 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -145,7 +146,7 @@ struct value : public expr_base> { // These functions ensure that a conversion is never out of range, and should be always used, if at all // possible, instead of direct manipulation of the `data` member. For very large types, .slice() and // .concat() can be used to split them into more manageable parts. - template + template::value, int>::type = 0> CXXRTL_ALWAYS_INLINE IntegerT get() const { static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, @@ -158,15 +159,32 @@ struct value : public expr_base> { return result; } - template + template::value, int>::type = 0> CXXRTL_ALWAYS_INLINE - void set(IntegerT other) { + IntegerT get() const { + auto unsigned_result = get::type>(); + IntegerT result; + memcpy(&result, &unsigned_result, sizeof(IntegerT)); + return result; + } + + template::value, int>::type = 0> + CXXRTL_ALWAYS_INLINE + void set(IntegerT value) { static_assert(std::numeric_limits::is_integer && !std::numeric_limits::is_signed, "set() requires T to be an unsigned integral type"); static_assert(std::numeric_limits::digits >= Bits, "set() requires the value to be at least as wide as T is"); for (size_t n = 0; n < chunks; n++) - data[n] = (other >> (n * chunk::bits)) & chunk::mask; + data[n] = (value >> (n * chunk::bits)) & chunk::mask; + } + + template::value, int>::type = 0> + CXXRTL_ALWAYS_INLINE + void set(IntegerT value) { + typename std::make_unsigned::type unsigned_value; + memcpy(&unsigned_value, &value, sizeof(IntegerT)); + set(unsigned_value); } // Operations with compile-time parameters.