Revision d0a981b2
b/hw/ptimer.c | ||
---|---|---|
7 | 7 |
*/ |
8 | 8 |
#include "hw.h" |
9 | 9 |
#include "qemu-timer.h" |
10 |
|
|
10 |
#include "host-utils.h" |
|
11 | 11 |
|
12 | 12 |
struct ptimer_state |
13 | 13 |
{ |
... | ... | |
78 | 78 |
} else { |
79 | 79 |
uint64_t rem; |
80 | 80 |
uint64_t div; |
81 |
uint32_t frac; |
|
82 |
int clz1, clz2; |
|
83 |
int shift; |
|
84 |
|
|
85 |
/* We need to divide time by period, where time is stored in |
|
86 |
rem (64-bit integer) and period is stored in period/period_frac |
|
87 |
(64.32 fixed point). |
|
88 |
|
|
89 |
Doing full precision division is hard, so scale values and |
|
90 |
do a 64-bit division. The result should be rounded down, |
|
91 |
so that the rounding error never causes the timer to go |
|
92 |
backwards. |
|
93 |
*/ |
|
81 | 94 |
|
82 | 95 |
rem = s->next_event - now; |
83 | 96 |
div = s->period; |
97 |
|
|
98 |
clz1 = clz64(rem); |
|
99 |
clz2 = clz64(div); |
|
100 |
shift = clz1 < clz2 ? clz1 : clz2; |
|
101 |
|
|
102 |
rem <<= shift; |
|
103 |
div <<= shift; |
|
104 |
if (shift >= 32) { |
|
105 |
div |= ((uint64_t)s->period_frac << (shift - 32)); |
|
106 |
} else { |
|
107 |
if (shift != 0) |
|
108 |
div |= (s->period_frac >> (32 - shift)); |
|
109 |
/* Look at remaining bits of period_frac and round div up if |
|
110 |
necessary. */ |
|
111 |
if ((uint32_t)(s->period_frac << shift)) |
|
112 |
div += 1; |
|
113 |
} |
|
84 | 114 |
counter = rem / div; |
85 | 115 |
} |
86 | 116 |
} else { |
Also available in: Unified diff