diff mbox series

[RFC,5/5] target/ppc: powerpc_excp: Move interrupt raising code to QOM

Message ID 20210601214649.785647-6-farosas@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series target/ppc: powerpc_excp improvements - part I | expand

Commit Message

Fabiano Rosas June 1, 2021, 9:46 p.m. UTC
This patch introduces a new way to dispatch the emulated interrupts in
powerpc_excp. It leverages the QEMU object model to store the
implementations for each interrupt and link them to their identifier
from POWERPC_EXCP enum. The processor-specific code then uses this
identifier to register which interrupts it supports.

Interrupts now come out of the big switch in powerpc_excp into their
own functions:

  static void ppc_intr_system_reset(<args>)
  {
      /*
       * Interrupt code. Sets any specific registers and MSR bits.
       */
  }
  PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");

  ^This line registers the interrupt with QOM.

When we initialize the emulated processor, the correct set of
interrupts is instantiated (pretty much like we already do):

  static void init_excp_POWER9(CPUPPCState *env)
  {
      ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
      (...)
  }

When it comes the time to inject the interrupt:

  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
  {
      (...)

      intr = &env->entry_points[excp];
      intr->setup_regs(<args>);    <-- ppc_intr_system_reset function

      (...)
      env->spr[srr0] = nip;
      env->spr[srr1] = msr;

      env->nip = intr->addr;
      env->msr = new_msr;
  }

Some points to notice:

- The structure for the new PPCInterrupt class object is stored
  directly inside of CPUPPCState (env) so the translation code can
  still access it linearly at an offset.

- Some interrupts were being registered for P7/8/9/10 but were never
  implemented (i.e. not in the powerpc_excp switch statement). They
  are likely never triggered. We now get the benefit of QOM warning in
  such cases:

  qemu-system-ppc64: missing object type 'POWERPC_EXCP_SDOOR'
  qemu-system-ppc64: missing object type 'POWERPC_EXCP_HV_MAINT'

- The code currently allows for Program interrupts to be ignored and
  System call interrupts to be directed to the vhyp hypercall code. I
  have added an 'ignore' flag to deal with these two cases and return
  early from powerpc_excp.

Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
---
 target/ppc/cpu.h         |  29 +-
 target/ppc/cpu_init.c    | 640 +++++++++++++++++++--------------------
 target/ppc/excp_helper.c | 545 ++-------------------------------
 target/ppc/interrupts.c  | 638 ++++++++++++++++++++++++++++++++++++++
 target/ppc/machine.c     |   2 +-
 target/ppc/meson.build   |   1 +
 target/ppc/ppc_intr.h    |  55 ++++
 target/ppc/translate.c   |   3 +-
 8 files changed, 1066 insertions(+), 847 deletions(-)
 create mode 100644 target/ppc/interrupts.c
 create mode 100644 target/ppc/ppc_intr.h

Comments

Bruno Larsen (billionai) June 2, 2021, 12:31 p.m. UTC | #1
On 01/06/2021 18:46, Fabiano Rosas wrote:
> This patch introduces a new way to dispatch the emulated interrupts in
> powerpc_excp. It leverages the QEMU object model to store the
> implementations for each interrupt and link them to their identifier
> from POWERPC_EXCP enum. The processor-specific code then uses this
> identifier to register which interrupts it supports.
>
> Interrupts now come out of the big switch in powerpc_excp into their
> own functions:
>
>    static void ppc_intr_system_reset(<args>)
>    {
>        /*
>         * Interrupt code. Sets any specific registers and MSR bits.
>         */
>    }
>    PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
>
>    ^This line registers the interrupt with QOM.
>
> When we initialize the emulated processor, the correct set of
> interrupts is instantiated (pretty much like we already do):
>
>    static void init_excp_POWER9(CPUPPCState *env)
>    {
>        ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
>        (...)
>    }
>
> When it comes the time to inject the interrupt:
>
>    static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>    {
>        (...)
>
>        intr = &env->entry_points[excp];
>        intr->setup_regs(<args>);    <-- ppc_intr_system_reset function
>
>        (...)
>        env->spr[srr0] = nip;
>        env->spr[srr1] = msr;
>
>        env->nip = intr->addr;
>        env->msr = new_msr;
>    }
>
> Some points to notice:
>
> - The structure for the new PPCInterrupt class object is stored
>    directly inside of CPUPPCState (env) so the translation code can
>    still access it linearly at an offset.
>
> - Some interrupts were being registered for P7/8/9/10 but were never
>    implemented (i.e. not in the powerpc_excp switch statement). They
>    are likely never triggered. We now get the benefit of QOM warning in
>    such cases:
>
>    qemu-system-ppc64: missing object type 'POWERPC_EXCP_SDOOR'
>    qemu-system-ppc64: missing object type 'POWERPC_EXCP_HV_MAINT'
>
> - The code currently allows for Program interrupts to be ignored and
>    System call interrupts to be directed to the vhyp hypercall code. I
>    have added an 'ignore' flag to deal with these two cases and return
>    early from powerpc_excp.
>
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---

I don't see anything really wrong with the code itself, but this patch 
should probably be broken up into at least 2, one for the code motion 
and another for the ppc_intr'ification of the exception model.

>   target/ppc/cpu.h         |  29 +-
>   target/ppc/cpu_init.c    | 640 +++++++++++++++++++--------------------
>   target/ppc/excp_helper.c | 545 ++-------------------------------
>   target/ppc/interrupts.c  | 638 ++++++++++++++++++++++++++++++++++++++
>   target/ppc/machine.c     |   2 +-
>   target/ppc/meson.build   |   1 +
>   target/ppc/ppc_intr.h    |  55 ++++
>   target/ppc/translate.c   |   3 +-
>   8 files changed, 1066 insertions(+), 847 deletions(-)
>   create mode 100644 target/ppc/interrupts.c
>   create mode 100644 target/ppc/ppc_intr.h
>
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index b0934d9be4..012677965f 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -174,6 +174,33 @@ enum {
>       POWERPC_EXCP_TRAP          = 0x40,
>   };
>   
> +typedef struct PPCInterrupt PPCInterrupt;
> +typedef struct ppc_intr_args ppc_intr_args;
> +typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                              int excp_model, ppc_intr_args *regs,
> +                              bool *ignore);
> +
> +struct ppc_intr_args {
> +    target_ulong nip;
> +    target_ulong msr;
> +    target_ulong new_nip;
> +    target_ulong new_msr;
> +    int sprn_srr0;
> +    int sprn_srr1;
> +    int sprn_asrr0;
> +    int sprn_asrr1;
> +    int lev;
> +};
> +
This part also has me a bit confused. Why define it first in 
excp_helper.c in the last patch just to move it to here now?
> +struct PPCInterrupt {
> +    Object parent;
> +
> +    int id;
> +    const char *name;
> +    target_ulong addr;
> +    ppc_intr_fn_t setup_regs;
> +};
> +
>   #define PPC_INPUT(env) ((env)->bus_model)
>   
>   /*****************************************************************************/
> @@ -1115,7 +1142,7 @@ struct CPUPPCState {
>       uint32_t irq_input_state;
>       void **irq_inputs;
>   
> -    target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */
> +    PPCInterrupt entry_points[POWERPC_EXCP_NB];
>       target_ulong excp_prefix;
>       target_ulong ivor_mask;
>       target_ulong ivpr_mask;
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index d0411e7302..d91183357d 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -46,6 +46,7 @@
>   #include "helper_regs.h"
>   #include "internal.h"
>   #include "spr_tcg.h"
> +#include "ppc_intr.h"
>   
>   /* #define PPC_DEBUG_SPR */
>   /* #define USE_APPLE_GDB */
> @@ -2132,16 +2133,16 @@ static void register_8xx_sprs(CPUPPCState *env)
>   static void init_excp_4xx_real(CPUPPCState *env)
>   {
>   #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
> -    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
> +    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
> +    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
> +    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
>       env->ivor_mask = 0x0000FFF0UL;
>       env->ivpr_mask = 0xFFFF0000UL;
>       /* Hardware reset vector */
<snip>
> @@ -2624,8 +2625,8 @@ static void init_excp_POWER9(CPUPPCState *env)
>       init_excp_POWER8(env);
>   
>   #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_HVIRT]    = 0x00000EA0;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000;
> +    ppc_intr_add(env, 0x00000EA0, POWERPC_EXCP_HVIRT);
> +    ppc_intr_add(env, 0x00017000, POWERPC_EXCP_SYSCALL_VECTORED);
>   #endif
>   }
Not sure if this is possible, but if this bit can be done separately as 
an earlier patch, it would make reviewing a lot easier.
>   
> @@ -8375,13 +8376,8 @@ static void init_ppc_proc(PowerPCCPU *cpu)
>       PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
>       CPUPPCState *env = &cpu->env;
>   #if !defined(CONFIG_USER_ONLY)
> -    int i;
>   
>       env->irq_inputs = NULL;
> -    /* Set all exception vectors to an invalid address */
> -    for (i = 0; i < POWERPC_EXCP_NB; i++) {
> -        env->excp_vectors[i] = (target_ulong)(-1ULL);
> -    }
We don't need to use this to set invalid values?
>       env->ivor_mask = 0x00000000;
>       env->ivpr_mask = 0x00000000;
>       /* Default MMU definitions */
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 12bf829c8f..26cbfab923 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -29,14 +29,6 @@
>   #endif
>   
>   /* #define DEBUG_OP */
> -/* #define DEBUG_SOFTWARE_TLB */
> -/* #define DEBUG_EXCEPTIONS */
> -
> -#ifdef DEBUG_EXCEPTIONS
> -#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
> -#else
> -#  define LOG_EXCP(...) do { } while (0)
> -#endif
>   
>   /*****************************************************************************/
>   /* Exception processing */
<snip>
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index e16a2721e2..2c82bda8cc 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -951,7 +951,8 @@ void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
>       TCGv t0 = tcg_temp_new();
>       tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
>       tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
> -    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
> +    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, entry_points[sprn_offs]) +
> +                  offsetof(PPCInterrupt, addr));
>       gen_store_spr(sprn, t0);
>       tcg_temp_free(t0);
>   }
Other than that, from what I can see, looks ok
Fabiano Rosas June 2, 2021, 3:11 p.m. UTC | #2
Bruno Piazera Larsen <bruno.larsen@eldorado.org.br> writes:

> On 01/06/2021 18:46, Fabiano Rosas wrote:

<snip>

>> +struct ppc_intr_args {
>> +    target_ulong nip;
>> +    target_ulong msr;
>> +    target_ulong new_nip;
>> +    target_ulong new_msr;
>> +    int sprn_srr0;
>> +    int sprn_srr1;
>> +    int sprn_asrr0;
>> +    int sprn_asrr1;
>> +    int lev;
>> +};
>> +
> This part also has me a bit confused. Why define it first in 
> excp_helper.c in the last patch just to move it to here now?

Because back then it wasn't used outside of excp_helper.c. People would
probably ask: "why put this in a common header if it is not used
anywhere else?" =)

>> +struct PPCInterrupt {
>> +    Object parent;
>> +
>> +    int id;
>> +    const char *name;
>> +    target_ulong addr;
>> +    ppc_intr_fn_t setup_regs;
>> +};
>> +
>>   #define PPC_INPUT(env) ((env)->bus_model)
>>   
>>   /*****************************************************************************/
>> @@ -1115,7 +1142,7 @@ struct CPUPPCState {
>>       uint32_t irq_input_state;
>>       void **irq_inputs;
>>   
>> -    target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */
>> +    PPCInterrupt entry_points[POWERPC_EXCP_NB];
>>       target_ulong excp_prefix;
>>       target_ulong ivor_mask;
>>       target_ulong ivpr_mask;
>> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
>> index d0411e7302..d91183357d 100644
>> --- a/target/ppc/cpu_init.c
>> +++ b/target/ppc/cpu_init.c
>> @@ -46,6 +46,7 @@
>>   #include "helper_regs.h"
>>   #include "internal.h"
>>   #include "spr_tcg.h"
>> +#include "ppc_intr.h"
>>   
>>   /* #define PPC_DEBUG_SPR */
>>   /* #define USE_APPLE_GDB */
>> @@ -2132,16 +2133,16 @@ static void register_8xx_sprs(CPUPPCState *env)
>>   static void init_excp_4xx_real(CPUPPCState *env)
>>   {
>>   #if !defined(CONFIG_USER_ONLY)
>> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
>> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
>> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
>> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
>> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
>> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
>> -    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
>> -    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
>> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
>> -    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
>> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
>> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
>> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
>> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
>> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
>> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
>> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
>> +    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
>> +    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
>> +    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
>>       env->ivor_mask = 0x0000FFF0UL;
>>       env->ivpr_mask = 0xFFFF0000UL;
>>       /* Hardware reset vector */
> <snip>
>> @@ -2624,8 +2625,8 @@ static void init_excp_POWER9(CPUPPCState *env)
>>       init_excp_POWER8(env);
>>   
>>   #if !defined(CONFIG_USER_ONLY)
>> -    env->excp_vectors[POWERPC_EXCP_HVIRT]    = 0x00000EA0;
>> -    env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000;
>> +    ppc_intr_add(env, 0x00000EA0, POWERPC_EXCP_HVIRT);
>> +    ppc_intr_add(env, 0x00017000, POWERPC_EXCP_SYSCALL_VECTORED);
>>   #endif
>>   }
> Not sure if this is possible, but if this bit can be done separately as 
> an earlier patch, it would make reviewing a lot easier.

It could, but then it would be a synthetic change with not much purpose
on its own. We probably wouldn't want to merge a change that adds a
function that only writes an array position.

But I agree that this patch is on the verge of being too large. I had
another version split into more patches and it felt that we'd need to
keep going back and forth to understand the real impact of the
change. I'll think some more about it for a v2.

>>   
>> @@ -8375,13 +8376,8 @@ static void init_ppc_proc(PowerPCCPU *cpu)
>>       PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
>>       CPUPPCState *env = &cpu->env;
>>   #if !defined(CONFIG_USER_ONLY)
>> -    int i;
>>   
>>       env->irq_inputs = NULL;
>> -    /* Set all exception vectors to an invalid address */
>> -    for (i = 0; i < POWERPC_EXCP_NB; i++) {
>> -        env->excp_vectors[i] = (target_ulong)(-1ULL);
>> -    }
> We don't need to use this to set invalid values?

I'm now using the interrupt callback pointer for this. So if the
processor has not registered the interrupt, the pointer will be NULL.
David Gibson June 7, 2021, 3:58 a.m. UTC | #3
On Tue, Jun 01, 2021 at 06:46:49PM -0300, Fabiano Rosas wrote:
> This patch introduces a new way to dispatch the emulated interrupts in
> powerpc_excp. It leverages the QEMU object model to store the
> implementations for each interrupt and link them to their identifier
> from POWERPC_EXCP enum. The processor-specific code then uses this
> identifier to register which interrupts it supports.
> 
> Interrupts now come out of the big switch in powerpc_excp into their
> own functions:
> 
>   static void ppc_intr_system_reset(<args>)
>   {
>       /*
>        * Interrupt code. Sets any specific registers and MSR bits.
>        */
>   }
>   PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
> 
>   ^This line registers the interrupt with QOM.
> 
> When we initialize the emulated processor, the correct set of
> interrupts is instantiated (pretty much like we already do):
> 
>   static void init_excp_POWER9(CPUPPCState *env)
>   {
>       ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
>       (...)
>   }
> 
> When it comes the time to inject the interrupt:
> 
>   static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>   {
>       (...)
> 
>       intr = &env->entry_points[excp];
>       intr->setup_regs(<args>);    <-- ppc_intr_system_reset function
> 
>       (...)
>       env->spr[srr0] = nip;
>       env->spr[srr1] = msr;
> 
>       env->nip = intr->addr;
>       env->msr = new_msr;
>   }
> 
> Some points to notice:
> 
> - The structure for the new PPCInterrupt class object is stored
>   directly inside of CPUPPCState (env) so the translation code can
>   still access it linearly at an offset.
> 
> - Some interrupts were being registered for P7/8/9/10 but were never
>   implemented (i.e. not in the powerpc_excp switch statement). They
>   are likely never triggered. We now get the benefit of QOM warning in
>   such cases:
> 
>   qemu-system-ppc64: missing object type 'POWERPC_EXCP_SDOOR'
>   qemu-system-ppc64: missing object type 'POWERPC_EXCP_HV_MAINT'
> 
> - The code currently allows for Program interrupts to be ignored and
>   System call interrupts to be directed to the vhyp hypercall code. I
>   have added an 'ignore' flag to deal with these two cases and return
>   early from powerpc_excp.
> 
> Signed-off-by: Fabiano Rosas <farosas@linux.ibm.com>
> ---
>  target/ppc/cpu.h         |  29 +-
>  target/ppc/cpu_init.c    | 640 +++++++++++++++++++--------------------
>  target/ppc/excp_helper.c | 545 ++-------------------------------
>  target/ppc/interrupts.c  | 638 ++++++++++++++++++++++++++++++++++++++
>  target/ppc/machine.c     |   2 +-
>  target/ppc/meson.build   |   1 +
>  target/ppc/ppc_intr.h    |  55 ++++
>  target/ppc/translate.c   |   3 +-
>  8 files changed, 1066 insertions(+), 847 deletions(-)
>  create mode 100644 target/ppc/interrupts.c
>  create mode 100644 target/ppc/ppc_intr.h
> 
> diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> index b0934d9be4..012677965f 100644
> --- a/target/ppc/cpu.h
> +++ b/target/ppc/cpu.h
> @@ -174,6 +174,33 @@ enum {
>      POWERPC_EXCP_TRAP          = 0x40,
>  };
>  
> +typedef struct PPCInterrupt PPCInterrupt;
> +typedef struct ppc_intr_args ppc_intr_args;
> +typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                              int excp_model, ppc_intr_args *regs,
> +                              bool *ignore);

