}
 #endif
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
-                        if (ppc_hw_interrupt(env) == 1) {
-                            /* Some exception was raised */
-                            if (env->pending_interrupts == 0)
-                                env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+                        ppc_hw_interrupt(env);
+                        if (env->pending_interrupts == 0)
+                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
-                            tmp_T0 = 0;
+                        tmp_T0 = 0;
 #else
-                            T0 = 0;
+                        T0 = 0;
 #endif
-                        }
                     }
 #elif defined(TARGET_MIPS)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
 
     uint32_t pcsr; /* CPU sensitivity register */
     IRQ_queue_t raised;
     IRQ_queue_t servicing;
-    CPUState *env;
+    qemu_irq *irqs;
 } IRQ_dst_t;
 
 typedef struct openpic_t {
     PCIDevice pci_dev;
-    SetIRQFunc *set_irq;
     int mem_index;
     /* Global registers */
     uint32_t frep; /* Feature reporting register */
     uint32_t glbc; /* Global configuration register  */
     uint32_t micr; /* MPIC interrupt configuration register */
     uint32_t veni; /* Vendor identification register */
+    uint32_t pint; /* Processor initialization register */
     uint32_t spve; /* Spurious vector register */
     uint32_t tifr; /* Timer frequency reporting register */
     /* Source registers */
        uint32_t mbr;    /* Mailbox register */
     } mailboxes[MAX_MAILBOXES];
 #endif
+    /* IRQ out is used when in bypass mode (not implemented) */
+    qemu_irq irq_out;
 } openpic_t;
 
 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
     priority = IPVP_PRIORITY(src->ipvp);
     if (priority <= dst->pctp) {
        /* Too low priority */
+        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
+                __func__, n_IRQ, n_CPU);
        return;
     }
     if (IRQ_testbit(&dst->raised, n_IRQ)) {
        /* Interrupt miss */
+        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
+                __func__, n_IRQ, n_CPU);
        return;
     }
     set_bit(&src->ipvp, IPVP_ACTIVITY);
     IRQ_setbit(&dst->raised, n_IRQ);
-    if (priority > dst->raised.priority) {
-        IRQ_get_next(opp, &dst->raised);
-        DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env);
-        opp->set_irq(dst->env, OPENPIC_EVT_INT, 1);
+    if (priority < dst->raised.priority) {
+        /* An higher priority IRQ is already raised */
+        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
+                __func__, n_IRQ, dst->raised.next, n_CPU);
+        return;
+    }
+    IRQ_get_next(opp, &dst->raised);
+    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
+        priority < dst->servicing.priority) {
+        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+                __func__, n_IRQ, dst->servicing.next, n_CPU);
+        /* Already servicing a higher priority IRQ */
+        return;
     }
+    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
+    qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
 }
 
 /* update pic state because registers for n_IRQ have changed value */
 
     if (!src->pending) {
         /* no irq pending */
+        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
         return;
     }
     if (test_bit(&src->ipvp, IPVP_MASK)) {
        /* Interrupt source is disabled */
+        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
        return;
     }
     if (IPVP_PRIORITY(src->ipvp) == 0) {
        /* Priority set to zero */
+        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
        return;
     }
     if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
         /* IRQ already active */
+        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
         return;
     }
     if (src->ide == 0x00000000) {
        /* No target */
+        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
        return;
     }
 
