aboutsummaryrefslogtreecommitdiff
path: root/target-sh4
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-12-02 06:18:24 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2007-12-02 06:18:24 +0000
commite96e2044a14340bf1e612b7f046093495c10a06f (patch)
treeb104c5d9280ad19c03afcecd20457324627d3580 /target-sh4
parent823029f909b3666660418387d48ea6a207f23f26 (diff)
SH4: system emulator interrupt update, by Magnus Damm.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3762 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sh4')
-rw-r--r--target-sh4/cpu.h1
-rw-r--r--target-sh4/helper.c75
-rw-r--r--target-sh4/op.c2
3 files changed, 60 insertions, 18 deletions
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index f9ecbb271d..6b90f47d11 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -121,6 +121,7 @@ typedef struct CPUSH4State {
int exception_index;
CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */
tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
+ void *intc_handle;
} CPUSH4State;
CPUSH4State *cpu_sh4_init(const char *cpu_model);
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index b8a05e124c..11e2e0f24b 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 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
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 @@ void do_interrupt(CPUState * env)
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;
}
}
diff --git a/target-sh4/op.c b/target-sh4/op.c
index 0dcec49060..1004ef4c70 100644
--- a/target-sh4/op.c
+++ b/target-sh4/op.c
@@ -419,7 +419,7 @@ void OPPROTO op_subv_T0_T1(void)
void OPPROTO op_trapa(void)
{
- env->tra = PARAM1 * 2;
+ env->tra = PARAM1 << 2;
env->exception_index = 0x160;
do_raise_exception();
RETURN();