Hmm.  Using this signature kind of enforces that we dispatch based on
which exception *then* then the exception model.  I think that's
backwards: since what vectors exist and make sense depends on the
exception model, I think we should ideally be splitting on model
first, then exception type.

Now, a lot of the existing code is exception-then-model and changing
that is a long term project, but I don't think we should lock
ourselves further into doing it the backwards way.

> +
> +struct ppc_intr_args {
> +    target_ulong nip;
> +    target_ulong msr;
> +    target_ulong new_nip;
> +    target_ulong new_msr;
> +    int sprn_srr0;
> +    int sprn_srr1;
> +    int sprn_asrr0;
> +    int sprn_asrr1;
> +    int lev;
> +};
> +
> +struct PPCInterrupt {

Having an info/dispatch structure for each vector makes sense..

> +    Object parent;

..but making it a QOM object really seems like overkill.  In fact
making it a QOM object at least somewhat exposes the internal
structure to the user via QMP, which I really don't think we want to
do.

> +
> +    int id;
> +    const char *name;
> +    target_ulong addr;
> +    ppc_intr_fn_t setup_regs;
> +};
> +
>  #define PPC_INPUT(env) ((env)->bus_model)
>  
>  /*****************************************************************************/
> @@ -1115,7 +1142,7 @@ struct CPUPPCState {
>      uint32_t irq_input_state;
>      void **irq_inputs;
>  
> -    target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */
> +    PPCInterrupt entry_points[POWERPC_EXCP_NB];
>      target_ulong excp_prefix;
>      target_ulong ivor_mask;
>      target_ulong ivpr_mask;
> diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
> index d0411e7302..d91183357d 100644
> --- a/target/ppc/cpu_init.c
> +++ b/target/ppc/cpu_init.c
> @@ -46,6 +46,7 @@
>  #include "helper_regs.h"
>  #include "internal.h"
>  #include "spr_tcg.h"
> +#include "ppc_intr.h"
>  
>  /* #define PPC_DEBUG_SPR */
>  /* #define USE_APPLE_GDB */
> @@ -2132,16 +2133,16 @@ static void register_8xx_sprs(CPUPPCState *env)
>  static void init_excp_4xx_real(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
> -    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
> +    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
> +    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
> +    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
>      env->ivor_mask = 0x0000FFF0UL;
>      env->ivpr_mask = 0xFFFF0000UL;
>      /* Hardware reset vector */
> @@ -2152,20 +2153,20 @@ static void init_excp_4xx_real(CPUPPCState *env)
>  static void init_excp_4xx_softmmu(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
> -    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
> +    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
> +    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DTLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_ITLB);
> +    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
>      env->ivor_mask = 0x0000FFF0UL;
>      env->ivpr_mask = 0xFFFF0000UL;
>      /* Hardware reset vector */
> @@ -2176,21 +2177,21 @@ static void init_excp_4xx_softmmu(CPUPPCState *env)
>  static void init_excp_MPC5xx(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
> -    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
> -    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
> -    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_FPA);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_EMUL);
> +    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_DABR);
> +    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001E00, POWERPC_EXCP_MEXTBR);
> +    ppc_intr_add(env, 0x00001F00, POWERPC_EXCP_NMEXTBR);
>      env->ivor_mask = 0x0000FFF0UL;
>      env->ivpr_mask = 0xFFFF0000UL;
>      /* Hardware reset vector */
> @@ -2201,27 +2202,27 @@ static void init_excp_MPC5xx(CPUPPCState *env)
>  static void init_excp_MPC8xx(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
> -    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_ITLBE]    = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_DTLBE]    = 0x00001400;
> -    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
> -    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
> -    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_FPA);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_EMUL);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_ITLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DTLB);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_ITLBE);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_DTLBE);
> +    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_DABR);
> +    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001E00, POWERPC_EXCP_MEXTBR);
> +    ppc_intr_add(env, 0x00001F00, POWERPC_EXCP_NMEXTBR);
>      env->ivor_mask = 0x0000FFF0UL;
>      env->ivpr_mask = 0xFFFF0000UL;
>      /* Hardware reset vector */
> @@ -2232,23 +2233,23 @@ static void init_excp_MPC8xx(CPUPPCState *env)
>  static void init_excp_G2(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_CRITICAL);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2257,26 +2258,26 @@ static void init_excp_G2(CPUPPCState *env)
>  static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000FFC;
> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_SPEU]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_EFPDI]    = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_EFPRI]    = 0x00000000;
> +    ppc_intr_add(env, 0x00000FFC, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_CRITICAL);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_APU);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FIT);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_WDT);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DTLB);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ITLB);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DEBUG);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SPEU);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EFPDI);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EFPRI);
>      env->ivor_mask = 0x0000FFF7UL;
>      env->ivpr_mask = ivpr_mask;
>      /* Hardware reset vector */
> @@ -2287,22 +2288,22 @@ static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
>  static void init_excp_BookE(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
> -    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_CRITICAL);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_APU);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FIT);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_WDT);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DTLB);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ITLB);
> +    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DEBUG);
>      env->ivor_mask = 0x0000FFF0UL;
>      env->ivpr_mask = 0xFFFF0000UL;
>      /* Hardware reset vector */
> @@ -2313,18 +2314,18 @@ static void init_excp_BookE(CPUPPCState *env)
>  static void init_excp_601(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_IO]       = 0x00000A00;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_RUNM]     = 0x00002000;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_IO);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_RUNM);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2334,24 +2335,24 @@ static void init_excp_602(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
>      /* XXX: exception prefix has a special behavior on 602 */
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> -    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001500;
> -    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001600;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
> +    ppc_intr_add(env, 0x00001500, POWERPC_EXCP_WDT);
> +    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_EMUL);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2360,22 +2361,22 @@ static void init_excp_602(CPUPPCState *env)
>  static void init_excp_603(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2384,20 +2385,20 @@ static void init_excp_603(CPUPPCState *env)
>  static void init_excp_604(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2406,21 +2407,21 @@ static void init_excp_604(CPUPPCState *env)
>  static void init_excp_7x0(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> -    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
> +    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2429,20 +2430,20 @@ static void init_excp_7x0(CPUPPCState *env)
>  static void init_excp_750cl(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2451,20 +2452,20 @@ static void init_excp_750cl(CPUPPCState *env)
>  static void init_excp_750cx(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2474,24 +2475,24 @@ static void init_excp_750cx(CPUPPCState *env)
>  static void init_excp_7x5(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> -    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
> +    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2500,23 +2501,23 @@ static void init_excp_7x5(CPUPPCState *env)
>  static void init_excp_7400(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> -    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
> -    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
> +    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_VPUA);
> +    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2525,25 +2526,25 @@ static void init_excp_7400(CPUPPCState *env)
>  static void init_excp_7450(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
> -    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
> -    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
> -    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
> -    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
> +    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
> +    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
> +    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
> +    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_VPUA);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x00000100UL;
>  #endif
> @@ -2553,26 +2554,26 @@ static void init_excp_7450(CPUPPCState *env)
>  static void init_excp_970(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
> -    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
> -    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
> -    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
> -    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000380, POWERPC_EXCP_DSEG);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000480, POWERPC_EXCP_ISEG);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000980, POWERPC_EXCP_HDECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
> +    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
> +    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_MAINT);
> +    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_VPUA);
> +    ppc_intr_add(env, 0x00001800, POWERPC_EXCP_THERM);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x0000000000000100ULL;
>  #endif
> @@ -2581,27 +2582,27 @@ static void init_excp_970(CPUPPCState *env)
>  static void init_excp_POWER7(CPUPPCState *env)
>  {
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
> -    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
> -    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
> -    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
> -    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
> -    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
> -    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
> -    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
> -    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
> -    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
> -    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
> -    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
> -    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
> -    env->excp_vectors[POWERPC_EXCP_HDSI]     = 0x00000E00;
> -    env->excp_vectors[POWERPC_EXCP_HISI]     = 0x00000E20;
> -    env->excp_vectors[POWERPC_EXCP_HV_EMU]   = 0x00000E40;
> -    env->excp_vectors[POWERPC_EXCP_HV_MAINT] = 0x00000E60;
> -    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
> -    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
> -    env->excp_vectors[POWERPC_EXCP_VSXU]     = 0x00000F40;
> +    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
> +    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
> +    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
> +    ppc_intr_add(env, 0x00000380, POWERPC_EXCP_DSEG);
> +    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
> +    ppc_intr_add(env, 0x00000480, POWERPC_EXCP_ISEG);
> +    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
> +    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
> +    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
> +    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
> +    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
> +    ppc_intr_add(env, 0x00000980, POWERPC_EXCP_HDECR);
> +    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
> +    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
> +    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_HDSI);
> +    ppc_intr_add(env, 0x00000E20, POWERPC_EXCP_HISI);
> +    ppc_intr_add(env, 0x00000E40, POWERPC_EXCP_HV_EMU);
> +    ppc_intr_add(env, 0x00000E60, POWERPC_EXCP_HV_MAINT);
> +    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
> +    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
> +    ppc_intr_add(env, 0x00000F40, POWERPC_EXCP_VSXU);
>      /* Hardware reset vector */
>      env->hreset_vector = 0x0000000000000100ULL;
>  #endif
> @@ -2612,10 +2613,10 @@ static void init_excp_POWER8(CPUPPCState *env)
>      init_excp_POWER7(env);
>  
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_SDOOR]    = 0x00000A00;
> -    env->excp_vectors[POWERPC_EXCP_FU]       = 0x00000F60;
> -    env->excp_vectors[POWERPC_EXCP_HV_FU]    = 0x00000F80;
> -    env->excp_vectors[POWERPC_EXCP_SDOOR_HV] = 0x00000E80;
> +    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_SDOOR);
> +    ppc_intr_add(env, 0x00000F60, POWERPC_EXCP_FU);
> +    ppc_intr_add(env, 0x00000F80, POWERPC_EXCP_HV_FU);
> +    ppc_intr_add(env, 0x00000E80, POWERPC_EXCP_SDOOR_HV);
>  #endif
>  }
>  
> @@ -2624,8 +2625,8 @@ static void init_excp_POWER9(CPUPPCState *env)
>      init_excp_POWER8(env);
>  
>  #if !defined(CONFIG_USER_ONLY)
> -    env->excp_vectors[POWERPC_EXCP_HVIRT]    = 0x00000EA0;
> -    env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000;
> +    ppc_intr_add(env, 0x00000EA0, POWERPC_EXCP_HVIRT);
> +    ppc_intr_add(env, 0x00017000, POWERPC_EXCP_SYSCALL_VECTORED);
>  #endif
>  }
>  
> @@ -8375,13 +8376,8 @@ static void init_ppc_proc(PowerPCCPU *cpu)
>      PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
>      CPUPPCState *env = &cpu->env;
>  #if !defined(CONFIG_USER_ONLY)
> -    int i;
>  
>      env->irq_inputs = NULL;
> -    /* Set all exception vectors to an invalid address */
> -    for (i = 0; i < POWERPC_EXCP_NB; i++) {
> -        env->excp_vectors[i] = (target_ulong)(-1ULL);
> -    }
>      env->ivor_mask = 0x00000000;
>      env->ivpr_mask = 0x00000000;
>      /* Default MMU definitions */
> diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
> index 12bf829c8f..26cbfab923 100644
> --- a/target/ppc/excp_helper.c
> +++ b/target/ppc/excp_helper.c
> @@ -29,14 +29,6 @@
>  #endif
>  
>  /* #define DEBUG_OP */
> -/* #define DEBUG_SOFTWARE_TLB */
> -/* #define DEBUG_EXCEPTIONS */
> -
> -#ifdef DEBUG_EXCEPTIONS
> -#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
> -#else
> -#  define LOG_EXCP(...) do { } while (0)
> -#endif
>  
>  /*****************************************************************************/
>  /* Exception processing */
> @@ -58,32 +50,6 @@ static void ppc_hw_interrupt(CPUPPCState *env)
>      env->error_code = 0;
>  }
>  #else /* defined(CONFIG_USER_ONLY) */
> -static inline void dump_syscall(CPUPPCState *env)
> -{
> -    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
> -                  " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
> -                  " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
> -                  " nip=" TARGET_FMT_lx "\n",
> -                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
> -                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
> -                  ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
> -                  ppc_dump_gpr(env, 8), env->nip);
> -}
> -
> -static inline void dump_hcall(CPUPPCState *env)
> -{
> -    qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
> -                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
> -                  " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
> -                  " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
> -                  " nip=" TARGET_FMT_lx "\n",
> -                  ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
> -                  ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
> -                  ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
> -                  ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
> -                  ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
> -                  env->nip);
> -}
>  
>  static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
>                                  target_ulong *msr)
> @@ -311,17 +277,6 @@ static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
>      check_tlb_flush(env, false);
>  }
>  
> -struct ppc_intr_args {
> -    target_ulong nip;
> -    target_ulong msr;
> -    target_ulong new_nip;
> -    target_ulong new_msr;
> -    int sprn_srr0;
> -    int sprn_srr1;
> -    int sprn_asrr0;
> -    int sprn_asrr1;
> -};
> -
>  /*
>   * Note that this function should be greatly optimized when called
>   * with a constant excp, from ppc_hw_interrupt
> @@ -331,11 +286,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      CPUState *cs = CPU(cpu);
>      CPUPPCState *env = &cpu->env;
>      struct ppc_intr_args regs;
> -    int lev = -1;
> +    PPCInterrupt *intr;
> +    bool ignore = false;
>  
>      qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
>                    " => %08x (%02x)\n", env->nip, excp, env->error_code);
>  
> +    if (excp == POWERPC_EXCP_NONE) {
> +        return;
> +    }
> +
> +    if (excp < POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
> +        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
> +        return;
> +    }
> +
>      /* new srr1 value excluding must-be-zero bits */
>      if (excp_model == POWERPC_EXCP_BOOKE) {
>          regs.msr = env->msr;
> @@ -380,469 +345,21 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>          excp = POWERPC_EXCP_PROGRAM;
>      }
>  
> -    switch (excp) {
> -    case POWERPC_EXCP_NONE:
> -        /* Should never happen */
> -        return;
> -    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
> -        switch (excp_model) {
> -        case POWERPC_EXCP_40x:
> -            regs.sprn_srr0 = SPR_40x_SRR2;
> -            regs.sprn_srr1 = SPR_40x_SRR3;
> -            break;
> -        case POWERPC_EXCP_BOOKE:
> -            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
> -            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
> -            break;
> -        case POWERPC_EXCP_G2:
> -            break;
> -        default:
> -            goto excp_invalid;
> -        }
> -        break;
> -    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
> -        if (msr_me == 0) {
> -            /*
> -             * Machine check exception is not enabled.  Enter
> -             * checkstop state.
> -             */
> -            fprintf(stderr, "Machine check while not allowed. "
> -                    "Entering checkstop state\n");
> -            if (qemu_log_separate()) {
> -                qemu_log("Machine check while not allowed. "
> -                        "Entering checkstop state\n");
> -            }
> -            cs->halted = 1;
> -            cpu_interrupt_exittb(cs);
> -        }
> -        if (env->msr_mask & MSR_HVB) {
> -            /*
> -             * ISA specifies HV, but can be delivered to guest with HV
> -             * clear (e.g., see FWNMI in PAPR).
> -             */
> -            regs.new_msr |= (target_ulong)MSR_HVB;
> -        }
> -
> -        /* machine check exceptions don't have ME set */
> -        regs.new_msr &= ~((target_ulong)1 << MSR_ME);
> -
> -        /* XXX: should also have something loaded in DAR / DSISR */
> -        switch (excp_model) {
> -        case POWERPC_EXCP_40x:
> -            regs.sprn_srr0 = SPR_40x_SRR2;
> -            regs.sprn_srr1 = SPR_40x_SRR3;
> -            break;
> -        case POWERPC_EXCP_BOOKE:
> -            /* FIXME: choose one or the other based on CPU type */
> -            regs.sprn_srr0 = SPR_BOOKE_MCSRR0;
> -            regs.sprn_srr1 = SPR_BOOKE_MCSRR1;
> -            regs.sprn_asrr0 = SPR_BOOKE_CSRR0;
> -            regs.sprn_asrr1 = SPR_BOOKE_CSRR1;
> -            break;
> -        default:
> -            break;
> -        }
> -        break;
> -    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
> -        LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
> -                 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
> -        break;
> -    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
> -        LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
> -                 "\n", regs.msr, regs.nip);
> -        regs.msr |= env->error_code;
> -        break;
> -    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
> -    {
> -        bool lpes0;
> -
> -        cs = CPU(cpu);
> -
> -        /*
> -         * Exception targeting modifiers
> -         *
> -         * LPES0 is supported on POWER7/8/9
> -         * LPES1 is not supported (old iSeries mode)
> -         *
> -         * On anything else, we behave as if LPES0 is 1
> -         * (externals don't alter MSR:HV)
> -         */
> -#if defined(TARGET_PPC64)
> -        if (excp_model == POWERPC_EXCP_POWER7 ||
> -            excp_model == POWERPC_EXCP_POWER8 ||
> -            excp_model == POWERPC_EXCP_POWER9 ||
> -            excp_model == POWERPC_EXCP_POWER10) {
> -            lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
> -        } else
> -#endif /* defined(TARGET_PPC64) */
> -        {
> -            lpes0 = true;
> -        }
> -
> -        if (!lpes0) {
> -            regs.new_msr |= (target_ulong)MSR_HVB;
> -            regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -            regs.sprn_srr0 = SPR_HSRR0;
> -            regs.sprn_srr1 = SPR_HSRR1;
> -        }
> -        if (env->mpic_proxy) {
> -            /* IACK the IRQ on delivery */
> -            env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
> -        }
> -        break;
> +    intr = &env->entry_points[excp];
> +    if (!intr->setup_regs) {
> +        cpu_abort(cs, "Raised an exception without defined vector %d\n",
> +                  excp);
>      }
> -    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
> -        /* Get rS/rD and rA from faulting opcode */
> -        /*
> -         * Note: the opcode fields will not be set properly for a
> -         * direct store load/store, but nobody cares as nobody
> -         * actually uses direct store segments.
> -         */
> -        env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
> -        break;
> -    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
> -        switch (env->error_code & ~0xF) {
> -        case POWERPC_EXCP_FP:
> -            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
> -                LOG_EXCP("Ignore floating point exception\n");
> -                cs->exception_index = POWERPC_EXCP_NONE;
> -                env->error_code = 0;
> -                return;
> -            }
>  
> -            /*
> -             * FP exceptions always have NIP pointing to the faulting
> -             * instruction, so always use store_next and claim we are
> -             * precise in the MSR.
> -             */
> -            regs.msr |= 0x00100000;
> -            env->spr[SPR_BOOKE_ESR] = ESR_FP;
> -            break;
> -        case POWERPC_EXCP_INVAL:
> -            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", regs.nip);
> -            regs.msr |= 0x00080000;
> -            env->spr[SPR_BOOKE_ESR] = ESR_PIL;
> -            break;
> -        case POWERPC_EXCP_PRIV:
> -            regs.msr |= 0x00040000;
> -            env->spr[SPR_BOOKE_ESR] = ESR_PPR;
> -            break;
> -        case POWERPC_EXCP_TRAP:
> -            regs.msr |= 0x00020000;
> -            env->spr[SPR_BOOKE_ESR] = ESR_PTR;
> -            break;
> -        default:
> -            /* Should never occur */
> -            cpu_abort(cs, "Invalid program exception %d. Aborting\n",
> -                      env->error_code);
> -            break;
> -        }
> -        break;
> -    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
> -        lev = env->error_code;
> -
> -        if ((lev == 1) && cpu->vhyp) {
> -            dump_hcall(env);
> -        } else {
> -            dump_syscall(env);
> -        }
> +    regs.new_nip = intr->addr | env->excp_prefix;
> +    intr->setup_regs(cpu, intr, excp_model, &regs, &ignore);
>  
> +    if (ignore) {
>          /*
> -         * We need to correct the NIP which in this case is supposed
> -         * to point to the next instruction. We also set env->nip here
> -         * because the modification needs to be accessible by the
> -         * virtual hypervisor code below.
> +         * The interrupt was ignored or delivered by other means
> +         * (e.g. vhyp).
>           */
> -        regs.nip += 4;
> -        env->nip = regs.nip;
> -
> -        /* "PAPR mode" built-in hypercall emulation */
> -        if ((lev == 1) && cpu->vhyp) {
> -            PPCVirtualHypervisorClass *vhc =
> -                PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> -            vhc->hypercall(cpu->vhyp, cpu);
> -            return;
> -        }
> -
> -        if (lev == 1) {
> -            regs.new_msr |= (target_ulong)MSR_HVB;
> -        }
> -        break;
> -    case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
> -        lev = env->error_code;
> -        dump_syscall(env);
> -        regs.nip += 4;
> -        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
> -        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        break;
> -    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
> -    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
> -    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
> -        break;
> -    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
> -        /* FIT on 4xx */
> -        LOG_EXCP("FIT exception\n");
> -        break;
> -    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
> -        LOG_EXCP("WDT exception\n");
> -        switch (excp_model) {
> -        case POWERPC_EXCP_BOOKE:
> -            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
> -            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
> -            break;
> -        default:
> -            break;
> -        }
> -        break;
> -    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
> -    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
> -        break;
> -    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
> -        if (env->flags & POWERPC_FLAG_DE) {
> -            /* FIXME: choose one or the other based on CPU type */
> -            regs.sprn_srr0 = SPR_BOOKE_DSRR0;
> -            regs.sprn_srr1 = SPR_BOOKE_DSRR1;
> -            regs.sprn_asrr0 = SPR_BOOKE_CSRR0;
> -            regs.sprn_asrr1 = SPR_BOOKE_CSRR1;
> -            /* DBSR already modified by caller */
> -        } else {
> -            cpu_abort(cs, "Debug exception triggered on unsupported model\n");
> -        }
> -        break;
> -    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
> -        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> -        break;
> -    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "Embedded floating point data exception "
> -                  "is not implemented yet !\n");
> -        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> -        break;
> -    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "Embedded floating point round exception "
> -                  "is not implemented yet !\n");
> -        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> -        break;
> -    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
> -        /* XXX: TODO */
> -        cpu_abort(cs,
> -                  "Performance counter exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
> -        break;
> -    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
> -        regs.sprn_srr0 = SPR_BOOKE_CSRR0;
> -        regs.sprn_srr1 = SPR_BOOKE_CSRR1;
> -        break;
> -    case POWERPC_EXCP_RESET:     /* System reset exception                   */
> -        /* A power-saving exception sets ME, otherwise it is unchanged */
> -        if (msr_pow) {
> -            /* indicate that we resumed from power save mode */
> -            regs.msr |= 0x10000;
> -            regs.new_msr |= ((target_ulong)1 << MSR_ME);
> -        }
> -        if (env->msr_mask & MSR_HVB) {
> -            /*
> -             * ISA specifies HV, but can be delivered to guest with HV
> -             * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
> -             */
> -            regs.new_msr |= (target_ulong)MSR_HVB;
> -        } else {
> -            if (msr_pow) {
> -                cpu_abort(cs, "Trying to deliver power-saving system reset "
> -                          "exception %d with no HV support\n", excp);
> -            }
> -        }
> -        break;
> -    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
> -    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
> -    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
> -        break;
> -    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
> -        regs.msr |= env->error_code;
> -        /* fall through */
> -    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
> -    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
> -    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
> -    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
> -    case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
> -    case POWERPC_EXCP_HV_EMU:
> -    case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
> -        regs.sprn_srr0 = SPR_HSRR0;
> -        regs.sprn_srr1 = SPR_HSRR1;
> -        regs.new_msr |= (target_ulong)MSR_HVB;
> -        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -        break;
> -    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
> -    case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
> -    case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
> -#ifdef TARGET_PPC64
> -        env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
> -#endif
> -        break;
> -    case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
> -#ifdef TARGET_PPC64
> -        env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
> -        regs.sprn_srr0 = SPR_HSRR0;
> -        regs.sprn_srr1 = SPR_HSRR1;
> -        regs.new_msr |= (target_ulong)MSR_HVB;
> -        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> -#endif
> -        break;
> -    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
> -        LOG_EXCP("PIT exception\n");
> -        break;
> -    case POWERPC_EXCP_IO:        /* IO error exception                       */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "602 emulation trap exception "
> -                  "is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
> -    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
> -    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
> -        switch (excp_model) {
> -        case POWERPC_EXCP_602:
> -        case POWERPC_EXCP_603:
> -        case POWERPC_EXCP_603E:
> -        case POWERPC_EXCP_G2:
> -            /* Swap temporary saved registers with GPRs */
> -            if (!(regs.new_msr & ((target_ulong)1 << MSR_TGPR))) {
> -                regs.new_msr |= (target_ulong)1 << MSR_TGPR;
> -                hreg_swap_gpr_tgpr(env);
> -            }
> -            /* fall through */
> -        case POWERPC_EXCP_7x5:
> -#if defined(DEBUG_SOFTWARE_TLB)
> -            if (qemu_log_enabled()) {
> -                const char *es;
> -                target_ulong *miss, *cmp;
> -                int en;
> -
> -                if (excp == POWERPC_EXCP_IFTLB) {
> -                    es = "I";
> -                    en = 'I';
> -                    miss = &env->spr[SPR_IMISS];
> -                    cmp = &env->spr[SPR_ICMP];
> -                } else {
> -                    if (excp == POWERPC_EXCP_DLTLB) {
> -                        es = "DL";
> -                    } else {
> -                        es = "DS";
> -                    }
> -                    en = 'D';
> -                    miss = &env->spr[SPR_DMISS];
> -                    cmp = &env->spr[SPR_DCMP];
> -                }
> -                qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
> -                         TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
> -                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
> -                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
> -                         env->error_code);
> -            }
> -#endif
> -            regs.msr |= env->crf[0] << 28;
> -            regs.msr |= env->error_code; /* key, D/I, S/L bits */
> -            /* Set way using a LRU mechanism */
> -            regs.msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
> -            break;
> -        case POWERPC_EXCP_74xx:
> -#if defined(DEBUG_SOFTWARE_TLB)
> -            if (qemu_log_enabled()) {
> -                const char *es;
> -                target_ulong *miss, *cmp;
> -                int en;
> -
> -                if (excp == POWERPC_EXCP_IFTLB) {
> -                    es = "I";
> -                    en = 'I';
> -                    miss = &env->spr[SPR_TLBMISS];
> -                    cmp = &env->spr[SPR_PTEHI];
> -                } else {
> -                    if (excp == POWERPC_EXCP_DLTLB) {
> -                        es = "DL";
> -                    } else {
> -                        es = "DS";
> -                    }
> -                    en = 'D';
> -                    miss = &env->spr[SPR_TLBMISS];
> -                    cmp = &env->spr[SPR_PTEHI];
> -                }
> -                qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
> -                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
> -                         env->error_code);
> -            }
> -#endif
> -            regs.msr |= env->error_code; /* key bit */
> -            break;
> -        default:
> -            cpu_abort(cs, "Invalid TLB miss exception\n");
> -            break;
> -        }
> -        break;
> -    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "Floating point assist exception "
> -                  "is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "DABR exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "IABR exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_SMI:       /* System management interrupt              */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "SMI exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "Thermal management exception "
> -                  "is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
> -        /* XXX: TODO */
> -        cpu_abort(cs,
> -                  "Performance counter exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
> -        /* XXX: TODO */
> -        cpu_abort(cs,
> -                  "970 soft-patch exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
> -        /* XXX: TODO */
> -        cpu_abort(cs,
> -                  "970 maintenance exception is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "Maskable external exception "
> -                  "is not implemented yet !\n");
> -        break;
> -    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
> -        /* XXX: TODO */
> -        cpu_abort(cs, "Non maskable external exception "
> -                  "is not implemented yet !\n");
> -        break;
> -    default:
> -    excp_invalid:
> -        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
> -        break;
> +        return;
>      }
>  
>      /* Sanity check */
> @@ -892,14 +409,6 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      }
>  #endif
>  
> -    regs.new_nip = env->excp_vectors[excp];
> -    if (regs.new_nip == (target_ulong)-1ULL) {
> -        cpu_abort(cs, "Raised an exception without defined vector %d\n",
> -                  excp);
> -    }
> -
> -    regs.new_nip |= env->excp_prefix;
> -
>      /* If any alternate SRR register are defined, duplicate saved values */
>      if (regs.sprn_asrr0 != -1) {
>          env->spr[regs.sprn_asrr0] = regs.nip;
> @@ -925,24 +434,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
>      }
>  #endif
>  
> -    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
> +    if (intr->id != POWERPC_EXCP_SYSCALL_VECTORED) {
>          /* Save PC */
>          env->spr[regs.sprn_srr0] = regs.nip;
>  
>          /* Save MSR */
>          env->spr[regs.sprn_srr1] = regs.msr;
> -
> -#if defined(TARGET_PPC64)
> -    } else {
> -        regs.new_nip += lev * 0x20;
> -
> -        env->lr = regs.nip;
> -        env->ctr = regs.msr;
> -#endif
>      }
>  
>      /* This can update regs.new_msr and regs.new_nip if AIL applies */
> -    ppc_excp_apply_ail(cpu, excp_model, excp, regs.msr, &regs.new_msr,
> +    ppc_excp_apply_ail(cpu, excp_model, intr->id, regs.msr, &regs.new_msr,
>                         &regs.new_nip);
>  
>      powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
> diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
> new file mode 100644
> index 0000000000..31faea84c5
> --- /dev/null
> +++ b/target/ppc/interrupts.c
> @@ -0,0 +1,638 @@
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "cpu.h"
> +#include "ppc_intr.h"
> +
> +/* for hreg_swap_gpr_tgpr */
> +#include "helper_regs.h"
> +
> +/* #define DEBUG_SOFTWARE_TLB */
> +/* #define DEBUG_EXCEPTIONS */
> +
> +#ifdef DEBUG_EXCEPTIONS
> +#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
> +#else
> +#  define LOG_EXCP(...) do { } while (0)
> +#endif
> +
> +void __ppc_intr_add(CPUPPCState *env, target_ulong addr, int id,
> +                   const char *intr_name)
> +{
> +    PPCInterrupt *intr = &env->entry_points[id];
> +
> +    object_initialize(intr, sizeof(*intr), intr_name);
> +    intr->addr = addr;
> +}
> +
> +static const TypeInfo ppc_interrupt_info = {
> +    .name = TYPE_PPC_INTERRUPT,
> +    .parent = TYPE_OBJECT,
> +    .abstract = true,
> +};
> +
> +static void ppc_interrupt_register_types(void)
> +{
> +    type_register_static(&ppc_interrupt_info);
> +}
> +type_init(ppc_interrupt_register_types);
> +
> +
> +
> +static void ppc_intr_def_log(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                             int excp_model, ppc_intr_args *regs, bool *ignore)
> +{
> +    LOG_EXCP("%s interrupt\n", intr->name);
> +}
> +
> +static void ppc_intr_def_not_impl(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                  int excp_model, ppc_intr_args *regs,
> +                                  bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +
> +    cpu_abort(cs, "%s interrupt not implemented yet.\n", intr->name);
> +}
> +
> +static void ppc_intr_def_no_op(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                               int excp_model, ppc_intr_args *regs,
> +                               bool *ignore)
> +{
> +}
> +
> +/* Default implementation for interrupts that set the MSR_HV bit */
> +static void ppc_intr_def_hv(PowerPCCPU *cpu, PPCInterrupt *intr, int excp_model,
> +                            ppc_intr_args *regs, bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    regs->sprn_srr0 = SPR_HSRR0;
> +    regs->sprn_srr1 = SPR_HSRR1;
> +    regs->new_msr |= (target_ulong)MSR_HVB;
> +    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +}
> +
> +/* Default implementation for Facility Unavailable interrupts */
> +static void ppc_intr_def_fac_unavail_64(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                        int excp_model, ppc_intr_args *regs,
> +                                        bool *ignore)
> +{
> +#ifdef TARGET_PPC64
> +    CPUPPCState *env = &cpu->env;
> +    env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
> +#endif
> +}
> +
> +static void ppc_debug_software_tlb(CPUPPCState *env, int excp, int excp_model,
> +                                   int imiss_sprn, int icmp_sprn,
> +                                   int dmiss_sprn, int dcmp_sprn)
> +{
> +#if defined(DEBUG_SOFTWARE_TLB)
> +    if (qemu_log_enabled()) {
> +        const char *es;
> +        target_ulong *miss, *cmp;
> +        int en;
> +
> +        if (excp == POWERPC_EXCP_IFTLB) {
> +            es = "I";
> +            en = 'I';
> +            miss = &env->spr[imiss_sprn];
> +            cmp = &env->spr[icmp_sprn];
> +        } else {
> +            if (excp == POWERPC_EXCP_DLTLB) {
> +                es = "DL";
> +            } else {
> +                es = "DS";
> +            }
> +            en = 'D';
> +            miss = &env->spr[dmiss_sprn];
> +            cmp = &env->spr[dcmp_srpn];
> +        }
> +
> +        if (excp_model == POWERPC_EXCP_74xx) {
> +            qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
> +                     TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
> +                     env->error_code);
> +        } else {
> +            qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
> +                     TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
> +                     TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
> +                     env->spr[SPR_HASH1], env->spr[SPR_HASH2],
> +                     env->error_code);
> +        }
> +    }
> +#endif
> +}
> +
> +static void ppc_intr_def_tlb_miss(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                  int excp_model, ppc_intr_args *regs,
> +                                  bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    switch (excp_model) {
> +    case POWERPC_EXCP_602:
> +    case POWERPC_EXCP_603:
> +    case POWERPC_EXCP_603E:
> +    case POWERPC_EXCP_G2:
> +        /* Swap temporary saved registers with GPRs */
> +        if (!(regs->new_msr & ((target_ulong)1 << MSR_TGPR))) {
> +            regs->new_msr |= (target_ulong)1 << MSR_TGPR;
> +            hreg_swap_gpr_tgpr(env);
> +        }
> +
> +        ppc_debug_software_tlb(env, intr->id, excp_model,
> +                               SPR_IMISS, SPR_ICMP,
> +                               SPR_DMISS, SPR_DCMP);
> +
> +        /* fall through */
> +    case POWERPC_EXCP_7x5:
> +        regs->msr |= env->crf[0] << 28;
> +        regs->msr |= env->error_code; /* key, D/I, S/L bits */
> +
> +        /* Set way using a LRU mechanism */
> +        regs->msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
> +
> +        break;
> +    case POWERPC_EXCP_74xx:
> +        ppc_debug_software_tlb(env, intr->id, excp_model,
> +                               SPR_TLBMISS, SPR_PTEHI,
> +                               SPR_TLBMISS, SPR_PTEHI);
> +
> +        regs->msr |= env->error_code; /* key bit */
> +        break;
> +    default:
> +        cpu_abort(cs, "Invalid instruction TLB miss exception\n");
> +        break;
> +    }
> +}
> +
> +static void ppc_intr_critical(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                              int excp_model, ppc_intr_args *regs, bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +
> +    switch (excp_model) {
> +    case POWERPC_EXCP_40x:
> +        regs->sprn_srr0 = SPR_40x_SRR2;
> +        regs->sprn_srr1 = SPR_40x_SRR3;
> +        break;
> +    case POWERPC_EXCP_BOOKE:
> +        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
> +        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
> +        break;
> +    case POWERPC_EXCP_G2:
> +        break;
> +    default:
> +        cpu_abort(cs, "Invalid Critical interrupt for model %d. Aborting\n",
> +                  excp_model);
> +        break;
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_CRITICAL, critical, "Critical input");
> +
> +static void ppc_intr_machine_check(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                   int excp_model, ppc_intr_args *regs,
> +                                   bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    if (msr_me == 0) {
> +        /*
> +         * Machine check exception is not enabled.  Enter
> +         * checkstop state.
> +         */
> +        fprintf(stderr, "Machine check while not allowed. "
> +                "Entering checkstop state\n");
> +        if (qemu_log_separate()) {
> +            qemu_log("Machine check while not allowed. "
> +                     "Entering checkstop state\n");
> +        }
> +        cs->halted = 1;
> +        cpu_interrupt_exittb(cs);
> +    }
> +    if (env->msr_mask & MSR_HVB) {
> +        /*
> +         * ISA specifies HV, but can be delivered to guest with HV
> +         * clear (e.g., see FWNMI in PAPR).
> +         */
> +        regs->new_msr |= (target_ulong)MSR_HVB;
> +    }
> +
> +    /* machine check exceptions don't have ME set */
> +    regs->new_msr &= ~((target_ulong)1 << MSR_ME);
> +
> +    /* XXX: should also have something loaded in DAR / DSISR */
> +    switch (excp_model) {
> +    case POWERPC_EXCP_40x:
> +        regs->sprn_srr0 = SPR_40x_SRR2;
> +        regs->sprn_srr1 = SPR_40x_SRR3;
> +        break;
> +    case POWERPC_EXCP_BOOKE:
> +        /* FIXME: choose one or the other based on CPU type */
> +        regs->sprn_srr0 = SPR_BOOKE_MCSRR0;
> +        regs->sprn_srr1 = SPR_BOOKE_MCSRR1;
> +        regs->sprn_asrr0 = SPR_BOOKE_CSRR0;
> +        regs->sprn_asrr1 = SPR_BOOKE_CSRR1;
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_MCHECK, machine_check, "Machine check");
> +
> +static void ppc_intr_data_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                  int excp_model, ppc_intr_args *regs,
> +                                  bool *ignore)
> +{
> +    LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
> +             "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_DSI, data_storage, "Data storage");
> +
> +static void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                  int excp_model, ppc_intr_args *regs,
> +                                  bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
> +             "\n", regs->msr, regs->nip);
> +    regs->msr |= env->error_code;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_ISI, insn_storage, "Instruction storage");
> +
> +static void ppc_intr_external(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                              int excp_model, ppc_intr_args *regs, bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +    bool lpes0;
> +
> +    /*
> +     * Exception targeting modifiers
> +     *
> +     * LPES0 is supported on POWER7/8/9
> +     * LPES1 is not supported (old iSeries mode)
> +     *
> +     * On anything else, we behave as if LPES0 is 1
> +     * (externals don't alter MSR:HV)
> +     */
> +#if defined(TARGET_PPC64)
> +    if (excp_model == POWERPC_EXCP_POWER7 ||
> +        excp_model == POWERPC_EXCP_POWER8 ||
> +        excp_model == POWERPC_EXCP_POWER9 ||
> +        excp_model == POWERPC_EXCP_POWER10) {
> +        lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
> +    } else
> +#endif /* defined(TARGET_PPC64) */
> +    {
> +        lpes0 = true;
> +    }
> +
> +    if (!lpes0) {
> +        regs->new_msr |= (target_ulong)MSR_HVB;
> +        regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +        regs->sprn_srr0 = SPR_HSRR0;
> +        regs->sprn_srr1 = SPR_HSRR1;
> +    }
> +    if (env->mpic_proxy) {
> +        /* IACK the IRQ on delivery */
> +        env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_EXTERNAL, external, "External");
> +
> +static void ppc_intr_alignment(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                               int excp_model, ppc_intr_args *regs,
> +                               bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    /* Get rS/rD and rA from faulting opcode */
> +    /*
> +     * Note: the opcode fields will not be set properly for a
> +     * direct store load/store, but nobody cares as nobody
> +     * actually uses direct store segments.
> +     */
> +    env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_ALIGN, alignment, "Alignment");
> +
> +static void ppc_intr_program(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                             int excp_model, ppc_intr_args *regs, bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    switch (env->error_code & ~0xF) {
> +    case POWERPC_EXCP_FP:
> +        if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
> +            LOG_EXCP("Ignore floating point exception\n");
> +            cs->exception_index = POWERPC_EXCP_NONE;
> +            env->error_code = 0;
> +
> +            *ignore = true;
> +            return;
> +        }
> +
> +        /*
> +         * FP exceptions always have NIP pointing to the faulting
> +         * instruction, so always use store_next and claim we are
> +         * precise in the MSR.
> +         */
> +        regs->msr |= 0x00100000;
> +        env->spr[SPR_BOOKE_ESR] = ESR_FP;
> +        break;
> +    case POWERPC_EXCP_INVAL:
> +        LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", regs->nip);
> +        regs->msr |= 0x00080000;
> +        env->spr[SPR_BOOKE_ESR] = ESR_PIL;
> +        break;
> +    case POWERPC_EXCP_PRIV:
> +        regs->msr |= 0x00040000;
> +        env->spr[SPR_BOOKE_ESR] = ESR_PPR;
> +        break;
> +    case POWERPC_EXCP_TRAP:
> +        regs->msr |= 0x00020000;
> +        env->spr[SPR_BOOKE_ESR] = ESR_PTR;
> +        break;
> +    default:
> +        /* Should never occur */
> +        cpu_abort(cs, "Invalid program exception %d. Aborting\n",
> +                  env->error_code);
> +        break;
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_PROGRAM, program, "Program");
> +
> +
> +static inline void dump_syscall(CPUPPCState *env)
> +{
> +    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
> +                  " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
> +                  " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
> +                  " nip=" TARGET_FMT_lx "\n",
> +                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
> +                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
> +                  ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
> +                  ppc_dump_gpr(env, 8), env->nip);
> +}
> +
> +static inline void dump_hcall(CPUPPCState *env)
> +{
> +    qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
> +                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
> +                  " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
> +                  " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
> +                  " nip=" TARGET_FMT_lx "\n",
> +                  ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
> +                  ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
> +                  ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
> +                  ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
> +                  ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
> +                  env->nip);
> +}
> +
> +
> +static void ppc_intr_system_call(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                 int excp_model, ppc_intr_args *regs,
> +                                 bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +    int lev;
> +
> +    lev = env->error_code;
> +
> +    if ((lev == 1) && cpu->vhyp) {
> +        dump_hcall(env);
> +    } else {
> +        dump_syscall(env);
> +    }
> +
> +    /*
> +     * We need to correct the NIP which in this case is supposed
> +     * to point to the next instruction. We also set env->nip here
> +     * because the modification needs to be accessible by the
> +     * virtual hypervisor code below.
> +     */
> +    regs->nip += 4;
> +    env->nip = regs->nip;
> +
> +    /* "PAPR mode" built-in hypercall emulation */
> +    if ((lev == 1) && cpu->vhyp) {
> +        PPCVirtualHypervisorClass *vhc =
> +            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
> +        vhc->hypercall(cpu->vhyp, cpu);
> +
> +        *ignore = true;
> +        return;
> +    }
> +
> +    if (lev == 1) {
> +        regs->new_msr |= (target_ulong)MSR_HVB;
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_SYSCALL, system_call, "System call");
> +
> +static void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                          int excp_model, ppc_intr_args *regs,
> +                                          bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +    int lev;
> +
> +    lev = env->error_code;
> +    dump_syscall(env);
> +
> +    regs->nip += 4;
> +    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
> +    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
> +    regs->new_nip += lev * 0x20;
> +
> +    env->lr = regs->nip;
> +    env->ctr = regs->msr;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_SYSCALL_VECTORED, system_call_vectored,
> +                     "System call vectored");
> +
> +static void ppc_intr_watchdog(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                              int excp_model, ppc_intr_args *regs, bool *ignore)
> +{
> +    LOG_EXCP("WDT exception\n");
> +    switch (excp_model) {
> +    case POWERPC_EXCP_BOOKE:
> +        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
> +        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_WDT, watchdog, "Watchdog timer");
> +
> +static void ppc_intr_debug(PowerPCCPU *cpu, PPCInterrupt *intr, int excp_model,
> +                           ppc_intr_args *regs, bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    if (env->flags & POWERPC_FLAG_DE) {
> +        /* FIXME: choose one or the other based on CPU type */
> +        regs->sprn_srr0 = SPR_BOOKE_DSRR0;
> +        regs->sprn_srr1 = SPR_BOOKE_DSRR1;
> +        regs->sprn_asrr0 = SPR_BOOKE_CSRR0;
> +        regs->sprn_asrr1 = SPR_BOOKE_CSRR1;
> +        /* DBSR already modified by caller */
> +    } else {
> +        cpu_abort(cs, "Debug exception triggered on unsupported model\n");
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_DEBUG, debug, "Debug");
> +
> +static void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                     int excp_model, ppc_intr_args *regs,
> +                                     bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_SPEU, spe_unavailable,
> +                     "SPE/embedded floating-point unavailable");
> +
> +static void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                      int excp_model, ppc_intr_args *regs,
> +                                      bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    ppc_intr_def_not_impl(cpu, intr, excp_model, regs, ignore);
> +    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_EFPDI, embedded_fp_data,
> +                     "Embedded floating-point data");
> +
> +static void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                       int excp_model, ppc_intr_args *regs,
> +                                       bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    ppc_intr_def_not_impl(cpu, intr, excp_model, regs, ignore);
> +    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_EFPRI, embedded_fp_round,
> +                     "Embedded floating-point round");
> +
> +static void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                            int excp_model, ppc_intr_args *regs,
> +                                            bool *ignore)
> +{
> +    regs->sprn_srr0 = SPR_BOOKE_CSRR0;
> +    regs->sprn_srr1 = SPR_BOOKE_CSRR1;
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_DOORCI, embedded_doorbell_crit,
> +                     "Embedded doorbell critical");
> +
> +static void ppc_intr_system_reset(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                  int excp_model, ppc_intr_args *regs,
> +                                  bool *ignore)
> +{
> +    CPUState *cs = CPU(cpu);
> +    CPUPPCState *env = &cpu->env;
> +
> +    /* A power-saving exception sets ME, otherwise it is unchanged */
> +    if (msr_pow) {
> +        /* indicate that we resumed from power save mode */
> +        regs->msr |= 0x10000;
> +        regs->new_msr |= ((target_ulong)1 << MSR_ME);
> +    }
> +    if (env->msr_mask & MSR_HVB) {
> +        /*
> +         * ISA specifies HV, but can be delivered to guest with HV
> +         * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
> +         */
> +        regs->new_msr |= (target_ulong)MSR_HVB;
> +    } else {
> +        if (msr_pow) {
> +            cpu_abort(cs, "Trying to deliver power-saving system reset "
> +                      "exception with no HV support\n");
> +        }
> +    }
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
> +
> +static void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                     int excp_model, ppc_intr_args *regs,
> +                                     bool *ignore)
> +{
> +    CPUPPCState *env = &cpu->env;
> +
> +    regs->msr |= env->error_code;
> +    ppc_intr_def_hv(cpu, intr, excp_model, regs, ignore);
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_HISI, hv_insn_storage,
> +                     "Hypervisor instruction storage");
> +
> +static void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCInterrupt *intr,
> +                                         int excp_model, ppc_intr_args *regs,
> +                                         bool *ignore)
> +{
> +#ifdef TARGET_PPC64
> +    ppc_intr_def_fac_unavail_64(cpu, intr, excp_model, regs, ignore);
> +    ppc_intr_def_hv(cpu, intr, excp_model, regs, ignore);
> +#endif
> +}
> +PPC_DEFINE_INTR(POWERPC_EXCP_HV_FU, hv_facility_unavail,
> +                "Hypervisor facility unavailable");
> +
> +PPC_DEFINE_INTR(POWERPC_EXCP_HDECR,    def_hv, "Hypervisor decrementer");
> +PPC_DEFINE_INTR(POWERPC_EXCP_HDSI,     def_hv, "Hypervisor data storage");
> +PPC_DEFINE_INTR(POWERPC_EXCP_HDSEG,    def_hv, "Hypervisor data segment");
> +PPC_DEFINE_INTR(POWERPC_EXCP_HISEG,    def_hv, "Hypervisor insn segment");
> +PPC_DEFINE_INTR(POWERPC_EXCP_SDOOR_HV, def_hv, "Hypervisor doorbell");
> +PPC_DEFINE_INTR(POWERPC_EXCP_HV_EMU,   def_hv, "Hypervisor emulation assist");
> +PPC_DEFINE_INTR(POWERPC_EXCP_HVIRT,    def_hv, "Hypervisor virtualization");
> +
> +PPC_DEFINE_INTR(POWERPC_EXCP_VPU,  def_fac_unavail_64, "Vector unavailable");
> +PPC_DEFINE_INTR(POWERPC_EXCP_VSXU, def_fac_unavail_64, "VSX unavailable");
> +PPC_DEFINE_INTR(POWERPC_EXCP_FU,   def_fac_unavail_64, "Facility unavailable");
> +
> +PPC_DEFINE_INTR(POWERPC_EXCP_IFTLB, def_tlb_miss, "Insn fetch TLB error");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DLTLB, def_tlb_miss, "Data load TLB error");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DSTLB, def_tlb_miss, "Data store TLB error");
> +
> +PPC_DEFINE_INTR(POWERPC_EXCP_FIT, def_log, "Fixed-interval timer");
> +PPC_DEFINE_INTR(POWERPC_EXCP_PIT, def_log, "Programmable interval timer");
> +
> +PPC_DEFINE_INTR(POWERPC_EXCP_FPU,   def_no_op, "Floating-point unavailable");
> +PPC_DEFINE_INTR(POWERPC_EXCP_APU,   def_no_op, "Aux. processor unavailable");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DECR,  def_no_op, "Decrementer");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DTLB,  def_no_op, "Data TLB error");
> +PPC_DEFINE_INTR(POWERPC_EXCP_ITLB,  def_no_op, "Instruction TLB error");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DOORI, def_no_op, "Embedded doorbell");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DSEG,  def_no_op, "Data segment");
> +PPC_DEFINE_INTR(POWERPC_EXCP_ISEG,  def_no_op, "Instruction segment");
> +PPC_DEFINE_INTR(POWERPC_EXCP_TRACE, def_no_op, "Trace");
> +
> +PPC_DEFINE_INTR(POWERPC_EXCP_EPERFM,  def_not_impl, "Embedded perf. monitor");
> +PPC_DEFINE_INTR(POWERPC_EXCP_IO,      def_not_impl, "IO error");
> +PPC_DEFINE_INTR(POWERPC_EXCP_RUNM,    def_not_impl, "Run mode");
> +PPC_DEFINE_INTR(POWERPC_EXCP_EMUL,    def_not_impl, "Emulation trap");
> +PPC_DEFINE_INTR(POWERPC_EXCP_FPA,     def_not_impl, "Floating-point assist");
> +PPC_DEFINE_INTR(POWERPC_EXCP_DABR,    def_not_impl, "Data address breakpoint");
> +PPC_DEFINE_INTR(POWERPC_EXCP_IABR,    def_not_impl, "Insn address breakpoint");
> +PPC_DEFINE_INTR(POWERPC_EXCP_SMI,     def_not_impl, "System management");
> +PPC_DEFINE_INTR(POWERPC_EXCP_THERM,   def_not_impl, "Thermal management");
> +PPC_DEFINE_INTR(POWERPC_EXCP_PERFM,   def_not_impl, "Performance counter");
> +PPC_DEFINE_INTR(POWERPC_EXCP_VPUA,    def_not_impl, "Vector assist");
> +PPC_DEFINE_INTR(POWERPC_EXCP_SOFTP,   def_not_impl, "Soft patch");
> +PPC_DEFINE_INTR(POWERPC_EXCP_MAINT,   def_not_impl, "Maintenance");
> +PPC_DEFINE_INTR(POWERPC_EXCP_MEXTBR,  def_not_impl, "Maskable external");
> +PPC_DEFINE_INTR(POWERPC_EXCP_NMEXTBR, def_not_impl, "Non-maskable external");
> +
> +/* These are used by P7 and P8 but were never implemented */
> +PPC_DEFINE_INTR(POWERPC_EXCP_SDOOR, def_not_impl, "Server doorbell");
> +PPC_DEFINE_INTR(POWERPC_EXCP_HV_MAINT, def_not_impl, "Hypervisor maintenance");
> diff --git a/target/ppc/machine.c b/target/ppc/machine.c
> index 93972df58e..3927359c7b 100644
> --- a/target/ppc/machine.c
> +++ b/target/ppc/machine.c
> @@ -115,7 +115,7 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
>      qemu_get_be32s(f, &env->pending_interrupts);
>      qemu_get_be32s(f, &env->irq_input_state);
>      for (i = 0; i < POWERPC_EXCP_NB; i++) {
> -        qemu_get_betls(f, &env->excp_vectors[i]);
> +        qemu_get_betls(f, &env->entry_points[i].addr);
>      }
>      qemu_get_betls(f, &env->excp_prefix);
>      qemu_get_betls(f, &env->ivor_mask);
> diff --git a/target/ppc/meson.build b/target/ppc/meson.build
> index a6a53a8d5c..740eac25f7 100644
> --- a/target/ppc/meson.build
> +++ b/target/ppc/meson.build
> @@ -30,6 +30,7 @@ ppc_softmmu_ss.add(files(
>    'mmu-hash32.c',
>    'mmu_helper.c',
>    'monitor.c',
> +  'interrupts.c',
>  ))
>  ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_false: files(
>    'tcg-stub.c'
> diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
> new file mode 100644
> index 0000000000..e588736c6d
> --- /dev/null
> +++ b/target/ppc/ppc_intr.h
> @@ -0,0 +1,55 @@
> +#ifndef PPC_INTR_H
> +#define PPC_INTR_H
> +
> +#include "qom/object.h"
> +#include "cpu-qom.h"
> +
> +#define TYPE_PPC_INTERRUPT "ppc-interrupt"
> +OBJECT_DECLARE_SIMPLE_TYPE(PPCInterrupt, PPC_INTERRUPT)
> +
> +void __ppc_intr_add(CPUPPCState *env, target_ulong addr, int id,
> +                    const char *intr_name);
> +
> +#define ppc_intr_add(_env, _addr, _id)                  \
> +    do {                                                \
> +        QEMU_BUILD_BUG_ON(_id <= POWERPC_EXCP_NONE);    \
> +        QEMU_BUILD_BUG_ON(_id >= POWERPC_EXCP_NB);      \
> +        __ppc_intr_add(_env, _addr, _id, #_id);         \
> +    } while (0)                                         \
> +
> +/*
> + * Registers an interrupt callback as a class. This makes it so that
> + * the interrupt callback implementation is stored on QOM and we can
> + * instantiate only the ones needed for a specific processor later.
> + *
> + * @_id: The interrupt id as in the POWERPC_EXCP_* enum. This will be
> + *   the QOM hash table key for the type.
> + * @_sym: The interrupt name as a valid C identifier. This will be
> + *   used to compose the symbol name for the callback to be invoked
> + *   for this interrupt.
> + * @_name: The interrupt name as a string for display.
> + */
> +#define PPC_DEFINE_INTR(_id, _sym, _name)       \
> +                                                \
> +    static void __##_id##_init(Object *obj)     \
> +    {                                           \
> +        PPCInterrupt *pi = PPC_INTERRUPT(obj);  \
> +                                                \
> +        pi->id = _id;                           \
> +        pi->name = _name;                       \
> +        pi->setup_regs = ppc_intr_##_sym;       \
> +    }                                           \
> +                                                \
> +    static const TypeInfo __##_id##_info = {    \
> +        .parent = TYPE_PPC_INTERRUPT,           \
> +        .name = #_id,                           \
> +        .instance_init = __##_id##_init,        \
> +    };                                          \
> +                                                \
> +    static void __##_id##_register_types(void)  \
> +    {                                           \
> +        type_register_static(&__##_id##_info);  \
> +    }                                           \
> +    type_init(__##_id##_register_types);        \
> +
> +#endif /* PPC_INTR_H */
> diff --git a/target/ppc/translate.c b/target/ppc/translate.c
> index e16a2721e2..2c82bda8cc 100644
> --- a/target/ppc/translate.c
> +++ b/target/ppc/translate.c
> @@ -951,7 +951,8 @@ void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
>      TCGv t0 = tcg_temp_new();
>      tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
>      tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
> -    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
> +    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, entry_points[sprn_offs]) +
> +                  offsetof(PPCInterrupt, addr));
>      gen_store_spr(sprn, t0);
>      tcg_temp_free(t0);
>  }
Fabiano Rosas June 7, 2021, 4:54 p.m. UTC | #4
David Gibson <david@gibson.dropbear.id.au> writes:

> On Tue, Jun 01, 2021 at 06:46:49PM -0300, Fabiano Rosas wrote:
>> +typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
>> +                              int excp_model, ppc_intr_args *regs,
>> +                              bool *ignore);
>
> Hmm.  Using this signature kind of enforces that we dispatch based on
> which exception *then* then the exception model.  I think that's
> backwards: since what vectors exist and make sense depends on the
> exception model, I think we should ideally be splitting on model
> first, then exception type.
>
> Now, a lot of the existing code is exception-then-model and changing
> that is a long term project, but I don't think we should lock
> ourselves further into doing it the backwards way.

Ok, so assuming one C file per exception model, I see three options:

 i) exception --> model (current):

 Interrupt code separate from models. One implementation for each
 interrupt that takes the model as argument. Models opt-in which
 interrupts they want (according to the ISA).

 ii) model --> exception:

 Interrupt code inside each model file. The model implements only the
 interrupts which exist (according to ISA). There would be duplication
 since several models would implement the same system reset, machine
 check, program, etc.

 iii) model --> exception w/ generic interrupts:

 Generic interrupt code separate from models. One implementation for
 each generic interrupt. Models opt-in which interrupts they want
 (according to the ISA). Models override generic implementation with
 model-specific ones.

Option (i) leads to the most code reuse; (ii) makes each model and its
interrupts into one comprehensive unit; (iii) avoids duplication of the
generic code.