-    if (!test_bit(&src->ipvp, IPVP_MODE) ||
-        src->ide == (1 << src->last_cpu)) {
+    if (src->ide == (1 << src->last_cpu)) {
+        /* Only one CPU is allowed to receive this IRQ */
+        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
+    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
         /* Directed delivery mode */
         for (i = 0; i < opp->nb_cpus; i++) {
             if (test_bit(&src->ide, i))
         }
     } else {
         /* Distributed delivery mode */
-        /* XXX: incorrect code */
-        for (i = src->last_cpu; i < src->last_cpu; i++) {
-            if (i == MAX_IRQ)
+        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
+            if (i == opp->nb_cpus)
                 i = 0;
             if (test_bit(&src->ide, i)) {
                 IRQ_local_pipe(opp, i, n_IRQ);
     /* Initialise controller registers */
     opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
     opp->veni = VENI;
+    opp->pint = 0x00000000;
     opp->spve = 0x000000FF;
     opp->tifr = 0x003F7A00;
     /* ? */
        opp->src[i].ide  = 0x00000000;
     }
     /* Initialise IRQ destinations */
-    for (i = 0; i < opp->nb_cpus; i++) {
+    for (i = 0; i < MAX_CPU; i++) {
        opp->dst[i].pctp      = 0x0000000F;
        opp->dst[i].pcsr      = 0x00000000;
        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
 static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
 {
     openpic_t *opp = opaque;
+    IRQ_dst_t *dst;
+    int idx;
 
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
     case 0x80: /* VENI */
        break;
     case 0x90: /* PINT */
-        /* XXX: Should be able to reset any CPU */
-        if (val & 1) {
-            DPRINTF("Reset CPU IRQ\n");
-            //                opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1);
+        for (idx = 0; idx < opp->nb_cpus; idx++) {
+            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
+                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
+                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            }
         }
+        opp->pint = val;
        break;
 #if MAX_IPI > 0
     case 0xA0: /* IPI_IPVP */
     openpic_t *opp = opaque;
     IRQ_src_t *src;
     IRQ_dst_t *dst;
-    int idx, n_IRQ;
+    int idx, s_IRQ, n_IRQ;
 
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
        break;
     case 0xB0: /* PEOI */
         DPRINTF("PEOI\n");
-       n_IRQ = IRQ_get_next(opp, &dst->servicing);
-       IRQ_resetbit(&dst->servicing, n_IRQ);
+       s_IRQ = IRQ_get_next(opp, &dst->servicing);
+       IRQ_resetbit(&dst->servicing, s_IRQ);
        dst->servicing.next = -1;
-       src = &opp->src[n_IRQ];
        /* Set up next servicing IRQ */
-       IRQ_get_next(opp, &dst->servicing);
-       /* Check queued interrupts. */
-       n_IRQ = IRQ_get_next(opp, &dst->raised);
-       if (n_IRQ != -1) {
-           src = &opp->src[n_IRQ];
-           if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
-                DPRINTF("Raise CPU IRQ\n");
-                opp->set_irq(dst->env, OPENPIC_EVT_INT, 1);
-            }
-       }
+       s_IRQ = IRQ_get_next(opp, &dst->servicing);
+        /* Check queued interrupts. */
+        n_IRQ = IRQ_get_next(opp, &dst->raised);
+        src = &opp->src[n_IRQ];
+        if (n_IRQ != -1 &&
+            (s_IRQ == -1 ||
+             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
+            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+                    idx, n_IRQ);
+            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+        }
        break;
     default:
         break;
        retval = idx;
        break;
     case 0xA0: /* PIAC */
+        DPRINTF("Lower OpenPIC INT output\n");
+        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
        n_IRQ = IRQ_get_next(opp, &dst->raised);
         DPRINTF("PIAC: irq=%d\n", n_IRQ);
        if (n_IRQ == -1) {
            /* No more interrupt pending */
-            retval = opp->spve;
+            retval = IPVP_VECTOR(opp->spve);
        } else {
            src = &opp->src[n_IRQ];
            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
 #endif
 }
 
-qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
-                         int *pmem_index, int nb_cpus, CPUState **envp)
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out)
 {
     openpic_t *opp;
     uint8_t *pci_conf;
     } else {
         opp = qemu_mallocz(sizeof(openpic_t));
     }
-    opp->set_irq = set_irq;
     opp->mem_index = cpu_register_io_memory(0, openpic_read,
                                             openpic_write, opp);
     
         opp->src[i].type = IRQ_INTERNAL;
     }
     for (i = 0; i < nb_cpus; i++)
-        opp->dst[i].env = envp[i];
+        opp->dst[i].irqs = irqs[i];
+    opp->irq_out = irq_out;
     openpic_reset(opp);
     if (pmem_index)
         *pmem_index = opp->mem_index;
+
     return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
 }
 
 /*
- * QEMU generic PPC hardware System Emulator
+ * QEMU generic PowerPC hardware System Emulator
  * 
  * Copyright (c) 2003-2007 Jocelyn Mayer
  * 
 #include "vl.h"
 #include "m48t59.h"
 
+//#define PPC_DEBUG_IRQ
+
 extern FILE *logfile;
 extern int loglevel;
 
-/*****************************************************************************/
-/* PowerPC internal fake IRQ controller
- * used to manage multiple sources hardware events
- */
-static void ppc_set_irq (void *opaque, int n_IRQ, int level)
+void ppc_set_irq (CPUState *env, int n_IRQ, int level)
 {
-    CPUState *env;
-
-    env = opaque;
     if (level) {
         env->pending_interrupts |= 1 << n_IRQ;
         cpu_interrupt(env, CPU_INTERRUPT_HARD);
         if (env->pending_interrupts == 0)
             cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
-#if 0
+#if defined(PPC_DEBUG_IRQ)
     printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__,
            env, n_IRQ, level, env->pending_interrupts, env->interrupt_request);
 #endif
 }
 
-void cpu_ppc_irq_init_cpu(CPUState *env)
+/* PowerPC 6xx / 7xx internal IRQ controller */
+static void ppc6xx_set_irq (void *opaque, int pin, int level)
 {
-    qemu_irq *qi;
-    int i;
+    CPUState *env = opaque;
+    int cur_level;
 
-    qi = qemu_allocate_irqs(ppc_set_irq, env, 32);
-    for (i = 0; i < 32; i++) {
-        env->irq[i] = qi[i];
+#if defined(PPC_DEBUG_IRQ)
+    printf("%s: env %p pin %d level %d\n", __func__, env, pin, level);
+#endif
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0) || 0) {
+        switch (pin) {
+        case PPC_INPUT_INT:
+            /* Level sensitive - asserted high */
+#if defined(PPC_DEBUG_IRQ)
+            printf("%s: set the external IRQ state to %d\n", __func__, level);
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC_INPUT_SMI:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            printf("%s: set the SMI IRQ state to %d\n", __func__, level);
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
+            break;
+        case PPC_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+#if defined(PPC_DEBUG_IRQ)
+                printf("%s: raise machine check state\n", __func__);
+#endif
+                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC_INPUT_CKSTP_IN:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                printf("%s: stop the CPU\n", __func__);
+#endif
+                env->halted = 1;
+            } else {
+#if defined(PPC_DEBUG_IRQ)
+                printf("%s: restart the CPU\n", __func__);
+#endif
+                env->halted = 0;
+            }
+            break;
+        case PPC_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+#if 0 // XXX: TOFIX
+#if defined(PPC_DEBUG_IRQ)
+                printf("%s: reset the CPU\n", __func__);
+#endif
+                cpu_reset(env);
+#endif
+            }
+            break;
+        case PPC_INPUT_SRESET:
+#if defined(PPC_DEBUG_IRQ)
+            printf("%s: set the RESET IRQ state to %d\n", __func__, level);
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+            printf("%s: unknown IRQ pin %d\n", __func__, pin);
+#endif
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
     }
 }
 
