Avoid rounding problems in ptimer_get_count

Signed-off-by: Paul Brook <paul@codesourcery.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6961 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
pbrook 2009-03-31 14:34:24 +00:00
parent bbeea539aa
commit d0a981b2d5
1 changed files with 31 additions and 1 deletions

View File

@ -7,7 +7,7 @@
*/
#include "hw.h"
#include "qemu-timer.h"
#include "host-utils.h"
struct ptimer_state
{
@ -78,9 +78,39 @@ uint64_t ptimer_get_count(ptimer_state *s)
} else {
uint64_t rem;
uint64_t div;
uint32_t frac;
int clz1, clz2;
int shift;
/* We need to divide time by period, where time is stored in
rem (64-bit integer) and period is stored in period/period_frac
(64.32 fixed point).
Doing full precision division is hard, so scale values and
do a 64-bit division. The result should be rounded down,
so that the rounding error never causes the timer to go
backwards.
*/
rem = s->next_event - now;
div = s->period;
clz1 = clz64(rem);
clz2 = clz64(div);
shift = clz1 < clz2 ? clz1 : clz2;
rem <<= shift;
div <<= shift;
if (shift >= 32) {
div |= ((uint64_t)s->period_frac << (shift - 32));
} else {
if (shift != 0)
div |= (s->period_frac >> (32 - shift));
/* Look at remaining bits of period_frac and round div up if
necessary. */
if ((uint32_t)(s->period_frac << shift))
div += 1;
}
counter = rem / div;
}
} else {