diff options
Diffstat (limited to 'target-ppc')
-rw-r--r-- | target-ppc/cpu.h | 16 | ||||
-rw-r--r-- | target-ppc/helper.c | 83 |
2 files changed, 99 insertions, 0 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b21d6b19fb..ef02f10968 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -740,6 +740,7 @@ struct CPUPPCState { int exception_index; int error_code; int interrupt_request; + uint32_t pending_interrupts; /* Those resources are used only during code translation */ /* Next instruction pointer */ @@ -1267,6 +1268,21 @@ enum { EXCP_TRAP = 0x40, }; +/* Hardware interruption sources: + * all those exception can be raised simulteaneously + */ +enum { + PPC_INTERRUPT_RESET = 0, /* Reset / critical input */ + PPC_INTERRUPT_MCK = 1, /* Machine check exception */ + PPC_INTERRUPT_EXT = 2, /* External interrupt */ + PPC_INTERRUPT_DECR = 3, /* Decrementer exception */ + PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */ + PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */ + PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */ + PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */ + PPC_INTERRUPT_DEBUG = 8, /* External debug exception */ +}; + /*****************************************************************************/ #endif /* !defined (__CPU_PPC_H__) */ diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b86f8234e6..4356edc36c 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -1229,6 +1229,13 @@ void do_interrupt (CPUState *env) { env->exception_index = -1; } + +int ppc_hw_interrupt (CPUState *env) +{ + env->exception_index = -1; + + return 0; +} #else /* defined (CONFIG_USER_ONLY) */ static void dump_syscall(CPUState *env) { @@ -1753,4 +1760,80 @@ void do_interrupt (CPUState *env) env->nip = excp; env->exception_index = EXCP_NONE; } + +int ppc_hw_interrupt (CPUState *env) +{ + int raised = 0; + +#if 0 + printf("%s: %p pending %08x req %08x %08x me %d ee %d\n", + __func__, env, env->pending_interrupts, + env->interrupt_request, interrupt_request, + msr_me, msr_ee); +#endif + /* Raise it */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { + /* External reset / critical input */ + env->exception_index = EXCP_RESET; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); + raised = 1; + } + if (raised == 0 && msr_me != 0) { + /* Machine check exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) { + env->exception_index = EXCP_MACHINE_CHECK; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK); + raised = 1; + } + } + if (raised == 0 && msr_ee != 0) { +#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */ + /* Hypervisor decrementer exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) { + env->exception_index = EXCP_HDECR; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR); + raised = 1; + } else +#endif + /* Decrementer exception */ + if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) { + env->exception_index = EXCP_DECR; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR); + raised = 1; + /* Programmable interval timer on embedded PowerPC */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) { + env->exception_index = EXCP_40x_PIT; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT); + raised = 1; + /* Fixed interval timer on embedded PowerPC */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) { + env->exception_index = EXCP_40x_FIT; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT); + raised = 1; + /* Watchdog timer on embedded PowerPC */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) { + env->exception_index = EXCP_40x_WATCHDOG; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT); + raised = 1; + /* External interrupt */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { + env->exception_index = EXCP_EXTERNAL; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); + raised = 1; + } +#if 0 // TODO + /* External debug exception */ + } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) { + env->exception_index = EXCP_xxx; + env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG); + raised = 1; +#endif + } + if (raised != 0) { + env->error_code = 0; + do_interrupt(env); + } + + return raised; +} #endif /* !CONFIG_USER_ONLY */ |