-/* External IRQ callback from OpenPIC IRQ controller */
-void ppc_openpic_irq (void *opaque, int n_IRQ, int level)
+void ppc6xx_irq_init (CPUState *env)
 {
-    switch (n_IRQ) {
-    case OPENPIC_EVT_INT:
-        n_IRQ = PPC_INTERRUPT_EXT;
-        break;
-    case OPENPIC_EVT_CINT:
-        /* On PowerPC BookE, critical input use vector 0 */
-        n_IRQ = PPC_INTERRUPT_RESET;
-        break;
-    case OPENPIC_EVT_MCK:
-        n_IRQ = PPC_INTERRUPT_MCK;
-        break;
-    case OPENPIC_EVT_DEBUG:
-        n_IRQ = PPC_INTERRUPT_DEBUG;
-        break;
-    case OPENPIC_EVT_RESET:
-        qemu_system_reset_request();
-        return;
-    }
-    ppc_set_irq(opaque, n_IRQ, level);
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
 }
 
 /*****************************************************************************/
-/* PPC time base and decrementer emulation */
+/* PowerPC time base and decrementer emulation */
 //#define DEBUG_TB
 
 struct ppc_tb_t {
 
  */
 #include "vl.h"
 
+/* SMP is not enabled, for now */
+#define MAX_CPUS 1
+
 #define BIOS_FILENAME "ppc_rom.bin"
 #define VGABIOS_FILENAME "video.x"
 #define NVRAM_SIZE        0x2000
                            const char *cpu_model,
                            int is_heathrow)
 {
-    CPUState *env;
+    CPUState *env, *envs[MAX_CPUS];
     char buf[1024];
-    qemu_irq *pic;
+    qemu_irq *pic, **openpic_irqs;
     m48t59_t *nvram;
     int unin_memory;
     int linux_boot, i;
     if (def == NULL) {
         cpu_abort(env, "Unable to find PowerPC CPU definition\n");
     }
-    cpu_ppc_register(env, def);
-    cpu_ppc_irq_init_cpu(env);
-
-    /* Set time-base frequency to 100 Mhz */
-    cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-    
-    env->osi_call = vga_osi_call;
+    for (i = 0; i < smp_cpus; i++) {
+        cpu_ppc_register(env, def);
+        /* Set time-base frequency to 100 Mhz */
+        cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+        env->osi_call = vga_osi_call;
+        envs[i] = env;
+    }
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
         unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
         cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
 
-        pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env);
+        openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+        openpic_irqs[0] =
+            qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+        for (i = 0; i < smp_cpus; i++) {
+            /* Mac99 IRQ connection between OpenPIC outputs pins
+             * and PowerPC input pins
+             */
+            openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+            openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+                ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT];
+            openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+                ((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT];
+            openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+                ((qemu_irq *)env->irq_inputs)[PPC_INPUT_MCP];
+            openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; /* Not connected ? */
+            openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+                ((qemu_irq *)env->irq_inputs)[PPC_INPUT_HRESET]; /* Check this */
+        }
+        pic = openpic_init(NULL, &openpic_mem_index, smp_cpus,
+                           openpic_irqs, NULL);
         pci_bus = pci_pmac_init(pic);
         /* init basic PC hardware */
         pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
 
         cpu_abort(env, "Unable to find PowerPC CPU definition\n");
     }
     cpu_ppc_register(env, def);
