diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-12-02 06:18:24 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-12-02 06:18:24 +0000 |
commit | e96e2044a14340bf1e612b7f046093495c10a06f (patch) | |
tree | b104c5d9280ad19c03afcecd20457324627d3580 /target-sh4 | |
parent | 823029f909b3666660418387d48ea6a207f23f26 (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.h | 1 | ||||
-rw-r--r-- | target-sh4/helper.c | 75 | ||||
-rw-r--r-- | target-sh4/op.c | 2 |
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(); |