From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Lof2r-00045w-P1 for qemu-devel@nongnu.org; Tue, 31 Mar 2009 10:34:29 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lof2q-00045S-E0 for qemu-devel@nongnu.org; Tue, 31 Mar 2009 10:34:29 -0400 Received: from [199.232.76.173] (port=47003 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lof2q-00045P-8G for qemu-devel@nongnu.org; Tue, 31 Mar 2009 10:34:28 -0400 Received: from savannah.gnu.org ([199.232.41.3]:55996 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1Lof2p-000669-Ks for qemu-devel@nongnu.org; Tue, 31 Mar 2009 10:34:27 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1Lof2n-0002zw-1F for qemu-devel@nongnu.org; Tue, 31 Mar 2009 14:34:25 +0000 Received: from pbrook by cvs.savannah.gnu.org with local (Exim 4.69) (envelope-from ) id 1Lof2m-0002zo-MG for qemu-devel@nongnu.org; Tue, 31 Mar 2009 14:34:24 +0000 MIME-Version: 1.0 Errors-To: pbrook Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Paul Brook Message-Id: Date: Tue, 31 Mar 2009 14:34:24 +0000 Subject: [Qemu-devel] [6961] Avoid rounding problems in ptimer_get_count Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 6961 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6961 Author: pbrook Date: 2009-03-31 14:34:24 +0000 (Tue, 31 Mar 2009) Log Message: ----------- Avoid rounding problems in ptimer_get_count Signed-off-by: Paul Brook Modified Paths: -------------- trunk/hw/ptimer.c Modified: trunk/hw/ptimer.c =================================================================== --- trunk/hw/ptimer.c 2009-03-31 05:55:16 UTC (rev 6960) +++ trunk/hw/ptimer.c 2009-03-31 14:34:24 UTC (rev 6961) @@ -7,8 +7,8 @@ */ #include "hw.h" #include "qemu-timer.h" +#include "host-utils.h" - struct ptimer_state { int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot. */ @@ -78,9 +78,39 @@ } 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 {