-    cpu_ppc_irq_init_cpu(env);
     /* Set time-base frequency to 100 Mhz */
     cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
 
     }
 
     isa_mem_base = 0xc0000000;
-    i8259 = i8259_init(first_cpu->irq[PPC_INTERRUPT_EXT]);
+    i8259 = i8259_init(first_cpu->irq_inputs[PPC_INPUT_INT]);
     pci_bus = pci_prep_init(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
 
     int error_code;
     int interrupt_request;
     uint32_t pending_interrupts;
-    void *irq[32];
+#if !defined(CONFIG_USER_ONLY)
+    /* This is the IRQ controller, which is implementation dependant
+     * and only relevant when emulating a complete machine.
+     */
+    uint32_t irq_input_state;
+    void **irq_inputs;
+#endif
 
     /* Those resources are used only during code translation */
     /* Next instruction pointer */
                            void *puc);
 
 void do_interrupt (CPUPPCState *env);
+void ppc_hw_interrupt (CPUPPCState *env);
 void cpu_loop_exit(void);
 
 void dump_stack (CPUPPCState *env);
 /* Hardware interruption sources:
  * all those exception can be raised simulteaneously
  */
+/* Input pins definitions */
+enum {
+    /* 6xx bus input pins */
+    PPC_INPUT_HRESET     = 0,
+    PPC_INPUT_SRESET     = 1,
+    PPC_INPUT_CKSTP_IN   = 2,
+    PPC_INPUT_MCP        = 3,
+    PPC_INPUT_SMI        = 4,
+    PPC_INPUT_INT        = 5,
+    /* Embedded PowerPC input pins */
+    PPC_INPUT_CINT       = 6,
+    PPC_INPUT_NB,
+};
+
+/* Hardware exceptions definitions */
 enum {
-    PPC_INTERRUPT_RESET  = 0, /* Reset / critical input               */
-    PPC_INTERRUPT_MCK    = 1, /* Machine check exception              */
-    PPC_INTERRUPT_EXT    = 2, /* External interrupt                   */
-    PPC_INTERRUPT_DECR   = 3, /* Decrementer exception                */
-    PPC_INTERRUPT_HDECR  = 4, /* Hypervisor decrementer exception     */
-    PPC_INTERRUPT_PIT    = 5, /* Programmable inteval timer interrupt */
-    PPC_INTERRUPT_FIT    = 6, /* Fixed interval timer interrupt       */
-    PPC_INTERRUPT_WDT    = 7, /* Watchdog timer interrupt             */
-    PPC_INTERRUPT_DEBUG  = 8, /* External debug exception             */
+    /* External hardware exception sources */
+    PPC_INTERRUPT_RESET  = 0,  /* Reset exception                      */
+    PPC_INTERRUPT_MCK    = 1,  /* Machine check exception              */
+    PPC_INTERRUPT_EXT    = 2,  /* External interrupt                   */
+    PPC_INTERRUPT_SMI    = 3,  /* System management interrupt          */
+    PPC_INTERRUPT_CEXT   = 4,  /* Critical external interrupt          */
+    PPC_INTERRUPT_DEBUG  = 5,  /* External debug exception             */
+    /* Internal hardware exception sources */
+    PPC_INTERRUPT_DECR   = 6,  /* Decrementer exception                */
+    PPC_INTERRUPT_HDECR  = 7,  /* Hypervisor decrementer exception     */
+    PPC_INTERRUPT_PIT    = 8,  /* Programmable inteval timer interrupt */
+    PPC_INTERRUPT_FIT    = 9,  /* Fixed interval timer interrupt       */
+    PPC_INTERRUPT_WDT    = 10, /* Watchdog timer interrupt             */
 };
 
 /*****************************************************************************/
 
     env->exception_index = -1;
 }
 