>> +
>> +struct ppc_intr_args {
>> +    target_ulong nip;
>> +    target_ulong msr;
>> +    target_ulong new_nip;
>> +    target_ulong new_msr;
>> +    int sprn_srr0;
>> +    int sprn_srr1;
>> +    int sprn_asrr0;
>> +    int sprn_asrr1;
>> +    int lev;
>> +};
>> +
>> +struct PPCInterrupt {
>
> Having an info/dispatch structure for each vector makes sense..
>
>> +    Object parent;
>
> ..but making it a QOM object really seems like overkill.  In fact
> making it a QOM object at least somewhat exposes the internal
> structure to the user via QMP, which I really don't think we want to
> do.

I'm using QOM code mainly to facilitate the id->function mapping. I'll
remove the QOM layer and implement my own.

>> +
>> +    int id;
>> +    const char *name;
>> +    target_ulong addr;
>> +    ppc_intr_fn_t setup_regs;
>> +};
David Gibson June 15, 2021, 5:56 a.m. UTC | #5
On Mon, Jun 07, 2021 at 01:54:15PM -0300, Fabiano Rosas wrote:
> David Gibson <david@gibson.dropbear.id.au> writes:
> 
> > On Tue, Jun 01, 2021 at 06:46:49PM -0300, Fabiano Rosas wrote:
> >> +typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
> >> +                              int excp_model, ppc_intr_args *regs,
> >> +                              bool *ignore);
> >
> > Hmm.  Using this signature kind of enforces that we dispatch based on
> > which exception *then* then the exception model.  I think that's
> > backwards: since what vectors exist and make sense depends on the
> > exception model, I think we should ideally be splitting on model
> > first, then exception type.
> >
> > Now, a lot of the existing code is exception-then-model and changing
> > that is a long term project, but I don't think we should lock
> > ourselves further into doing it the backwards way.
> 
> Ok, so assuming one C file per exception model, I see three options:
> 
>  i) exception --> model (current):
> 
>  Interrupt code separate from models. One implementation for each
>  interrupt that takes the model as argument. Models opt-in which
>  interrupts they want (according to the ISA).
> 
>  ii) model --> exception:
> 
>  Interrupt code inside each model file. The model implements only the
>  interrupts which exist (according to ISA). There would be duplication
>  since several models would implement the same system reset, machine
>  check, program, etc.
> 
>  iii) model --> exception w/ generic interrupts:
> 
>  Generic interrupt code separate from models. One implementation for
>  each generic interrupt. Models opt-in which interrupts they want
>  (according to the ISA). Models override generic implementation with
>  model-specific ones.
> 
> Option (i) leads to the most code reuse;

