qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [MIPS] Optimize MIPS timer read/write functions


From: Aurelien Jarno
Subject: [Qemu-devel] [MIPS] Optimize MIPS timer read/write functions
Date: Tue, 19 Feb 2008 01:10:20 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

The patch below optimize the MIPS timer read/write functions and 
improves its precision.
   
cpu_mips_update_count() is replaced by cpu_mips_timer_update()
which does not call cpu_mips_store_count() and do fewer things. As
this function is called by the callback function, it is called very
often and thus it is worth optimizing it.

The patch also ensures that env->CP0_Count is not written in normal use
(that is when CP0_Count is not written, and the timer not started or
stopped), so that no ticks are lost.

diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index 3e7d5e3..d912fd5 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -2,6 +2,8 @@
 #include "mips.h"
 #include "qemu-timer.h"
 
+#define TIMER_FREQ     100 * 1000 * 1000
+
 void cpu_mips_irqctrl_init (void)
 {
 }
@@ -24,49 +26,41 @@ uint32_t cpu_mips_get_count (CPUState *env)
     else
         return env->CP0_Count +
             (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                               100 * 1000 * 1000, ticks_per_sec);
+                               TIMER_FREQ, ticks_per_sec);
 }
 
-void cpu_mips_store_count (CPUState *env, uint32_t count)
+static void cpu_mips_timer_update(CPUState *env)
 {
     uint64_t now, next;
-    uint32_t tmp;
-    uint32_t compare = env->CP0_Compare;
+    uint32_t wait;
 
-    tmp = count;
-    if (count == compare)
-        tmp++;
     now = qemu_get_clock(vm_clock);
-    next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
-    if (next == now)
-       next++;
-#if 0
-    if (logfile) {
-        fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
-                __func__, now, count, compare, next - now);
-    }
-#endif
-    /* Store new count and compare registers */
-    env->CP0_Compare = compare;
-    env->CP0_Count =
-        count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
-    /* Adjust timer */
+    wait = env->CP0_Compare - env->CP0_Count - 
+           (uint32_t)muldiv64(now, TIMER_FREQ, ticks_per_sec);
+    next = now + muldiv64(wait, ticks_per_sec, TIMER_FREQ);
     qemu_mod_timer(env->timer, next);
 }
 
-static void cpu_mips_update_count (CPUState *env, uint32_t count)
+void cpu_mips_store_count (CPUState *env, uint32_t count)
 {
     if (env->CP0_Cause & (1 << CP0Ca_DC))
-        return;
-
-    cpu_mips_store_count(env, count);
+        env->CP0_Count = count;
+    else {
+        /* Store new count register */
+        env->CP0_Count =
+            count - (uint32_t)muldiv64(qemu_get_clock(vm_clock), 
+                                       TIMER_FREQ, ticks_per_sec);
+        /* Update timer timer */
+        cpu_mips_timer_update(env);
+    }
 }
 
 void cpu_mips_store_compare (CPUState *env, uint32_t value)
 {
     env->CP0_Compare = value;
-    cpu_mips_update_count(env, cpu_mips_get_count(env));
-    if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+    if (!(env->CP0_Cause & (1 << CP0Ca_DC)))
+        cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2)
         env->CP0_Cause &= ~(1 << CP0Ca_TI);
     qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
 }
@@ -80,7 +74,7 @@ void cpu_mips_stop_count(CPUState *env)
 {
     /* Store the current value */
     env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                                         100 * 1000 * 1000, ticks_per_sec);
+                                         TIMER_FREQ, ticks_per_sec);
 }
 
 static void mips_timer_cb (void *opaque)
@@ -97,8 +91,8 @@ static void mips_timer_cb (void *opaque)
     if (env->CP0_Cause & (1 << CP0Ca_DC))
         return;
 
-    cpu_mips_update_count(env, cpu_mips_get_count(env));
-    if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+    cpu_mips_timer_update(env);
+    if (env->insn_flags & ISA_MIPS32R2)
         env->CP0_Cause |= 1 << CP0Ca_TI;
     qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
 }
@@ -107,5 +101,5 @@ void cpu_mips_clock_init (CPUState *env)
 {
     env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
     env->CP0_Compare = 0;
-    cpu_mips_update_count(env, 1);
+    cpu_mips_store_count(env, 1);
 }

-- 
  .''`.  Aurelien Jarno             | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   address@hidden         | address@hidden
   `-    people.debian.org/~aurel32 | www.aurel32.net




reply via email to

[Prev in Thread] Current Thread [Next in Thread]