-int ppc_hw_interrupt (CPUState *env)
+void ppc_hw_interrupt (CPUState *env)
 {
     env->exception_index = -1;
-
-    return 0;
 }
 #else /* defined (CONFIG_USER_ONLY) */
 static void dump_syscall(CPUState *env)
     env->exception_index = EXCP_NONE;
 }
 
-int ppc_hw_interrupt (CPUState *env)
+void ppc_hw_interrupt (CPUPPCState *env)
 {
     int raised = 0;
 
     /* Raise it */
     if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
         /* External reset / critical input */
+        /* XXX: critical input should be handled another way.
+         *      This code is not correct !
+         */
         env->exception_index = EXCP_RESET;
         env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
         raised = 1;
         /* External interrupt */
         } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
             env->exception_index = EXCP_EXTERNAL;
+            /* Taking an external interrupt does not clear the external
+             * interrupt status
+             */
+#if 0
             env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
             raised = 1;
         }
 #if 0 // TODO
         env->error_code = 0;
         do_interrupt(env);
     }
-    
-    return raised;
 }
 #endif /* !CONFIG_USER_ONLY */
 
     uint64_t msr_mask;
 };
 
+/* For user-mode emulation, we don't emulate any IRQ controller */
+#if defined(CONFIG_USER_ONLY)
+#define PPC_IRQ_INIT_FN(name)                                         \
+static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \
+{                                                                     \
+}
+#else
+#define PPC_IRQ_INIT_FN(name)                                         \
+void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
+#endif
+PPC_IRQ_INIT_FN(6xx);
+
 /* Generic callbacks:
  * do nothing but store/retrieve spr value
  */
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
     case CPU_PPC_403GA:   /* 403 GA family                 */
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
     case CPU_PPC_405CR:   /* 405 GP/CR family              */
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
     case CPU_PPC_NPE405H: /* NPe405 H family               */
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
 #if defined (TODO)
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
     case CPU_PPC_440EP:   /* 440 EP family                 */
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
     /* Embedded PowerPC from Freescale                     */
         env->nb_tlb = 64;
         env->nb_ways = 1;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
 #if defined (TODO)
         env->nb_ways = 2;
         env->id_tlbs = 0;
         env->id_tlbs = 0;
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
 
     case CPU_PPC_602:     /* PowerPC 602                   */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
 
     case CPU_PPC_603:     /* PowerPC 603                   */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
         
     case CPU_PPC_G2:      /* PowerPC G2 family             */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
 
     case CPU_PPC_604:     /* PowerPC 604                   */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
 
     case CPU_PPC_74x:     /* PowerPC 740 / 750             */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
 
     case CPU_PPC_750FX10: /* IBM PowerPC 750 FX            */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
 
     case CPU_PPC_755_10:  /* PowerPC 755                   */
                      SPR_NOACCESS, SPR_NOACCESS,
                      &spr_read_generic, &spr_write_generic,
                      0x00000000);
+        /* Allocate hardware IRQ controller */
+        ppc6xx_irq_init(env);
         break;
 
 #if defined (TODO)
 
     default:
         gen_spr_generic(env);
+        /* XXX: TODO: allocate internal IRQ controller */
         break;
     }
     if (env->nb_BATs == -1)
 
 int piix4_init(PCIBus *bus, int devfn);
 
 /* openpic.c */
+/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
 enum {
-    OPENPIC_EVT_INT = 0, /* IRQ                       */
-    OPENPIC_EVT_CINT,    /* critical IRQ              */
-    OPENPIC_EVT_MCK,     /* Machine check event       */
-    OPENPIC_EVT_DEBUG,   /* Inconditional debug event */
-    OPENPIC_EVT_RESET,   /* Core reset event          */
+    OPENPIC_OUTPUT_INT = 0, /* IRQ                       */
+    OPENPIC_OUTPUT_CINT,    /* critical IRQ              */
+    OPENPIC_OUTPUT_MCK,     /* Machine check event       */
+    OPENPIC_OUTPUT_DEBUG,   /* Inconditional debug event */
+    OPENPIC_OUTPUT_RESET,   /* Core reset event          */
+    OPENPIC_OUTPUT_NB,
 };
-qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
-                        int *pmem_index, int nb_cpus,
-                        struct CPUState **envp);
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out);
 
 /* heathrow_pic.c */
 qemu_irq *heathrow_pic_init(int *pmem_index);
 
 #ifdef TARGET_PPC
 /* PowerPC hardware exceptions management helpers */
-void cpu_ppc_irq_init_cpu(CPUState *env);
-void ppc_openpic_irq (void *opaque, int n_IRQ, int level);
-int ppc_hw_interrupt (CPUState *env);
 ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
 #endif
 void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);