175 constexpr int numberOfBits = std::numeric_limits<T>::digits + (std::is_signed_v<T> ? 1 : 0);
180 using SignificantBitsCaseTypes = std::tuple<uint8_t, uint16_t, uint32_t, uint64_t>;
184 constexpr int getMinWidthsForFractionalCase(
const FractionalCase& fc) {
195 template<
typename RawType,
typename F>
199 if constexpr(numberOfBits<RawType> >= 8) {
204 if constexpr(numberOfBits<RawType> >= 16) {
209 if constexpr(numberOfBits<RawType> >= 32) {
214 if constexpr(numberOfBits<RawType> >= 64) {
224 template<
typename RawType,
typename UserType,
typename F>
237 if constexpr(std::is_integral_v<UserType>) {
239 std::is_signed_v<UserType> == info.
signedFlag) {
251 if constexpr(numberOfBits<RawType> >= 32) {
260 throw std::logic_error(
"NOT IMPLEMENTED");
265 template<
typename UserType,
typename RawType,
typename F>
266 void callWithConverterParamsFixedRaw(
269 detail::callForSignificantBitsCase<RawType>(info.channels[channelIndex], [&]<
SignificantBitsCase sc> {
271 detail::callForFractionalCase<RawType, UserType>(info.channels[channelIndex], [&]<FractionalCase fc> {
272 if constexpr(numberOfBits<RawType> >= detail::getMinWidthsForFractionalCase(fc)) {
273 if constexpr(fc == FractionalCase::ieee754_32) {
275 std::forward<F>(fun).template operator()<RawType, sc, fc, true>();
277 else if constexpr(fc == FractionalCase::fixedNegativeFast) {
280 assert(numberOfBits<UserType> >= int(info.channels[channelIndex].width) -
281 info.channels[channelIndex].nFractionalBits);
282 assert(std::is_signed_v<UserType> ==
283 info.channels[channelIndex].signedFlag);
284 std::forward<F>(fun).template operator()<RawType, sc, fc, std::is_signed_v<UserType>>();
288 if(info.channels[channelIndex].signedFlag) {
289 std::forward<F>(fun).template operator()<RawType, sc, fc, true>();
292 std::forward<F>(fun).template operator()<RawType, sc, fc, false>();
297 throw ChimeraTK::logic_error(
298 std::format(
"Specified raw data width of {} bits does not fit into the significant bit "
299 "width of {} bits for register '{}', channel {}.",
300 numberOfBits<RawType>, detail::getMinWidthsForFractionalCase(fc),
301 std::string(info.getRegisterName()), channelIndex));
309 template<
typename UserType,
typename F>
321 using RawType = std::make_unsigned_t<decltype(x)>;
322 if constexpr(std::is_same_v<UserType, ChimeraTK::Void>) {
327 .template operator()<RawType, SignificantBitsCase::generic, FractionalCase::integer, false>();
331 callWithConverterParamsFixedRaw<UserType, RawType>(info, channelIndex, fun);
338 template<std::size_t... Is>
339 constexpr auto makeUnusedBitMaskTable(std::index_sequence<Is...>) {
340 return std::array<uint64_t, 65>{(Is < 64 ? (~uint64_t{} << Is) : 0)...};
345 template<std::size_t... Is>
346 constexpr auto makeUsedBitMaskTable(std::index_sequence<Is...>) {
347 return std::array<uint64_t, 65>{(Is < 64 ? (~(~uint64_t{} << Is)) : ~uint64_t{})...};
352 template<std::size_t... Is>
353 constexpr auto makeSignBitMaskTable(std::index_sequence<Is...>) {
354 return std::array<uint64_t, 65>{(Is > 0 ? (uint64_t{1} << (Is - 1)) : 0)...};
359 constexpr auto unusedBitMaskTable = makeUnusedBitMaskTable(std::make_index_sequence<65>{});
360 constexpr auto usedBitMaskTable = makeUsedBitMaskTable(std::make_index_sequence<65>{});
361 constexpr auto signBitMaskTable = makeSignBitMaskTable(std::make_index_sequence<65>{});
366 template<
typename PromotedRawType,
typename RawType, SignificantBitsCase significantBitsCase>
367 constexpr PromotedRawType interpretArbitraryBitInteger(
368 RawType signBitMask, RawType usedBitMask, RawType unusedBitMask, RawType rawValue) {
369 static_assert(std::is_integral_v<RawType>);
370 static_assert(!std::is_signed_v<RawType>);
372 if constexpr(significantBitsCase == SignificantBitsCase::generic) {
373 if constexpr(std::is_signed_v<PromotedRawType>) {
374 if(!(rawValue & signBitMask)) {
375 return PromotedRawType(rawValue & usedBitMask);
378 return PromotedRawType(rawValue | unusedBitMask);
382 return PromotedRawType(rawValue & usedBitMask);
391 using UnsignedType = std::tuple_element_t<int(significantBitsCase), SignificantBitsCaseTypes>;
392 using SignedType = std::make_signed_t<UnsignedType>;
393 if constexpr(std::is_signed_v<PromotedRawType>) {
394 return PromotedRawType(SignedType(rawValue));
397 return PromotedRawType(UnsignedType(rawValue));
412 : _signBitMask(isSigned ? detail::signBitMaskTable[info.width] : 0),
413 _usedBitMask(detail::usedBitMaskTable[info.width]), _unusedBitMask(detail::unusedBitMaskTable[info.width]) {
417 constexpr uint32_t maxRawWidth = detail::numberOfBits<uint64_t>;
418 if(info.
width > maxRawWidth) {
420 std::format(
"RawConverter cannot deal with a bit width of {} > {}.", info.
width, maxRawWidth));
424 "RawConverter cannot deal with {} fractional bits (larger than total width).", info.
nFractionalBits));
428 "RawConverter cannot deal with {} fractional bits (too negative, result doesn't fit in {} bits).",
436 _inverseConversionFactor = std::pow(FloatIntermediate(2), info.
nFractionalBits);
442 _conversionFactor = FloatIntermediate(1.) / _inverseConversionFactor;
453 if constexpr(isSigned) {
454 _maxRawValue = _usedBitMask ^ _signBitMask;
455 _minRawValue = _signBitMask;
458 _maxRawValue = _usedBitMask;
461 _maxPromotedRawValue = _maxRawValue;
462 _minPromotedRawValue = detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
463 _signBitMask, _usedBitMask, _unusedBitMask, _minRawValue);
467 _maxRawValue = RawType(std::bit_cast<uint32_t>(std::numeric_limits<float>::max()));
468 _minRawValue = RawType(std::bit_cast<uint32_t>(std::numeric_limits<float>::lowest()));
477 auto promotedRawValue = detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
478 _signBitMask, _usedBitMask, _unusedBitMask, rawValue);
479 return numericToUserType<UserType>(promotedRawValue);
485 auto promotedRawValue = detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
486 _signBitMask, _usedBitMask, _unusedBitMask, rawValue);
487 return numericToUserType<UserType>(FloatIntermediate(promotedRawValue) * _conversionFactor);
492 using IntIntermediate = std::conditional_t<isSigned, int64_t, uint64_t>;
493 auto promotedRawValue = IntIntermediate(detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
494 _signBitMask, _usedBitMask, _unusedBitMask, rawValue));
495 auto intermediateUnsigned = uint64_t(promotedRawValue);
496 intermediateUnsigned <<= _nNegativeFractionalBits;
497 return numericToUserType<UserType>(IntIntermediate(intermediateUnsigned));
503 static_assert(std::is_integral_v<UserType>);
504 static_assert(std::is_signed_v<UserType> == std::is_signed_v<PromotedRawType>);
505 auto promotedRawValue = UserType(detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
506 _signBitMask, _usedBitMask, _unusedBitMask, rawValue));
507 auto intermediateUnsigned = std::make_unsigned_t<UserType>(promotedRawValue);
508 intermediateUnsigned <<= _nNegativeFractionalBits;
509 return UserType(intermediateUnsigned);
513 static_assert(detail::numberOfBits<RawType> >= 32);
514 static_assert(std::numeric_limits<float>::is_iec559);
515 auto promotedRawValue = detail::interpretArbitraryBitInteger<PromotedRawType, RawType, sc>(
516 _signBitMask, _usedBitMask, _unusedBitMask, rawValue);
517 return numericToUserType<UserType>(std::bit_cast<float>(uint32_t(promotedRawValue)));