mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-08 18:23:57 -06:00
New model for PowerPC CPU hardware interrupt events:
move all PowerPC specific code into target-ppc/helper.c to avoid polluting the common code in cpu-exec.c. This makes implementation of new features (ie embedded PowerPC timers, critical interrupts, ...) easier. This also avoid hardcoding the IRQ callback in the OpenPIC controller, making it more easily reusable and allowing cascading. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2542 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
de270b3c7c
commit
4710357290
8 changed files with 193 additions and 46 deletions
|
@ -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__) */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue