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