diff options
author | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-04-09 22:45:36 +0000 |
---|---|---|
committer | j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-04-09 22:45:36 +0000 |
commit | e9df014c0b433ecd9785db4a423e472bc3db386a (patch) | |
tree | e16e40d4fd68aff979be0d8e57ffdc17ee108ca7 /hw/ppc.c | |
parent | 682c4f15598fa82eb00973b9b14be86d1e5a726c (diff) |
Implement embedded IRQ controller for PowerPC 6xx/740 & 750.
Fix PowerPC external interrupt input handling and lowering.
Fix OpenPIC output pins management.
Fix multiples bugs in OpenPIC IRQ management.
Fix OpenPIC CPU(s) reset function.
Fix Mac99 machine to properly route OpenPIC outputs to the PowerPC input pins.
Fix PREP machine to properly route i8259 output to the PowerPC external
interrupt pin.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2647 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/ppc.c')
-rw-r--r-- | hw/ppc.c | 126 |
1 files changed, 88 insertions, 38 deletions
@@ -1,5 +1,5 @@ /* - * QEMU generic PPC hardware System Emulator + * QEMU generic PowerPC hardware System Emulator * * Copyright (c) 2003-2007 Jocelyn Mayer * @@ -24,18 +24,13 @@ #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); @@ -44,49 +39,104 @@ static void ppc_set_irq (void *opaque, int n_IRQ, int level) 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 { |