Technically, yes, but my experience with this approach is that because
many of the interrupts have similar, but not quite identical behaviour
in different models, the "common" interrupt path is so littered with
special cases and per-model tests that they become very hard to read.
It also makes things fragile, because it's difficult to refactor or
update things for one model without risking breaking some other model
for an obscure CPU variant you barely know and aren't thinking about
at the time.

Basically the reason I think things look at mess at the moment, is
that historically we've tried to share the implementation for things
that aren't quite similar enough for that to really work well.

> (ii) makes each model and its
> interrupts into one comprehensive unit; (iii) avoids duplication of the
> generic code.

Note that with model-then-exception it's still possible and encouraged
for the model specific code to call back to a common "library"
implementation for things that really do have the same logic between
models.  For simple things like system reset the per-model versions
could well just be stubs calling back to generic code.

But for the complex MMU interrupts, which have heaps of variants and
different cases, I think model-then-exception will make following the
logic much easier.

> 
> >> +
> >> +struct ppc_intr_args {
> >> +    target_ulong nip;
> >> +    target_ulong msr;
> >> +    target_ulong new_nip;
> >> +    target_ulong new_msr;
> >> +    int sprn_srr0;
> >> +    int sprn_srr1;
> >> +    int sprn_asrr0;
> >> +    int sprn_asrr1;
> >> +    int lev;
> >> +};
> >> +
> >> +struct PPCInterrupt {
> >
> > Having an info/dispatch structure for each vector makes sense..
> >
> >> +    Object parent;
> >
> > ..but making it a QOM object really seems like overkill.  In fact
> > making it a QOM object at least somewhat exposes the internal
> > structure to the user via QMP, which I really don't think we want to
> > do.
> 
> I'm using QOM code mainly to facilitate the id->function mapping. I'll
> remove the QOM layer and implement my own.
> 
> >> +
> >> +    int id;
> >> +    const char *name;
> >> +    target_ulong addr;
> >> +    ppc_intr_fn_t setup_regs;
> >> +};
>
diff mbox series

Patch

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index b0934d9be4..012677965f 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -174,6 +174,33 @@  enum {
     POWERPC_EXCP_TRAP          = 0x40,
 };
 
+typedef struct PPCInterrupt PPCInterrupt;
+typedef struct ppc_intr_args ppc_intr_args;
+typedef void (*ppc_intr_fn_t)(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs,
+                              bool *ignore);
+
+struct ppc_intr_args {
+    target_ulong nip;
+    target_ulong msr;
+    target_ulong new_nip;
+    target_ulong new_msr;
+    int sprn_srr0;
+    int sprn_srr1;
+    int sprn_asrr0;
+    int sprn_asrr1;
+    int lev;
+};
+
+struct PPCInterrupt {
+    Object parent;
+
+    int id;
+    const char *name;
+    target_ulong addr;
+    ppc_intr_fn_t setup_regs;
+};
+
 #define PPC_INPUT(env) ((env)->bus_model)
 
 /*****************************************************************************/
@@ -1115,7 +1142,7 @@  struct CPUPPCState {
     uint32_t irq_input_state;
     void **irq_inputs;
 
-    target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */
+    PPCInterrupt entry_points[POWERPC_EXCP_NB];
     target_ulong excp_prefix;
     target_ulong ivor_mask;
     target_ulong ivpr_mask;
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index d0411e7302..d91183357d 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -46,6 +46,7 @@ 
 #include "helper_regs.h"
 #include "internal.h"
 #include "spr_tcg.h"
+#include "ppc_intr.h"
 
 /* #define PPC_DEBUG_SPR */
 /* #define USE_APPLE_GDB */
@@ -2132,16 +2133,16 @@  static void register_8xx_sprs(CPUPPCState *env)
 static void init_excp_4xx_real(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
+    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2152,20 +2153,20 @@  static void init_excp_4xx_real(CPUPPCState *env)
 static void init_excp_4xx_softmmu(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_PIT);
+    ppc_intr_add(env, 0x00001010, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00001020, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_DEBUG);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2176,21 +2177,21 @@  static void init_excp_4xx_softmmu(CPUPPCState *env)
 static void init_excp_MPC5xx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
-    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
-    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_FPA);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_EMUL);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_DABR);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001E00, POWERPC_EXCP_MEXTBR);
+    ppc_intr_add(env, 0x00001F00, POWERPC_EXCP_NMEXTBR);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2201,27 +2202,27 @@  static void init_excp_MPC5xx(CPUPPCState *env)
 static void init_excp_MPC8xx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
-    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_ITLBE]    = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_DTLBE]    = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_DABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001C00;
-    env->excp_vectors[POWERPC_EXCP_MEXTBR]   = 0x00001E00;
-    env->excp_vectors[POWERPC_EXCP_NMEXTBR]  = 0x00001F00;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_FPA);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_EMUL);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_ITLBE);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_DTLBE);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_DABR);
+    ppc_intr_add(env, 0x00001C00, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001E00, POWERPC_EXCP_MEXTBR);
+    ppc_intr_add(env, 0x00001F00, POWERPC_EXCP_NMEXTBR);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2232,23 +2233,23 @@  static void init_excp_MPC8xx(CPUPPCState *env)
 static void init_excp_G2(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2257,26 +2258,26 @@  static void init_excp_G2(CPUPPCState *env)
 static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000FFC;
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_SPEU]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EFPDI]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EFPRI]    = 0x00000000;
+    ppc_intr_add(env, 0x00000FFC, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_APU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DEBUG);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SPEU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EFPDI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EFPRI);
     env->ivor_mask = 0x0000FFF7UL;
     env->ivpr_mask = ivpr_mask;
     /* Hardware reset vector */
@@ -2287,22 +2288,22 @@  static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
 static void init_excp_BookE(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
-    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_CRITICAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_APU);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_FIT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DTLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_ITLB);
+    ppc_intr_add(env, 0x00000000, POWERPC_EXCP_DEBUG);
     env->ivor_mask = 0x0000FFF0UL;
     env->ivpr_mask = 0xFFFF0000UL;
     /* Hardware reset vector */
