SH4: system emulator interrupt update, by Magnus Damm.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3762 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index b8a05e1..11e2e0f 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -27,6 +27,7 @@
 
 #include "cpu.h"
 #include "exec-all.h"
+#include "hw/sh_intc.h"
 
 #if defined(CONFIG_USER_ONLY)
 
@@ -74,6 +75,31 @@
 
 void do_interrupt(CPUState * env)
 {
+    int do_irq = env->interrupt_request & CPU_INTERRUPT_HARD;
+    int do_exp, irq_vector = env->exception_index;
+
+    /* prioritize exceptions over interrupts */
+
+    do_exp = env->exception_index != -1;
+    do_irq = do_irq && (env->exception_index == -1);
+
+    if (env->sr & SR_BL) {
+        if (do_exp && env->exception_index != 0x1e0) {
+            env->exception_index = 0x000; /* masked exception -> reset */
+        }
+        if (do_irq) {
+            return; /* masked */
+        }
+    }
+
+    if (do_irq) {
+        irq_vector = sh_intc_get_pending_vector(env->intc_handle,
+						(env->sr >> 4) & 0xf);
+        if (irq_vector == -1) {
+            return; /* masked */
+	}
+    }
+
     if (loglevel & CPU_LOG_INT) {
 	const char *expname;
 	switch (env->exception_index) {
@@ -117,32 +143,47 @@
 	    expname = "trapa";
 	    break;
 	default:
-	    expname = "???";
-	    break;
+            expname = do_irq ? "interrupt" : "???";
+            break;
 	}
 	fprintf(logfile, "exception 0x%03x [%s] raised\n",
-		env->exception_index, expname);
+		irq_vector, expname);
 	cpu_dump_state(env, logfile, fprintf, 0);
     }
 
     env->ssr = env->sr;
-    env->spc = env->spc;
+    env->spc = env->pc;
     env->sgr = env->gregs[15];
     env->sr |= SR_BL | SR_MD | SR_RB;
 
-    env->expevt = env->exception_index & 0x7ff;
-    switch (env->exception_index) {
-    case 0x040:
-    case 0x060:
-    case 0x080:
-	env->pc = env->vbr + 0x400;
-	break;
-    case 0x140:
-	env->pc = 0xa0000000;
-	break;
-    default:
-	env->pc = env->vbr + 0x100;
-	break;
+    if (do_exp) {
+        env->expevt = env->exception_index;
+        switch (env->exception_index) {
+        case 0x000:
+        case 0x020:
+        case 0x140:
+            env->sr &= ~SR_FD;
+            env->sr |= 0xf << 4; /* IMASK */
+            env->pc = 0xa0000000;
+            break;
+        case 0x040:
+        case 0x060:
+            env->pc = env->vbr + 0x400;
+            break;
+        case 0x160:
+            env->spc += 2; /* special case for TRAPA */
+            /* fall through */
+        default:
+            env->pc = env->vbr + 0x100;
+            break;
+        }
+        return;
+    }
+
+    if (do_irq) {
+        env->intevt = irq_vector;
+        env->pc = env->vbr + 0x600;
+        return;
     }
 }