aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-exec.c12
-rw-r--r--hw/openpic.c106
-rw-r--r--hw/ppc.c126
-rw-r--r--hw/ppc_chrp.c42
-rw-r--r--hw/ppc_prep.c3
-rw-r--r--target-ppc/cpu.h46
-rw-r--r--target-ppc/helper.c16
-rw-r--r--target-ppc/translate_init.c35
-rw-r--r--vl.h20
9 files changed, 287 insertions, 119 deletions
diff --git a/cpu-exec.c b/cpu-exec.c
index 0eabacd643..284cb92ae8 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -467,16 +467,14 @@ int cpu_exec(CPUState *env1)
}
#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) &&
diff --git a/hw/openpic.c b/hw/openpic.c
index 3481f2d525..d52eb751e7 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -159,18 +159,18 @@ typedef struct IRQ_dst_t {
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 */
@@ -196,6 +196,8 @@ typedef struct openpic_t {
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)
@@ -255,19 +257,34 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, 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 */
@@ -280,27 +297,34 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ)
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))
@@ -308,9 +332,8 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ)
}
} 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);
@@ -350,6 +373,7 @@ static void openpic_reset (openpic_t *opp)
/* 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;
/* ? */
@@ -360,7 +384,7 @@ static void openpic_reset (openpic_t *opp)
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));
@@ -511,6 +535,8 @@ static void write_mailbox_register (openpic_t *opp, int n_mbx,
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)
@@ -530,11 +556,18 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
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 */
@@ -735,7 +768,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
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)
@@ -770,21 +803,21 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
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;
@@ -815,11 +848,13 @@ static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
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) ||
@@ -964,8 +999,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num,
#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;
@@ -995,7 +1030,6 @@ qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
} 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);
@@ -1020,9 +1054,11 @@ qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
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);
}
diff --git a/hw/ppc.c b/hw/ppc.c
index 44555bd634..f5c45001bb 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -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 {
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index 18a1aab2b5..c418cd1b4a 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -23,6 +23,9 @@
*/
#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
@@ -296,9 +299,9 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
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;
@@ -329,13 +332,13 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
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);
@@ -458,7 +461,26 @@ static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
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,
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 225b531685..8b53ef30a8 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -548,7 +548,6 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
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);
@@ -599,7 +598,7 @@ static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
}
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) */
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 1515af9930..0560a38a1e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -758,7 +758,13 @@ struct CPUPPCState {
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 */
@@ -801,6 +807,7 @@ int cpu_ppc_signal_handler(int host_signum, void *pinfo,
void *puc);
void do_interrupt (CPUPPCState *env);
+void ppc_hw_interrupt (CPUPPCState *env);
void cpu_loop_exit(void);
void dump_stack (CPUPPCState *env);
@@ -1303,16 +1310,35 @@ enum {
/* 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 */
};
/*****************************************************************************/
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 69ed260f75..b9a55b1f2b 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1358,11 +1358,9 @@ void do_interrupt (CPUState *env)
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)
@@ -1927,7 +1925,7 @@ void do_interrupt (CPUState *env)
env->exception_index = EXCP_NONE;
}
-int ppc_hw_interrupt (CPUState *env)
+void ppc_hw_interrupt (CPUPPCState *env)
{
int raised = 0;
@@ -1940,6 +1938,9 @@ int ppc_hw_interrupt (CPUState *env)
/* 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;
@@ -1984,7 +1985,12 @@ int ppc_hw_interrupt (CPUState *env)
/* 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
@@ -1999,7 +2005,5 @@ int ppc_hw_interrupt (CPUState *env)
env->error_code = 0;
do_interrupt(env);
}
-
- return raised;
}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index d5626316c9..805c897248 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -35,6 +35,18 @@ struct ppc_def_t {
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
*/
@@ -1865,6 +1877,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -1879,6 +1892,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -1895,6 +1909,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -1909,6 +1924,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
break;
#if defined (TODO)
@@ -1940,6 +1956,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -1959,6 +1976,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
break;
/* Embedded PowerPC from Freescale */
@@ -1994,6 +2012,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
env->nb_tlb = 64;
env->nb_ways = 1;
env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
break;
#if defined (TODO)
@@ -2038,6 +2057,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2060,6 +2080,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2087,6 +2109,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2123,6 +2147,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2146,6 +2172,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2178,6 +2206,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2213,6 +2243,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
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 */
@@ -2257,6 +2289,8 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
break;
#if defined (TODO)
@@ -2326,6 +2360,7 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
default:
gen_spr_generic(env);
+ /* XXX: TODO: allocate internal IRQ controller */
break;
}
if (env->nb_BATs == -1)
diff --git a/vl.h b/vl.h
index 2f87946e87..b40ff37475 100644
--- a/vl.h
+++ b/vl.h
@@ -854,16 +854,17 @@ void i440fx_init_memory_mappings(PCIDevice *d);
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);
@@ -1145,9 +1146,6 @@ extern QEMUMachine shix_machine;
#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);