@@ -2313,18 +2314,18 @@  static void init_excp_BookE(CPUPPCState *env)
 static void init_excp_601(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_IO]       = 0x00000A00;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_RUNM]     = 0x00002000;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_IO);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00002000, POWERPC_EXCP_RUNM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2334,24 +2335,24 @@  static void init_excp_602(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
     /* XXX: exception prefix has a special behavior on 602 */
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001500;
-    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001600;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001500, POWERPC_EXCP_WDT);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_EMUL);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2360,22 +2361,22 @@  static void init_excp_602(CPUPPCState *env)
 static void init_excp_603(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2384,20 +2385,20 @@  static void init_excp_603(CPUPPCState *env)
 static void init_excp_604(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2406,21 +2407,21 @@  static void init_excp_604(CPUPPCState *env)
 static void init_excp_7x0(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2429,20 +2430,20 @@  static void init_excp_7x0(CPUPPCState *env)
 static void init_excp_750cl(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2451,20 +2452,20 @@  static void init_excp_750cl(CPUPPCState *env)
 static void init_excp_750cx(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2474,24 +2475,24 @@  static void init_excp_750cx(CPUPPCState *env)
 static void init_excp_7x5(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2500,23 +2501,23 @@  static void init_excp_7x5(CPUPPCState *env)
 static void init_excp_7400(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_VPUA);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2525,25 +2526,25 @@  static void init_excp_7400(CPUPPCState *env)
 static void init_excp_7450(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
-    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
-    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
-    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00001000, POWERPC_EXCP_IFTLB);
+    ppc_intr_add(env, 0x00001100, POWERPC_EXCP_DLTLB);
+    ppc_intr_add(env, 0x00001200, POWERPC_EXCP_DSTLB);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001400, POWERPC_EXCP_SMI);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_VPUA);
     /* Hardware reset vector */
     env->hreset_vector = 0x00000100UL;
 #endif
@@ -2553,26 +2554,26 @@  static void init_excp_7450(CPUPPCState *env)
 static void init_excp_970(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
-    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
-    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
-    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000380, POWERPC_EXCP_DSEG);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000480, POWERPC_EXCP_ISEG);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000980, POWERPC_EXCP_HDECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00001300, POWERPC_EXCP_IABR);
+    ppc_intr_add(env, 0x00001600, POWERPC_EXCP_MAINT);
+    ppc_intr_add(env, 0x00001700, POWERPC_EXCP_VPUA);
+    ppc_intr_add(env, 0x00001800, POWERPC_EXCP_THERM);
     /* Hardware reset vector */
     env->hreset_vector = 0x0000000000000100ULL;
 #endif
@@ -2581,27 +2582,27 @@  static void init_excp_970(CPUPPCState *env)
 static void init_excp_POWER7(CPUPPCState *env)
 {
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
-    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
-    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
-    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
-    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
-    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
-    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
-    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
-    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
-    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
-    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
-    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
-    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
-    env->excp_vectors[POWERPC_EXCP_HDSI]     = 0x00000E00;
-    env->excp_vectors[POWERPC_EXCP_HISI]     = 0x00000E20;
-    env->excp_vectors[POWERPC_EXCP_HV_EMU]   = 0x00000E40;
-    env->excp_vectors[POWERPC_EXCP_HV_MAINT] = 0x00000E60;
-    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
-    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
-    env->excp_vectors[POWERPC_EXCP_VSXU]     = 0x00000F40;
+    ppc_intr_add(env, 0x00000100, POWERPC_EXCP_RESET);
+    ppc_intr_add(env, 0x00000200, POWERPC_EXCP_MCHECK);
+    ppc_intr_add(env, 0x00000300, POWERPC_EXCP_DSI);
+    ppc_intr_add(env, 0x00000380, POWERPC_EXCP_DSEG);
+    ppc_intr_add(env, 0x00000400, POWERPC_EXCP_ISI);
+    ppc_intr_add(env, 0x00000480, POWERPC_EXCP_ISEG);
+    ppc_intr_add(env, 0x00000500, POWERPC_EXCP_EXTERNAL);
+    ppc_intr_add(env, 0x00000600, POWERPC_EXCP_ALIGN);
+    ppc_intr_add(env, 0x00000700, POWERPC_EXCP_PROGRAM);
+    ppc_intr_add(env, 0x00000800, POWERPC_EXCP_FPU);
+    ppc_intr_add(env, 0x00000900, POWERPC_EXCP_DECR);
+    ppc_intr_add(env, 0x00000980, POWERPC_EXCP_HDECR);
+    ppc_intr_add(env, 0x00000C00, POWERPC_EXCP_SYSCALL);
+    ppc_intr_add(env, 0x00000D00, POWERPC_EXCP_TRACE);
+    ppc_intr_add(env, 0x00000E00, POWERPC_EXCP_HDSI);
+    ppc_intr_add(env, 0x00000E20, POWERPC_EXCP_HISI);
+    ppc_intr_add(env, 0x00000E40, POWERPC_EXCP_HV_EMU);
+    ppc_intr_add(env, 0x00000E60, POWERPC_EXCP_HV_MAINT);
+    ppc_intr_add(env, 0x00000F00, POWERPC_EXCP_PERFM);
+    ppc_intr_add(env, 0x00000F20, POWERPC_EXCP_VPU);
+    ppc_intr_add(env, 0x00000F40, POWERPC_EXCP_VSXU);
     /* Hardware reset vector */
     env->hreset_vector = 0x0000000000000100ULL;
 #endif
@@ -2612,10 +2613,10 @@  static void init_excp_POWER8(CPUPPCState *env)
     init_excp_POWER7(env);
 
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_SDOOR]    = 0x00000A00;
-    env->excp_vectors[POWERPC_EXCP_FU]       = 0x00000F60;
-    env->excp_vectors[POWERPC_EXCP_HV_FU]    = 0x00000F80;
-    env->excp_vectors[POWERPC_EXCP_SDOOR_HV] = 0x00000E80;
+    ppc_intr_add(env, 0x00000A00, POWERPC_EXCP_SDOOR);
+    ppc_intr_add(env, 0x00000F60, POWERPC_EXCP_FU);
+    ppc_intr_add(env, 0x00000F80, POWERPC_EXCP_HV_FU);
+    ppc_intr_add(env, 0x00000E80, POWERPC_EXCP_SDOOR_HV);
 #endif
 }
 
@@ -2624,8 +2625,8 @@  static void init_excp_POWER9(CPUPPCState *env)
     init_excp_POWER8(env);
 
 #if !defined(CONFIG_USER_ONLY)
-    env->excp_vectors[POWERPC_EXCP_HVIRT]    = 0x00000EA0;
-    env->excp_vectors[POWERPC_EXCP_SYSCALL_VECTORED] = 0x00017000;
+    ppc_intr_add(env, 0x00000EA0, POWERPC_EXCP_HVIRT);
+    ppc_intr_add(env, 0x00017000, POWERPC_EXCP_SYSCALL_VECTORED);
 #endif
 }
 
@@ -8375,13 +8376,8 @@  static void init_ppc_proc(PowerPCCPU *cpu)
     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
     CPUPPCState *env = &cpu->env;
 #if !defined(CONFIG_USER_ONLY)
-    int i;
 
     env->irq_inputs = NULL;
-    /* Set all exception vectors to an invalid address */
-    for (i = 0; i < POWERPC_EXCP_NB; i++) {
-        env->excp_vectors[i] = (target_ulong)(-1ULL);
-    }
     env->ivor_mask = 0x00000000;
     env->ivpr_mask = 0x00000000;
     /* Default MMU definitions */
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 12bf829c8f..26cbfab923 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -29,14 +29,6 @@ 
 #endif
 
 /* #define DEBUG_OP */
-/* #define DEBUG_SOFTWARE_TLB */
-/* #define DEBUG_EXCEPTIONS */
-
-#ifdef DEBUG_EXCEPTIONS
-#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
-#else
-#  define LOG_EXCP(...) do { } while (0)
-#endif
 
 /*****************************************************************************/
 /* Exception processing */
@@ -58,32 +50,6 @@  static void ppc_hw_interrupt(CPUPPCState *env)
     env->error_code = 0;
 }
 #else /* defined(CONFIG_USER_ONLY) */
-static inline void dump_syscall(CPUPPCState *env)
-{
-    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
-                  " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
-                  " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
-                  " nip=" TARGET_FMT_lx "\n",
-                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
-                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
-                  ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
-                  ppc_dump_gpr(env, 8), env->nip);
-}
-
-static inline void dump_hcall(CPUPPCState *env)
-{
-    qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
-                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
-                  " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
-                  " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
-                  " nip=" TARGET_FMT_lx "\n",
-                  ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
-                  ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
-                  ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
-                  ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
-                  ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
-                  env->nip);
-}
 
 static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
                                 target_ulong *msr)
@@ -311,17 +277,6 @@  static inline void powerpc_set_excp_state(PowerPCCPU *cpu, target_ulong new_nip,
     check_tlb_flush(env, false);
 }
 
-struct ppc_intr_args {
-    target_ulong nip;
-    target_ulong msr;
-    target_ulong new_nip;
-    target_ulong new_msr;
-    int sprn_srr0;
-    int sprn_srr1;
-    int sprn_asrr0;
-    int sprn_asrr1;
-};
-
 /*
  * Note that this function should be greatly optimized when called
  * with a constant excp, from ppc_hw_interrupt
@@ -331,11 +286,21 @@  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     struct ppc_intr_args regs;
-    int lev = -1;
+    PPCInterrupt *intr;
+    bool ignore = false;
 
     qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
                   " => %08x (%02x)\n", env->nip, excp, env->error_code);
 
+    if (excp == POWERPC_EXCP_NONE) {
+        return;
+    }
+
+    if (excp < POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
+        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+        return;
+    }
+
     /* new srr1 value excluding must-be-zero bits */
     if (excp_model == POWERPC_EXCP_BOOKE) {
         regs.msr = env->msr;
@@ -380,469 +345,21 @@  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
         excp = POWERPC_EXCP_PROGRAM;
     }
 
-    switch (excp) {
-    case POWERPC_EXCP_NONE:
-        /* Should never happen */
-        return;
-    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
-        switch (excp_model) {
-        case POWERPC_EXCP_40x:
-            regs.sprn_srr0 = SPR_40x_SRR2;
-            regs.sprn_srr1 = SPR_40x_SRR3;
-            break;
-        case POWERPC_EXCP_BOOKE:
-            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-            break;
-        case POWERPC_EXCP_G2:
-            break;
-        default:
-            goto excp_invalid;
-        }
-        break;
-    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
-        if (msr_me == 0) {
-            /*
-             * Machine check exception is not enabled.  Enter
-             * checkstop state.
-             */
-            fprintf(stderr, "Machine check while not allowed. "
-                    "Entering checkstop state\n");
-            if (qemu_log_separate()) {
-                qemu_log("Machine check while not allowed. "
-                        "Entering checkstop state\n");
-            }
-            cs->halted = 1;
-            cpu_interrupt_exittb(cs);
-        }
-        if (env->msr_mask & MSR_HVB) {
-            /*
-             * ISA specifies HV, but can be delivered to guest with HV
-             * clear (e.g., see FWNMI in PAPR).
-             */
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        }
-
-        /* machine check exceptions don't have ME set */
-        regs.new_msr &= ~((target_ulong)1 << MSR_ME);
-
-        /* XXX: should also have something loaded in DAR / DSISR */
-        switch (excp_model) {
-        case POWERPC_EXCP_40x:
-            regs.sprn_srr0 = SPR_40x_SRR2;
-            regs.sprn_srr1 = SPR_40x_SRR3;
-            break;
-        case POWERPC_EXCP_BOOKE:
-            /* FIXME: choose one or the other based on CPU type */
-            regs.sprn_srr0 = SPR_BOOKE_MCSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_MCSRR1;
-            regs.sprn_asrr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_asrr1 = SPR_BOOKE_CSRR1;
-            break;
-        default:
-            break;
-        }
-        break;
-    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
-        LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
-                 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-        break;
-    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
-        LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
-                 "\n", regs.msr, regs.nip);
-        regs.msr |= env->error_code;
-        break;
-    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
-    {
-        bool lpes0;
-
-        cs = CPU(cpu);
-
-        /*
-         * Exception targeting modifiers
-         *
-         * LPES0 is supported on POWER7/8/9
-         * LPES1 is not supported (old iSeries mode)
-         *
-         * On anything else, we behave as if LPES0 is 1
-         * (externals don't alter MSR:HV)
-         */
-#if defined(TARGET_PPC64)
-        if (excp_model == POWERPC_EXCP_POWER7 ||
-            excp_model == POWERPC_EXCP_POWER8 ||
-            excp_model == POWERPC_EXCP_POWER9 ||
-            excp_model == POWERPC_EXCP_POWER10) {
-            lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
-        } else
-#endif /* defined(TARGET_PPC64) */
-        {
-            lpes0 = true;
-        }
-
-        if (!lpes0) {
-            regs.new_msr |= (target_ulong)MSR_HVB;
-            regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-            regs.sprn_srr0 = SPR_HSRR0;
-            regs.sprn_srr1 = SPR_HSRR1;
-        }
-        if (env->mpic_proxy) {
-            /* IACK the IRQ on delivery */
-            env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
-        }
-        break;
+    intr = &env->entry_points[excp];
+    if (!intr->setup_regs) {
+        cpu_abort(cs, "Raised an exception without defined vector %d\n",
+                  excp);
     }
-    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
-        /* Get rS/rD and rA from faulting opcode */
-        /*
-         * Note: the opcode fields will not be set properly for a
-         * direct store load/store, but nobody cares as nobody
-         * actually uses direct store segments.
-         */
-        env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
-        break;
-    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
-        switch (env->error_code & ~0xF) {
-        case POWERPC_EXCP_FP:
-            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
-                LOG_EXCP("Ignore floating point exception\n");
-                cs->exception_index = POWERPC_EXCP_NONE;
-                env->error_code = 0;
-                return;
-            }
 
-            /*
-             * FP exceptions always have NIP pointing to the faulting
-             * instruction, so always use store_next and claim we are
-             * precise in the MSR.
-             */
-            regs.msr |= 0x00100000;
-            env->spr[SPR_BOOKE_ESR] = ESR_FP;
-            break;
-        case POWERPC_EXCP_INVAL:
-            LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", regs.nip);
-            regs.msr |= 0x00080000;
-            env->spr[SPR_BOOKE_ESR] = ESR_PIL;
-            break;
-        case POWERPC_EXCP_PRIV:
-            regs.msr |= 0x00040000;
-            env->spr[SPR_BOOKE_ESR] = ESR_PPR;
-            break;
-        case POWERPC_EXCP_TRAP:
-            regs.msr |= 0x00020000;
-            env->spr[SPR_BOOKE_ESR] = ESR_PTR;
-            break;
-        default:
-            /* Should never occur */
-            cpu_abort(cs, "Invalid program exception %d. Aborting\n",
-                      env->error_code);
-            break;
-        }
-        break;
-    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
-        lev = env->error_code;
-
-        if ((lev == 1) && cpu->vhyp) {
-            dump_hcall(env);
-        } else {
-            dump_syscall(env);
-        }
+    regs.new_nip = intr->addr | env->excp_prefix;
+    intr->setup_regs(cpu, intr, excp_model, &regs, &ignore);
 
