qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH, MIPS R2] Timer start/stop implementation
@ 2007-09-24 13:25 Aurelien Jarno
  0 siblings, 0 replies; only message in thread
From: Aurelien Jarno @ 2007-09-24 13:25 UTC (permalink / raw)
  To: qemu-devel

Hi all,

The patch below allows the timer to be stopped using the DC bit in the 
CP0 Cause register. This feature is required for MIPS R2 implementations.

It also removes a few places where the interrupt corresponding to the 
timer is hardcoded, and leaves it hardcoded at only one place 
(initialisation).

Bye,
Aurelien

Index: hw/mips_timer.c
===================================================================
RCS file: /sources/qemu/qemu/hw/mips_timer.c,v
retrieving revision 1.7
diff -u -d -p -r1.7 mips_timer.c
--- hw/mips_timer.c	6 Sep 2007 00:18:14 -0000	1.7
+++ hw/mips_timer.c	24 Sep 2007 13:22:50 -0000
@@ -17,9 +17,12 @@ uint32_t cpu_mips_get_random (CPUState *
 /* MIPS R4K timer */
 uint32_t cpu_mips_get_count (CPUState *env)
 {
-    return env->CP0_Count +
-        (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                           100 * 1000 * 1000, ticks_per_sec);
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        return env->CP0_Count;
+    else
+        return env->CP0_Count +
+            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
+                               100 * 1000 * 1000, ticks_per_sec);
 }
 
 void cpu_mips_store_count (CPUState *env, uint32_t count)
@@ -63,7 +66,19 @@ void cpu_mips_store_compare (CPUState *e
     cpu_mips_update_count(env, cpu_mips_get_count(env));
     if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
         env->CP0_Cause &= ~(1 << CP0Ca_TI);
-    qemu_irq_lower(env->irq[7]);
+    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0In_IPTI) & 0x7]);
+}
+
+void cpu_mips_start_count(CPUState *env)
+{
+    cpu_mips_store_count(env, env->CP0_Count);
+}
+
+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);
 }
 
 static void mips_timer_cb (void *opaque)
@@ -76,10 +91,14 @@ static void mips_timer_cb (void *opaque)
         fprintf(logfile, "%s\n", __func__);
     }
 #endif
+
+    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))
         env->CP0_Cause |= 1 << CP0Ca_TI;
-    qemu_irq_raise(env->irq[7]);
+    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0In_IPTI) & 0x7]);
 }
 
 void cpu_mips_clock_init (CPUState *env)
Index: target-mips/exec.h
===================================================================
RCS file: /sources/qemu/qemu/target-mips/exec.h,v
retrieving revision 1.32
diff -u -d -p -r1.32 exec.h
--- target-mips/exec.h	16 Sep 2007 21:08:03 -0000	1.32
+++ target-mips/exec.h	24 Sep 2007 13:22:50 -0000
@@ -153,6 +153,8 @@ uint32_t cpu_mips_get_random (CPUState *
 uint32_t cpu_mips_get_count (CPUState *env);
 void cpu_mips_store_count (CPUState *env, uint32_t value);
 void cpu_mips_store_compare (CPUState *env, uint32_t value);
+void cpu_mips_start_count(CPUState *env);
+void cpu_mips_stop_count(CPUState *env);
 void cpu_mips_update_irq (CPUState *env);
 void cpu_mips_clock_init (CPUState *env);
 void cpu_mips_tlb_flush (CPUState *env, int flush_global);
Index: target-mips/op.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op.c,v
retrieving revision 1.72
diff -u -d -p -r1.72 op.c
--- target-mips/op.c	24 Sep 2007 12:48:00 -0000	1.72
+++ target-mips/op.c	24 Sep 2007 13:22:51 -0000
@@ -1882,9 +1882,8 @@ void op_mttc0_status(void)
 
 void op_mtc0_intctl (void)
 {
-    /* vectored interrupts not implemented, timer on int 7,
-       no performance counters. */
-    env->CP0_IntCtl |= T0 & 0x000002e0;
+    /* vectored interrupts not implemented, no performance counters. */
+    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (T0 & 0x000002e0);
     RETURN();
 }
 
@@ -1904,12 +1903,20 @@ void op_mtc0_srsmap (void)
 void op_mtc0_cause (void)
 {
     uint32_t mask = 0x00C00300;
+    uint32_t old = env->CP0_Cause;
 
     if (env->insn_flags & ISA_MIPS32R2)
         mask |= 1 << CP0Ca_DC;
 
     env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask);
 
+    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
+        if (env->CP0_Cause & (1 << CP0Ca_DC))
+            CALL_FROM_TB1(cpu_mips_stop_count, env);
+        else
+            CALL_FROM_TB1(cpu_mips_start_count, env);	
+    }
+
     /* Handle the software interrupt as an hardware one, as they
        are very similar */
     if (T0 & CP0Ca_IP_mask) {
Index: target-mips/op_helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-mips/op_helper.c,v
retrieving revision 1.59
diff -u -d -p -r1.59 op_helper.c
--- target-mips/op_helper.c	17 Sep 2007 08:09:53 -0000	1.59
+++ target-mips/op_helper.c	24 Sep 2007 13:22:52 -0000
@@ -265,6 +265,16 @@ void cpu_mips_store_compare(CPUState *en
     cpu_abort(env, "mtc0 compare\n");
 }
 
+void cpu_mips_start_count(CPUState *env)
+{
+    cpu_abort(env, "start count\n");
+}
+
+void cpu_mips_stop_count(CPUState *env)
+{
+    cpu_abort(env, "stop count\n");
+}
+
 void cpu_mips_update_irq(CPUState *env)
 {
     cpu_abort(env, "mtc0 status / mtc0 cause\n");

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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2007-09-24 13:25 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-09-24 13:25 [Qemu-devel] [PATCH, MIPS R2] Timer start/stop implementation Aurelien Jarno

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).