mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 15:02:25 +00:00
73d18261dc
Added missing factoring of the upper-half division remainder into the lower-half calculation. Fixes #5243
64 lines
2.1 KiB
C++
64 lines
2.1 KiB
C++
/*
|
|
* \brief Utilities for timer drivers
|
|
* \author Martin Stein
|
|
* \date 2017-08-23
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _DRIVERS__TIMER__UTIL_H_
|
|
#define _DRIVERS__TIMER__UTIL_H_
|
|
|
|
namespace Genode {
|
|
|
|
enum { TIMER_MIN_TICKS_PER_MS = 1000ULL };
|
|
|
|
/*
|
|
* Translate timer ticks to microseconds without losing precicision
|
|
*
|
|
* There are hardware timers whose frequency can't be expressed as
|
|
* ticks-per-microsecond integer-value because only a ticks-per-millisecond
|
|
* integer-value is precise enough. We don't want to use expensive
|
|
* floating-point values here but nonetheless want to translate from ticks
|
|
* to time with microseconds precision. Thus, we split the input in two and
|
|
* translate both parts separately. This way, we can raise precision by
|
|
* shifting the values to their optimal bit position. Afterwards, the
|
|
* results are shifted back and merged together again. Note, the remainder
|
|
* of the upper-half division is factored into the lower-half calculation
|
|
* (as upper-half value).
|
|
*
|
|
* Please ensure that the assertion
|
|
* "ticks_per_ms >= TIMER_MIN_TICKS_PER_MS" is true when calling this
|
|
* method!
|
|
*/
|
|
template <typename RESULT_T, typename TICS_PER_MS_T>
|
|
RESULT_T timer_ticks_to_us(RESULT_T const ticks,
|
|
TICS_PER_MS_T const ticks_per_ms)
|
|
{
|
|
enum:RESULT_T {
|
|
HALF_WIDTH = (sizeof(RESULT_T) << 2),
|
|
MSB_MASK = (~(RESULT_T)0) << HALF_WIDTH,
|
|
LSB_MASK = (~(RESULT_T)0) >> HALF_WIDTH,
|
|
MSB_RSHIFT = 10,
|
|
LSB_LSHIFT = HALF_WIDTH - MSB_RSHIFT,
|
|
};
|
|
/* upper half */
|
|
RESULT_T const msb0 = ((ticks & MSB_MASK) >> MSB_RSHIFT) * 1000;
|
|
RESULT_T const msb = (msb0 / ticks_per_ms) << MSB_RSHIFT;
|
|
RESULT_T const rem = (msb0 % ticks_per_ms) << MSB_RSHIFT;
|
|
/* lower half */
|
|
RESULT_T const lsb0 = ((ticks & LSB_MASK) << LSB_LSHIFT) * 1000
|
|
+ (rem << LSB_LSHIFT);
|
|
RESULT_T const lsb = (lsb0 / ticks_per_ms) >> LSB_LSHIFT;
|
|
|
|
return msb + lsb;
|
|
}
|
|
}
|
|
|
|
#endif /* _DRIVERS__TIMER__UTIL_H_ */
|