+    if (ignore) {
         /*
-         * We need to correct the NIP which in this case is supposed
-         * to point to the next instruction. We also set env->nip here
-         * because the modification needs to be accessible by the
-         * virtual hypervisor code below.
+         * The interrupt was ignored or delivered by other means
+         * (e.g. vhyp).
          */
-        regs.nip += 4;
-        env->nip = regs.nip;
-
-        /* "PAPR mode" built-in hypercall emulation */
-        if ((lev == 1) && cpu->vhyp) {
-            PPCVirtualHypervisorClass *vhc =
-                PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
-            vhc->hypercall(cpu->vhyp, cpu);
-            return;
-        }
-
-        if (lev == 1) {
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        }
-        break;
-    case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception                     */
-        lev = env->error_code;
-        dump_syscall(env);
-        regs.nip += 4;
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        break;
-    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
-    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
-    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
-        break;
-    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
-        /* FIT on 4xx */
-        LOG_EXCP("FIT exception\n");
-        break;
-    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
-        LOG_EXCP("WDT exception\n");
-        switch (excp_model) {
-        case POWERPC_EXCP_BOOKE:
-            regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-            break;
-        default:
-            break;
-        }
-        break;
-    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
-    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
-        break;
-    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
-        if (env->flags & POWERPC_FLAG_DE) {
-            /* FIXME: choose one or the other based on CPU type */
-            regs.sprn_srr0 = SPR_BOOKE_DSRR0;
-            regs.sprn_srr1 = SPR_BOOKE_DSRR1;
-            regs.sprn_asrr0 = SPR_BOOKE_CSRR0;
-            regs.sprn_asrr1 = SPR_BOOKE_CSRR1;
-            /* DBSR already modified by caller */
-        } else {
-            cpu_abort(cs, "Debug exception triggered on unsupported model\n");
-        }
-        break;
-    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
-        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        break;
-    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs, "Embedded floating point data exception "
-                  "is not implemented yet !\n");
-        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        break;
-    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
-        /* XXX: TODO */
-        cpu_abort(cs, "Embedded floating point round exception "
-                  "is not implemented yet !\n");
-        env->spr[SPR_BOOKE_ESR] = ESR_SPV;
-        break;
-    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "Performance counter exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
-        break;
-    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
-        regs.sprn_srr0 = SPR_BOOKE_CSRR0;
-        regs.sprn_srr1 = SPR_BOOKE_CSRR1;
-        break;
-    case POWERPC_EXCP_RESET:     /* System reset exception                   */
-        /* A power-saving exception sets ME, otherwise it is unchanged */
-        if (msr_pow) {
-            /* indicate that we resumed from power save mode */
-            regs.msr |= 0x10000;
-            regs.new_msr |= ((target_ulong)1 << MSR_ME);
-        }
-        if (env->msr_mask & MSR_HVB) {
-            /*
-             * ISA specifies HV, but can be delivered to guest with HV
-             * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
-             */
-            regs.new_msr |= (target_ulong)MSR_HVB;
-        } else {
-            if (msr_pow) {
-                cpu_abort(cs, "Trying to deliver power-saving system reset "
-                          "exception %d with no HV support\n", excp);
-            }
-        }
-        break;
-    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
-    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
-    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
-        break;
-    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
-        regs.msr |= env->error_code;
-        /* fall through */
-    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
-    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
-    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
-    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
-    case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
-    case POWERPC_EXCP_HV_EMU:
-    case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
-        regs.sprn_srr0 = SPR_HSRR0;
-        regs.sprn_srr1 = SPR_HSRR1;
-        regs.new_msr |= (target_ulong)MSR_HVB;
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-        break;
-    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
-    case POWERPC_EXCP_VSXU:       /* VSX unavailable exception               */
-    case POWERPC_EXCP_FU:         /* Facility unavailable exception          */
-#ifdef TARGET_PPC64
-        env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
-#endif
-        break;
-    case POWERPC_EXCP_HV_FU:     /* Hypervisor Facility Unavailable Exception */
-#ifdef TARGET_PPC64
-        env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
-        regs.sprn_srr0 = SPR_HSRR0;
-        regs.sprn_srr1 = SPR_HSRR1;
-        regs.new_msr |= (target_ulong)MSR_HVB;
-        regs.new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-#endif
-        break;
-    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
-        LOG_EXCP("PIT exception\n");
-        break;
-    case POWERPC_EXCP_IO:        /* IO error exception                       */
-        /* XXX: TODO */
-        cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
-        /* XXX: TODO */
-        cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
-        /* XXX: TODO */
-        cpu_abort(cs, "602 emulation trap exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
-    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
-    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
-        switch (excp_model) {
-        case POWERPC_EXCP_602:
-        case POWERPC_EXCP_603:
-        case POWERPC_EXCP_603E:
-        case POWERPC_EXCP_G2:
-            /* Swap temporary saved registers with GPRs */
-            if (!(regs.new_msr & ((target_ulong)1 << MSR_TGPR))) {
-                regs.new_msr |= (target_ulong)1 << MSR_TGPR;
-                hreg_swap_gpr_tgpr(env);
-            }
-            /* fall through */
-        case POWERPC_EXCP_7x5:
-#if defined(DEBUG_SOFTWARE_TLB)
-            if (qemu_log_enabled()) {
-                const char *es;
-                target_ulong *miss, *cmp;
-                int en;
-
-                if (excp == POWERPC_EXCP_IFTLB) {
-                    es = "I";
-                    en = 'I';
-                    miss = &env->spr[SPR_IMISS];
-                    cmp = &env->spr[SPR_ICMP];
-                } else {
-                    if (excp == POWERPC_EXCP_DLTLB) {
-                        es = "DL";
-                    } else {
-                        es = "DS";
-                    }
-                    en = 'D';
-                    miss = &env->spr[SPR_DMISS];
-                    cmp = &env->spr[SPR_DCMP];
-                }
-                qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
-                         TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
-                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
-                         env->spr[SPR_HASH1], env->spr[SPR_HASH2],
-                         env->error_code);
-            }
-#endif
-            regs.msr |= env->crf[0] << 28;
-            regs.msr |= env->error_code; /* key, D/I, S/L bits */
-            /* Set way using a LRU mechanism */
-            regs.msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
-            break;
-        case POWERPC_EXCP_74xx:
-#if defined(DEBUG_SOFTWARE_TLB)
-            if (qemu_log_enabled()) {
-                const char *es;
-                target_ulong *miss, *cmp;
-                int en;
-
-                if (excp == POWERPC_EXCP_IFTLB) {
-                    es = "I";
-                    en = 'I';
-                    miss = &env->spr[SPR_TLBMISS];
-                    cmp = &env->spr[SPR_PTEHI];
-                } else {
-                    if (excp == POWERPC_EXCP_DLTLB) {
-                        es = "DL";
-                    } else {
-                        es = "DS";
-                    }
-                    en = 'D';
-                    miss = &env->spr[SPR_TLBMISS];
-                    cmp = &env->spr[SPR_PTEHI];
-                }
-                qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
-                         TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
-                         env->error_code);
-            }
-#endif
-            regs.msr |= env->error_code; /* key bit */
-            break;
-        default:
-            cpu_abort(cs, "Invalid TLB miss exception\n");
-            break;
-        }
-        break;
-    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
-        /* XXX: TODO */
-        cpu_abort(cs, "Floating point assist exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_DABR:      /* Data address breakpoint                  */
-        /* XXX: TODO */
-        cpu_abort(cs, "DABR exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
-        /* XXX: TODO */
-        cpu_abort(cs, "IABR exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_SMI:       /* System management interrupt              */
-        /* XXX: TODO */
-        cpu_abort(cs, "SMI exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
-        /* XXX: TODO */
-        cpu_abort(cs, "Thermal management exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "Performance counter exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
-        /* XXX: TODO */
-        cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "970 soft-patch exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
-        /* XXX: TODO */
-        cpu_abort(cs,
-                  "970 maintenance exception is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_MEXTBR:    /* Maskable external breakpoint             */
-        /* XXX: TODO */
-        cpu_abort(cs, "Maskable external exception "
-                  "is not implemented yet !\n");
-        break;
-    case POWERPC_EXCP_NMEXTBR:   /* Non maskable external breakpoint         */
-        /* XXX: TODO */
-        cpu_abort(cs, "Non maskable external exception "
-                  "is not implemented yet !\n");
-        break;
-    default:
-    excp_invalid:
-        cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
-        break;
+        return;
     }
 
     /* Sanity check */
@@ -892,14 +409,6 @@  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 #endif
 
-    regs.new_nip = env->excp_vectors[excp];
-    if (regs.new_nip == (target_ulong)-1ULL) {
-        cpu_abort(cs, "Raised an exception without defined vector %d\n",
-                  excp);
-    }
-
-    regs.new_nip |= env->excp_prefix;
-
     /* If any alternate SRR register are defined, duplicate saved values */
     if (regs.sprn_asrr0 != -1) {
         env->spr[regs.sprn_asrr0] = regs.nip;
@@ -925,24 +434,16 @@  static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
     }
 #endif
 
-    if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
+    if (intr->id != POWERPC_EXCP_SYSCALL_VECTORED) {
         /* Save PC */
         env->spr[regs.sprn_srr0] = regs.nip;
 
         /* Save MSR */
         env->spr[regs.sprn_srr1] = regs.msr;
-
-#if defined(TARGET_PPC64)
-    } else {
-        regs.new_nip += lev * 0x20;
-
-        env->lr = regs.nip;
-        env->ctr = regs.msr;
-#endif
     }
 
     /* This can update regs.new_msr and regs.new_nip if AIL applies */
-    ppc_excp_apply_ail(cpu, excp_model, excp, regs.msr, &regs.new_msr,
+    ppc_excp_apply_ail(cpu, excp_model, intr->id, regs.msr, &regs.new_msr,
                        &regs.new_nip);
 
     powerpc_set_excp_state(cpu, regs.new_nip, regs.new_msr);
diff --git a/target/ppc/interrupts.c b/target/ppc/interrupts.c
new file mode 100644
index 0000000000..31faea84c5
--- /dev/null
+++ b/target/ppc/interrupts.c
@@ -0,0 +1,638 @@ 
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "ppc_intr.h"
+
+/* for hreg_swap_gpr_tgpr */
+#include "helper_regs.h"
+
+/* #define DEBUG_SOFTWARE_TLB */
+/* #define DEBUG_EXCEPTIONS */
+
+#ifdef DEBUG_EXCEPTIONS
+#  define LOG_EXCP(...) qemu_log(__VA_ARGS__)
+#else
+#  define LOG_EXCP(...) do { } while (0)
+#endif
+
+void __ppc_intr_add(CPUPPCState *env, target_ulong addr, int id,
+                   const char *intr_name)
+{
+    PPCInterrupt *intr = &env->entry_points[id];
+
+    object_initialize(intr, sizeof(*intr), intr_name);
+    intr->addr = addr;
+}
+
+static const TypeInfo ppc_interrupt_info = {
+    .name = TYPE_PPC_INTERRUPT,
+    .parent = TYPE_OBJECT,
+    .abstract = true,
+};
+
+static void ppc_interrupt_register_types(void)
+{
+    type_register_static(&ppc_interrupt_info);
+}
+type_init(ppc_interrupt_register_types);
+
+
+
+static void ppc_intr_def_log(PowerPCCPU *cpu, PPCInterrupt *intr,
+                             int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    LOG_EXCP("%s interrupt\n", intr->name);
+}
+
+static void ppc_intr_def_not_impl(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+
+    cpu_abort(cs, "%s interrupt not implemented yet.\n", intr->name);
+}
+
+static void ppc_intr_def_no_op(PowerPCCPU *cpu, PPCInterrupt *intr,
+                               int excp_model, ppc_intr_args *regs,
+                               bool *ignore)
+{
+}
+
+/* Default implementation for interrupts that set the MSR_HV bit */
+static void ppc_intr_def_hv(PowerPCCPU *cpu, PPCInterrupt *intr, int excp_model,
+                            ppc_intr_args *regs, bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    regs->sprn_srr0 = SPR_HSRR0;
+    regs->sprn_srr1 = SPR_HSRR1;
+    regs->new_msr |= (target_ulong)MSR_HVB;
+    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+}
+
+/* Default implementation for Facility Unavailable interrupts */
+static void ppc_intr_def_fac_unavail_64(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                        int excp_model, ppc_intr_args *regs,
+                                        bool *ignore)
+{
+#ifdef TARGET_PPC64
+    CPUPPCState *env = &cpu->env;
+    env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
+#endif
+}
+
+static void ppc_debug_software_tlb(CPUPPCState *env, int excp, int excp_model,
+                                   int imiss_sprn, int icmp_sprn,
+                                   int dmiss_sprn, int dcmp_sprn)
+{
+#if defined(DEBUG_SOFTWARE_TLB)
+    if (qemu_log_enabled()) {
+        const char *es;
+        target_ulong *miss, *cmp;
+        int en;
+
+        if (excp == POWERPC_EXCP_IFTLB) {
+            es = "I";
+            en = 'I';
+            miss = &env->spr[imiss_sprn];
+            cmp = &env->spr[icmp_sprn];
+        } else {
+            if (excp == POWERPC_EXCP_DLTLB) {
+                es = "DL";
+            } else {
+                es = "DS";
+            }
+            en = 'D';
+            miss = &env->spr[dmiss_sprn];
+            cmp = &env->spr[dcmp_srpn];
+        }
+
+        if (excp_model == POWERPC_EXCP_74xx) {
+            qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+                     TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+                     env->error_code);
+        } else {
+            qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
+                     TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
+                     TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
+                     env->spr[SPR_HASH1], env->spr[SPR_HASH2],
+                     env->error_code);
+        }
+    }
+#endif
+}
+
+static void ppc_intr_def_tlb_miss(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    switch (excp_model) {
+    case POWERPC_EXCP_602:
+    case POWERPC_EXCP_603:
+    case POWERPC_EXCP_603E:
+    case POWERPC_EXCP_G2:
+        /* Swap temporary saved registers with GPRs */
+        if (!(regs->new_msr & ((target_ulong)1 << MSR_TGPR))) {
+            regs->new_msr |= (target_ulong)1 << MSR_TGPR;
+            hreg_swap_gpr_tgpr(env);
+        }
+
+        ppc_debug_software_tlb(env, intr->id, excp_model,
+                               SPR_IMISS, SPR_ICMP,
+                               SPR_DMISS, SPR_DCMP);
+
+        /* fall through */
+    case POWERPC_EXCP_7x5:
+        regs->msr |= env->crf[0] << 28;
+        regs->msr |= env->error_code; /* key, D/I, S/L bits */
+
+        /* Set way using a LRU mechanism */
+        regs->msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+
+        break;
+    case POWERPC_EXCP_74xx:
+        ppc_debug_software_tlb(env, intr->id, excp_model,
+                               SPR_TLBMISS, SPR_PTEHI,
+                               SPR_TLBMISS, SPR_PTEHI);
+
+        regs->msr |= env->error_code; /* key bit */
+        break;
+    default:
+        cpu_abort(cs, "Invalid instruction TLB miss exception\n");
+        break;
+    }
+}
+
+static void ppc_intr_critical(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+
+    switch (excp_model) {
+    case POWERPC_EXCP_40x:
+        regs->sprn_srr0 = SPR_40x_SRR2;
+        regs->sprn_srr1 = SPR_40x_SRR3;
+        break;
+    case POWERPC_EXCP_BOOKE:
+        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+        break;
+    case POWERPC_EXCP_G2:
+        break;
+    default:
+        cpu_abort(cs, "Invalid Critical interrupt for model %d. Aborting\n",
+                  excp_model);
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_CRITICAL, critical, "Critical input");
+
+static void ppc_intr_machine_check(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                   int excp_model, ppc_intr_args *regs,
+                                   bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    if (msr_me == 0) {
+        /*
+         * Machine check exception is not enabled.  Enter
+         * checkstop state.
+         */
+        fprintf(stderr, "Machine check while not allowed. "
+                "Entering checkstop state\n");
+        if (qemu_log_separate()) {
+            qemu_log("Machine check while not allowed. "
+                     "Entering checkstop state\n");
+        }
+        cs->halted = 1;
+        cpu_interrupt_exittb(cs);
+    }
+    if (env->msr_mask & MSR_HVB) {
+        /*
+         * ISA specifies HV, but can be delivered to guest with HV
+         * clear (e.g., see FWNMI in PAPR).
+         */
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    }
+
+    /* machine check exceptions don't have ME set */
+    regs->new_msr &= ~((target_ulong)1 << MSR_ME);
+
+    /* XXX: should also have something loaded in DAR / DSISR */
+    switch (excp_model) {
+    case POWERPC_EXCP_40x:
+        regs->sprn_srr0 = SPR_40x_SRR2;
+        regs->sprn_srr1 = SPR_40x_SRR3;
+        break;
+    case POWERPC_EXCP_BOOKE:
+        /* FIXME: choose one or the other based on CPU type */
+        regs->sprn_srr0 = SPR_BOOKE_MCSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_MCSRR1;
+        regs->sprn_asrr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_asrr1 = SPR_BOOKE_CSRR1;
+        break;
+    default:
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_MCHECK, machine_check, "Machine check");
+
+static void ppc_intr_data_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
+             "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_DSI, data_storage, "Data storage");
+
+static void ppc_intr_insn_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
+             "\n", regs->msr, regs->nip);
+    regs->msr |= env->error_code;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_ISI, insn_storage, "Instruction storage");
+
+static void ppc_intr_external(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+    bool lpes0;
+
+    /*
+     * Exception targeting modifiers
+     *
+     * LPES0 is supported on POWER7/8/9
+     * LPES1 is not supported (old iSeries mode)
+     *
+     * On anything else, we behave as if LPES0 is 1
+     * (externals don't alter MSR:HV)
+     */
+#if defined(TARGET_PPC64)
+    if (excp_model == POWERPC_EXCP_POWER7 ||
+        excp_model == POWERPC_EXCP_POWER8 ||
+        excp_model == POWERPC_EXCP_POWER9 ||
+        excp_model == POWERPC_EXCP_POWER10) {
+        lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
+    } else
+#endif /* defined(TARGET_PPC64) */
+    {
+        lpes0 = true;
+    }
+
+    if (!lpes0) {
+        regs->new_msr |= (target_ulong)MSR_HVB;
+        regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+        regs->sprn_srr0 = SPR_HSRR0;
+        regs->sprn_srr1 = SPR_HSRR1;
+    }
+    if (env->mpic_proxy) {
+        /* IACK the IRQ on delivery */
+        env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_EXTERNAL, external, "External");
+
+static void ppc_intr_alignment(PowerPCCPU *cpu, PPCInterrupt *intr,
+                               int excp_model, ppc_intr_args *regs,
+                               bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    /* Get rS/rD and rA from faulting opcode */
+    /*
+     * Note: the opcode fields will not be set properly for a
+     * direct store load/store, but nobody cares as nobody
+     * actually uses direct store segments.
+     */
+    env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_ALIGN, alignment, "Alignment");
+
+static void ppc_intr_program(PowerPCCPU *cpu, PPCInterrupt *intr,
+                             int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    switch (env->error_code & ~0xF) {
+    case POWERPC_EXCP_FP:
+        if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+            LOG_EXCP("Ignore floating point exception\n");
+            cs->exception_index = POWERPC_EXCP_NONE;
+            env->error_code = 0;
+
+            *ignore = true;
+            return;
+        }
+
+        /*
+         * FP exceptions always have NIP pointing to the faulting
+         * instruction, so always use store_next and claim we are
+         * precise in the MSR.
+         */
+        regs->msr |= 0x00100000;
+        env->spr[SPR_BOOKE_ESR] = ESR_FP;
+        break;
+    case POWERPC_EXCP_INVAL:
+        LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", regs->nip);
+        regs->msr |= 0x00080000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+        break;
+    case POWERPC_EXCP_PRIV:
+        regs->msr |= 0x00040000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PPR;
+        break;
+    case POWERPC_EXCP_TRAP:
+        regs->msr |= 0x00020000;
+        env->spr[SPR_BOOKE_ESR] = ESR_PTR;
+        break;
+    default:
+        /* Should never occur */
+        cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+                  env->error_code);
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_PROGRAM, program, "Program");
+
+
+static inline void dump_syscall(CPUPPCState *env)
+{
+    qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64
+                  " r3=%016" PRIx64 " r4=%016" PRIx64 " r5=%016" PRIx64
+                  " r6=%016" PRIx64 " r7=%016" PRIx64 " r8=%016" PRIx64
+                  " nip=" TARGET_FMT_lx "\n",
+                  ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
+                  ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
+                  ppc_dump_gpr(env, 6), ppc_dump_gpr(env, 7),
+                  ppc_dump_gpr(env, 8), env->nip);
+}
+
+static inline void dump_hcall(CPUPPCState *env)
+{
+    qemu_log_mask(CPU_LOG_INT, "hypercall r3=%016" PRIx64
+                  " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
+                  " r7=%016" PRIx64 " r8=%016" PRIx64 " r9=%016" PRIx64
+                  " r10=%016" PRIx64 " r11=%016" PRIx64 " r12=%016" PRIx64
+                  " nip=" TARGET_FMT_lx "\n",
+                  ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
+                  ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6),
+                  ppc_dump_gpr(env, 7), ppc_dump_gpr(env, 8),
+                  ppc_dump_gpr(env, 9), ppc_dump_gpr(env, 10),
+                  ppc_dump_gpr(env, 11), ppc_dump_gpr(env, 12),
+                  env->nip);
+}
+
+
+static void ppc_intr_system_call(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                 int excp_model, ppc_intr_args *regs,
+                                 bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int lev;
+
+    lev = env->error_code;
+
+    if ((lev == 1) && cpu->vhyp) {
+        dump_hcall(env);
+    } else {
+        dump_syscall(env);
+    }
+
+    /*
+     * We need to correct the NIP which in this case is supposed
+     * to point to the next instruction. We also set env->nip here
+     * because the modification needs to be accessible by the
+     * virtual hypervisor code below.
+     */
+    regs->nip += 4;
+    env->nip = regs->nip;
+
+    /* "PAPR mode" built-in hypercall emulation */
+    if ((lev == 1) && cpu->vhyp) {
+        PPCVirtualHypervisorClass *vhc =
+            PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+        vhc->hypercall(cpu->vhyp, cpu);
+
+        *ignore = true;
+        return;
+    }
+
+    if (lev == 1) {
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_SYSCALL, system_call, "System call");
+
+static void ppc_intr_system_call_vectored(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                          int excp_model, ppc_intr_args *regs,
+                                          bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+    int lev;
+
+    lev = env->error_code;
+    dump_syscall(env);
+
+    regs->nip += 4;
+    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
+    regs->new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
+    regs->new_nip += lev * 0x20;
+
+    env->lr = regs->nip;
+    env->ctr = regs->msr;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_SYSCALL_VECTORED, system_call_vectored,
+                     "System call vectored");
+
+static void ppc_intr_watchdog(PowerPCCPU *cpu, PPCInterrupt *intr,
+                              int excp_model, ppc_intr_args *regs, bool *ignore)
+{
+    LOG_EXCP("WDT exception\n");
+    switch (excp_model) {
+    case POWERPC_EXCP_BOOKE:
+        regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+        break;
+    default:
+        break;
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_WDT, watchdog, "Watchdog timer");
+
+static void ppc_intr_debug(PowerPCCPU *cpu, PPCInterrupt *intr, int excp_model,
+                           ppc_intr_args *regs, bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    if (env->flags & POWERPC_FLAG_DE) {
+        /* FIXME: choose one or the other based on CPU type */
+        regs->sprn_srr0 = SPR_BOOKE_DSRR0;
+        regs->sprn_srr1 = SPR_BOOKE_DSRR1;
+        regs->sprn_asrr0 = SPR_BOOKE_CSRR0;
+        regs->sprn_asrr1 = SPR_BOOKE_CSRR1;
+        /* DBSR already modified by caller */
+    } else {
+        cpu_abort(cs, "Debug exception triggered on unsupported model\n");
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_DEBUG, debug, "Debug");
+
+static void ppc_intr_spe_unavailable(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                     int excp_model, ppc_intr_args *regs,
+                                     bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_SPEU, spe_unavailable,
+                     "SPE/embedded floating-point unavailable");
+
+static void ppc_intr_embedded_fp_data(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                      int excp_model, ppc_intr_args *regs,
+                                      bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    ppc_intr_def_not_impl(cpu, intr, excp_model, regs, ignore);
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_EFPDI, embedded_fp_data,
+                     "Embedded floating-point data");
+
+static void ppc_intr_embedded_fp_round(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                       int excp_model, ppc_intr_args *regs,
+                                       bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    ppc_intr_def_not_impl(cpu, intr, excp_model, regs, ignore);
+    env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_EFPRI, embedded_fp_round,
+                     "Embedded floating-point round");
+
+static void ppc_intr_embedded_doorbell_crit(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                            int excp_model, ppc_intr_args *regs,
+                                            bool *ignore)
+{
+    regs->sprn_srr0 = SPR_BOOKE_CSRR0;
+    regs->sprn_srr1 = SPR_BOOKE_CSRR1;
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_DOORCI, embedded_doorbell_crit,
+                     "Embedded doorbell critical");
+
+static void ppc_intr_system_reset(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                  int excp_model, ppc_intr_args *regs,
+                                  bool *ignore)
+{
+    CPUState *cs = CPU(cpu);
+    CPUPPCState *env = &cpu->env;
+
+    /* A power-saving exception sets ME, otherwise it is unchanged */
+    if (msr_pow) {
+        /* indicate that we resumed from power save mode */
+        regs->msr |= 0x10000;
+        regs->new_msr |= ((target_ulong)1 << MSR_ME);
+    }
+    if (env->msr_mask & MSR_HVB) {
+        /*
+         * ISA specifies HV, but can be delivered to guest with HV
+         * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
+         */
+        regs->new_msr |= (target_ulong)MSR_HVB;
+    } else {
+        if (msr_pow) {
+            cpu_abort(cs, "Trying to deliver power-saving system reset "
+                      "exception with no HV support\n");
+        }
+    }
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_RESET, system_reset, "System reset");
+
+static void ppc_intr_hv_insn_storage(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                     int excp_model, ppc_intr_args *regs,
+                                     bool *ignore)
+{
+    CPUPPCState *env = &cpu->env;
+
+    regs->msr |= env->error_code;
+    ppc_intr_def_hv(cpu, intr, excp_model, regs, ignore);
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_HISI, hv_insn_storage,
+                     "Hypervisor instruction storage");
+
+static void ppc_intr_hv_facility_unavail(PowerPCCPU *cpu, PPCInterrupt *intr,
+                                         int excp_model, ppc_intr_args *regs,
+                                         bool *ignore)
+{
+#ifdef TARGET_PPC64
+    ppc_intr_def_fac_unavail_64(cpu, intr, excp_model, regs, ignore);
+    ppc_intr_def_hv(cpu, intr, excp_model, regs, ignore);
+#endif
+}
+PPC_DEFINE_INTR(POWERPC_EXCP_HV_FU, hv_facility_unavail,
+                "Hypervisor facility unavailable");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_HDECR,    def_hv, "Hypervisor decrementer");
+PPC_DEFINE_INTR(POWERPC_EXCP_HDSI,     def_hv, "Hypervisor data storage");
+PPC_DEFINE_INTR(POWERPC_EXCP_HDSEG,    def_hv, "Hypervisor data segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_HISEG,    def_hv, "Hypervisor insn segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_SDOOR_HV, def_hv, "Hypervisor doorbell");
+PPC_DEFINE_INTR(POWERPC_EXCP_HV_EMU,   def_hv, "Hypervisor emulation assist");
+PPC_DEFINE_INTR(POWERPC_EXCP_HVIRT,    def_hv, "Hypervisor virtualization");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_VPU,  def_fac_unavail_64, "Vector unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_VSXU, def_fac_unavail_64, "VSX unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_FU,   def_fac_unavail_64, "Facility unavailable");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_IFTLB, def_tlb_miss, "Insn fetch TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_DLTLB, def_tlb_miss, "Data load TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_DSTLB, def_tlb_miss, "Data store TLB error");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_FIT, def_log, "Fixed-interval timer");
+PPC_DEFINE_INTR(POWERPC_EXCP_PIT, def_log, "Programmable interval timer");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_FPU,   def_no_op, "Floating-point unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_APU,   def_no_op, "Aux. processor unavailable");
+PPC_DEFINE_INTR(POWERPC_EXCP_DECR,  def_no_op, "Decrementer");
+PPC_DEFINE_INTR(POWERPC_EXCP_DTLB,  def_no_op, "Data TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_ITLB,  def_no_op, "Instruction TLB error");
+PPC_DEFINE_INTR(POWERPC_EXCP_DOORI, def_no_op, "Embedded doorbell");
+PPC_DEFINE_INTR(POWERPC_EXCP_DSEG,  def_no_op, "Data segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_ISEG,  def_no_op, "Instruction segment");
+PPC_DEFINE_INTR(POWERPC_EXCP_TRACE, def_no_op, "Trace");
+
+PPC_DEFINE_INTR(POWERPC_EXCP_EPERFM,  def_not_impl, "Embedded perf. monitor");
+PPC_DEFINE_INTR(POWERPC_EXCP_IO,      def_not_impl, "IO error");
+PPC_DEFINE_INTR(POWERPC_EXCP_RUNM,    def_not_impl, "Run mode");
+PPC_DEFINE_INTR(POWERPC_EXCP_EMUL,    def_not_impl, "Emulation trap");
+PPC_DEFINE_INTR(POWERPC_EXCP_FPA,     def_not_impl, "Floating-point assist");
+PPC_DEFINE_INTR(POWERPC_EXCP_DABR,    def_not_impl, "Data address breakpoint");
+PPC_DEFINE_INTR(POWERPC_EXCP_IABR,    def_not_impl, "Insn address breakpoint");
+PPC_DEFINE_INTR(POWERPC_EXCP_SMI,     def_not_impl, "System management");
+PPC_DEFINE_INTR(POWERPC_EXCP_THERM,   def_not_impl, "Thermal management");
+PPC_DEFINE_INTR(POWERPC_EXCP_PERFM,   def_not_impl, "Performance counter");
+PPC_DEFINE_INTR(POWERPC_EXCP_VPUA,    def_not_impl, "Vector assist");
+PPC_DEFINE_INTR(POWERPC_EXCP_SOFTP,   def_not_impl, "Soft patch");
+PPC_DEFINE_INTR(POWERPC_EXCP_MAINT,   def_not_impl, "Maintenance");
+PPC_DEFINE_INTR(POWERPC_EXCP_MEXTBR,  def_not_impl, "Maskable external");
+PPC_DEFINE_INTR(POWERPC_EXCP_NMEXTBR, def_not_impl, "Non-maskable external");
+
+/* These are used by P7 and P8 but were never implemented */
+PPC_DEFINE_INTR(POWERPC_EXCP_SDOOR, def_not_impl, "Server doorbell");
+PPC_DEFINE_INTR(POWERPC_EXCP_HV_MAINT, def_not_impl, "Hypervisor maintenance");
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index 93972df58e..3927359c7b 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -115,7 +115,7 @@  static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
     qemu_get_be32s(f, &env->pending_interrupts);
     qemu_get_be32s(f, &env->irq_input_state);
     for (i = 0; i < POWERPC_EXCP_NB; i++) {
-        qemu_get_betls(f, &env->excp_vectors[i]);
+        qemu_get_betls(f, &env->entry_points[i].addr);
     }
     qemu_get_betls(f, &env->excp_prefix);
     qemu_get_betls(f, &env->ivor_mask);
diff --git a/target/ppc/meson.build b/target/ppc/meson.build
index a6a53a8d5c..740eac25f7 100644
--- a/target/ppc/meson.build
+++ b/target/ppc/meson.build
@@ -30,6 +30,7 @@  ppc_softmmu_ss.add(files(
   'mmu-hash32.c',
   'mmu_helper.c',
   'monitor.c',
+  'interrupts.c',
 ))
 ppc_softmmu_ss.add(when: 'CONFIG_TCG', if_false: files(
   'tcg-stub.c'
diff --git a/target/ppc/ppc_intr.h b/target/ppc/ppc_intr.h
new file mode 100644
index 0000000000..e588736c6d
--- /dev/null
+++ b/target/ppc/ppc_intr.h
@@ -0,0 +1,55 @@ 
+#ifndef PPC_INTR_H
+#define PPC_INTR_H
+
+#include "qom/object.h"
+#include "cpu-qom.h"
+
+#define TYPE_PPC_INTERRUPT "ppc-interrupt"
+OBJECT_DECLARE_SIMPLE_TYPE(PPCInterrupt, PPC_INTERRUPT)
+
+void __ppc_intr_add(CPUPPCState *env, target_ulong addr, int id,
+                    const char *intr_name);
+
+#define ppc_intr_add(_env, _addr, _id)                  \
+    do {                                                \
+        QEMU_BUILD_BUG_ON(_id <= POWERPC_EXCP_NONE);    \
+        QEMU_BUILD_BUG_ON(_id >= POWERPC_EXCP_NB);      \
+        __ppc_intr_add(_env, _addr, _id, #_id);         \
+    } while (0)                                         \
+
+/*
+ * Registers an interrupt callback as a class. This makes it so that
+ * the interrupt callback implementation is stored on QOM and we can
+ * instantiate only the ones needed for a specific processor later.
+ *
+ * @_id: The interrupt id as in the POWERPC_EXCP_* enum. This will be
+ *   the QOM hash table key for the type.
+ * @_sym: The interrupt name as a valid C identifier. This will be
+ *   used to compose the symbol name for the callback to be invoked
+ *   for this interrupt.
+ * @_name: The interrupt name as a string for display.
+ */
+#define PPC_DEFINE_INTR(_id, _sym, _name)       \
+                                                \
+    static void __##_id##_init(Object *obj)     \
+    {                                           \
+        PPCInterrupt *pi = PPC_INTERRUPT(obj);  \
+                                                \
+        pi->id = _id;                           \
+        pi->name = _name;                       \
+        pi->setup_regs = ppc_intr_##_sym;       \
+    }                                           \
+                                                \
+    static const TypeInfo __##_id##_info = {    \
+        .parent = TYPE_PPC_INTERRUPT,           \
+        .name = #_id,                           \
+        .instance_init = __##_id##_init,        \
+    };                                          \
+                                                \
+    static void __##_id##_register_types(void)  \
+    {                                           \
+        type_register_static(&__##_id##_info);  \
+    }                                           \
+    type_init(__##_id##_register_types);        \
+
+#endif /* PPC_INTR_H */
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e16a2721e2..2c82bda8cc 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -951,7 +951,8 @@  void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
     TCGv t0 = tcg_temp_new();
     tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
     tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
-    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs]));
+    tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, entry_points[sprn_offs]) +
+                  offsetof(PPCInterrupt, addr));
     gen_store_spr(sprn, t0);
     tcg_temp_free(t0);
 }