Revision e9df014c
b/cpu-exec.c | ||
---|---|---|
467 | 467 |
} |
468 | 468 |
#endif |
469 | 469 |
if (interrupt_request & CPU_INTERRUPT_HARD) { |
470 |
if (ppc_hw_interrupt(env) == 1) { |
|
471 |
/* Some exception was raised */ |
|
472 |
if (env->pending_interrupts == 0) |
|
473 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
|
470 |
ppc_hw_interrupt(env); |
|
471 |
if (env->pending_interrupts == 0) |
|
472 |
env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
|
474 | 473 |
#if defined(__sparc__) && !defined(HOST_SOLARIS) |
475 |
tmp_T0 = 0;
|
|
474 |
tmp_T0 = 0; |
|
476 | 475 |
#else |
477 |
T0 = 0;
|
|
476 |
T0 = 0; |
|
478 | 477 |
#endif |
479 |
} |
|
480 | 478 |
} |
481 | 479 |
#elif defined(TARGET_MIPS) |
482 | 480 |
if ((interrupt_request & CPU_INTERRUPT_HARD) && |
b/hw/openpic.c | ||
---|---|---|
159 | 159 |
uint32_t pcsr; /* CPU sensitivity register */ |
160 | 160 |
IRQ_queue_t raised; |
161 | 161 |
IRQ_queue_t servicing; |
162 |
CPUState *env;
|
|
162 |
qemu_irq *irqs;
|
|
163 | 163 |
} IRQ_dst_t; |
164 | 164 |
|
165 | 165 |
typedef struct openpic_t { |
166 | 166 |
PCIDevice pci_dev; |
167 |
SetIRQFunc *set_irq; |
|
168 | 167 |
int mem_index; |
169 | 168 |
/* Global registers */ |
170 | 169 |
uint32_t frep; /* Feature reporting register */ |
171 | 170 |
uint32_t glbc; /* Global configuration register */ |
172 | 171 |
uint32_t micr; /* MPIC interrupt configuration register */ |
173 | 172 |
uint32_t veni; /* Vendor identification register */ |
173 |
uint32_t pint; /* Processor initialization register */ |
|
174 | 174 |
uint32_t spve; /* Spurious vector register */ |
175 | 175 |
uint32_t tifr; /* Timer frequency reporting register */ |
176 | 176 |
/* Source registers */ |
... | ... | |
196 | 196 |
uint32_t mbr; /* Mailbox register */ |
197 | 197 |
} mailboxes[MAX_MAILBOXES]; |
198 | 198 |
#endif |
199 |
/* IRQ out is used when in bypass mode (not implemented) */ |
|
200 |
qemu_irq irq_out; |
|
199 | 201 |
} openpic_t; |
200 | 202 |
|
201 | 203 |
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) |
... | ... | |
255 | 257 |
priority = IPVP_PRIORITY(src->ipvp); |
256 | 258 |
if (priority <= dst->pctp) { |
257 | 259 |
/* Too low priority */ |
260 |
DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", |
|
261 |
__func__, n_IRQ, n_CPU); |
|
258 | 262 |
return; |
259 | 263 |
} |
260 | 264 |
if (IRQ_testbit(&dst->raised, n_IRQ)) { |
261 | 265 |
/* Interrupt miss */ |
266 |
DPRINTF("%s: IRQ %d was missed on CPU %d\n", |
|
267 |
__func__, n_IRQ, n_CPU); |
|
262 | 268 |
return; |
263 | 269 |
} |
264 | 270 |
set_bit(&src->ipvp, IPVP_ACTIVITY); |
265 | 271 |
IRQ_setbit(&dst->raised, n_IRQ); |
266 |
if (priority > dst->raised.priority) { |
|
267 |
IRQ_get_next(opp, &dst->raised); |
|
268 |
DPRINTF("Raise CPU IRQ fn %p env %p\n", opp->set_irq, dst->env); |
|
269 |
opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); |
|
272 |
if (priority < dst->raised.priority) { |
|
273 |
/* An higher priority IRQ is already raised */ |
|
274 |
DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n", |
|
275 |
__func__, n_IRQ, dst->raised.next, n_CPU); |
|
276 |
return; |
|
277 |
} |
|
278 |
IRQ_get_next(opp, &dst->raised); |
|
279 |
if (IRQ_get_next(opp, &dst->servicing) != -1 && |
|
280 |
priority < dst->servicing.priority) { |
|
281 |
DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", |
|
282 |
__func__, n_IRQ, dst->servicing.next, n_CPU); |
|
283 |
/* Already servicing a higher priority IRQ */ |
|
284 |
return; |
|
270 | 285 |
} |
286 |
DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); |
|
287 |
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); |
|
271 | 288 |
} |
272 | 289 |
|
273 | 290 |
/* update pic state because registers for n_IRQ have changed value */ |
... | ... | |
280 | 297 |
|
281 | 298 |
if (!src->pending) { |
282 | 299 |
/* no irq pending */ |
300 |
DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); |
|
283 | 301 |
return; |
284 | 302 |
} |
285 | 303 |
if (test_bit(&src->ipvp, IPVP_MASK)) { |
286 | 304 |
/* Interrupt source is disabled */ |
305 |
DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); |
|
287 | 306 |
return; |
288 | 307 |
} |
289 | 308 |
if (IPVP_PRIORITY(src->ipvp) == 0) { |
290 | 309 |
/* Priority set to zero */ |
310 |
DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); |
|
291 | 311 |
return; |
292 | 312 |
} |
293 | 313 |
if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { |
294 | 314 |
/* IRQ already active */ |
315 |
DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); |
|
295 | 316 |
return; |
296 | 317 |
} |
297 | 318 |
if (src->ide == 0x00000000) { |
298 | 319 |
/* No target */ |
320 |
DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); |
|
299 | 321 |
return; |
300 | 322 |
} |
301 | 323 |
|
302 |
if (!test_bit(&src->ipvp, IPVP_MODE) || |
|
303 |
src->ide == (1 << src->last_cpu)) { |
|
324 |
if (src->ide == (1 << src->last_cpu)) { |
|
325 |
/* Only one CPU is allowed to receive this IRQ */ |
|
326 |
IRQ_local_pipe(opp, src->last_cpu, n_IRQ); |
|
327 |
} else if (!test_bit(&src->ipvp, IPVP_MODE)) { |
|
304 | 328 |
/* Directed delivery mode */ |
305 | 329 |
for (i = 0; i < opp->nb_cpus; i++) { |
306 | 330 |
if (test_bit(&src->ide, i)) |
... | ... | |
308 | 332 |
} |
309 | 333 |
} else { |
310 | 334 |
/* Distributed delivery mode */ |
311 |
/* XXX: incorrect code */ |
|
312 |
for (i = src->last_cpu; i < src->last_cpu; i++) { |
|
313 |
if (i == MAX_IRQ) |
|
335 |
for (i = src->last_cpu + 1; i != src->last_cpu; i++) { |
|
336 |
if (i == opp->nb_cpus) |
|
314 | 337 |
i = 0; |
315 | 338 |
if (test_bit(&src->ide, i)) { |
316 | 339 |
IRQ_local_pipe(opp, i, n_IRQ); |
... | ... | |
350 | 373 |
/* Initialise controller registers */ |
351 | 374 |
opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; |
352 | 375 |
opp->veni = VENI; |
376 |
opp->pint = 0x00000000; |
|
353 | 377 |
opp->spve = 0x000000FF; |
354 | 378 |
opp->tifr = 0x003F7A00; |
355 | 379 |
/* ? */ |
... | ... | |
360 | 384 |
opp->src[i].ide = 0x00000000; |
361 | 385 |
} |
362 | 386 |
/* Initialise IRQ destinations */ |
363 |
for (i = 0; i < opp->nb_cpus; i++) {
|
|
387 |
for (i = 0; i < MAX_CPU; i++) {
|
|
364 | 388 |
opp->dst[i].pctp = 0x0000000F; |
365 | 389 |
opp->dst[i].pcsr = 0x00000000; |
366 | 390 |
memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); |
... | ... | |
511 | 535 |
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) |
512 | 536 |
{ |
513 | 537 |
openpic_t *opp = opaque; |
538 |
IRQ_dst_t *dst; |
|
539 |
int idx; |
|
514 | 540 |
|
515 | 541 |
DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); |
516 | 542 |
if (addr & 0xF) |
... | ... | |
530 | 556 |
case 0x80: /* VENI */ |
531 | 557 |
break; |
532 | 558 |
case 0x90: /* PINT */ |
533 |
/* XXX: Should be able to reset any CPU */ |
|
534 |
if (val & 1) { |
|
535 |
DPRINTF("Reset CPU IRQ\n"); |
|
536 |
// opp->set_irq(dst->env, OPENPIC_EVT_RESET, 1); |
|
559 |
for (idx = 0; idx < opp->nb_cpus; idx++) { |
|
560 |
if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { |
|
561 |
DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); |
|
562 |
dst = &opp->dst[idx]; |
|
563 |
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); |
|
564 |
} else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) { |
|
565 |
DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); |
|
566 |
dst = &opp->dst[idx]; |
|
567 |
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); |
|
568 |
} |
|
537 | 569 |
} |
570 |
opp->pint = val; |
|
538 | 571 |
break; |
539 | 572 |
#if MAX_IPI > 0 |
540 | 573 |
case 0xA0: /* IPI_IPVP */ |
... | ... | |
735 | 768 |
openpic_t *opp = opaque; |
736 | 769 |
IRQ_src_t *src; |
737 | 770 |
IRQ_dst_t *dst; |
738 |
int idx, n_IRQ; |
|
771 |
int idx, s_IRQ, n_IRQ;
|
|
739 | 772 |
|
740 | 773 |
DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); |
741 | 774 |
if (addr & 0xF) |
... | ... | |
770 | 803 |
break; |
771 | 804 |
case 0xB0: /* PEOI */ |
772 | 805 |
DPRINTF("PEOI\n"); |
773 |
n_IRQ = IRQ_get_next(opp, &dst->servicing);
|
|
774 |
IRQ_resetbit(&dst->servicing, n_IRQ);
|
|
806 |
s_IRQ = IRQ_get_next(opp, &dst->servicing);
|
|
807 |
IRQ_resetbit(&dst->servicing, s_IRQ);
|
|
775 | 808 |
dst->servicing.next = -1; |
776 |
src = &opp->src[n_IRQ]; |
|
777 | 809 |
/* Set up next servicing IRQ */ |
778 |
IRQ_get_next(opp, &dst->servicing); |
|
779 |
/* Check queued interrupts. */ |
|
780 |
n_IRQ = IRQ_get_next(opp, &dst->raised); |
|
781 |
if (n_IRQ != -1) { |
|
782 |
src = &opp->src[n_IRQ]; |
|
783 |
if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { |
|
784 |
DPRINTF("Raise CPU IRQ\n"); |
|
785 |
opp->set_irq(dst->env, OPENPIC_EVT_INT, 1); |
|
786 |
} |
|
787 |
} |
|
810 |
s_IRQ = IRQ_get_next(opp, &dst->servicing); |
|
811 |
/* Check queued interrupts. */ |
|
812 |
n_IRQ = IRQ_get_next(opp, &dst->raised); |
|
813 |
src = &opp->src[n_IRQ]; |
|
814 |
if (n_IRQ != -1 && |
|
815 |
(s_IRQ == -1 || |
|
816 |
IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { |
|
817 |
DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", |
|
818 |
idx, n_IRQ); |
|
819 |
qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); |
|
820 |
} |
|
788 | 821 |
break; |
789 | 822 |
default: |
790 | 823 |
break; |
... | ... | |
815 | 848 |
retval = idx; |
816 | 849 |
break; |
817 | 850 |
case 0xA0: /* PIAC */ |
851 |
DPRINTF("Lower OpenPIC INT output\n"); |
|
852 |
qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); |
|
818 | 853 |
n_IRQ = IRQ_get_next(opp, &dst->raised); |
819 | 854 |
DPRINTF("PIAC: irq=%d\n", n_IRQ); |
820 | 855 |
if (n_IRQ == -1) { |
821 | 856 |
/* No more interrupt pending */ |
822 |
retval = opp->spve;
|
|
857 |
retval = IPVP_VECTOR(opp->spve);
|
|
823 | 858 |
} else { |
824 | 859 |
src = &opp->src[n_IRQ]; |
825 | 860 |
if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || |
... | ... | |
964 | 999 |
#endif |
965 | 1000 |
} |
966 | 1001 |
|
967 |
qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq,
|
|
968 |
int *pmem_index, int nb_cpus, CPUState **envp)
|
|
1002 |
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
|
|
1003 |
qemu_irq **irqs, qemu_irq irq_out)
|
|
969 | 1004 |
{ |
970 | 1005 |
openpic_t *opp; |
971 | 1006 |
uint8_t *pci_conf; |
... | ... | |
995 | 1030 |
} else { |
996 | 1031 |
opp = qemu_mallocz(sizeof(openpic_t)); |
997 | 1032 |
} |
998 |
opp->set_irq = set_irq; |
|
999 | 1033 |
opp->mem_index = cpu_register_io_memory(0, openpic_read, |
1000 | 1034 |
openpic_write, opp); |
1001 | 1035 |
|
... | ... | |
1020 | 1054 |
opp->src[i].type = IRQ_INTERNAL; |
1021 | 1055 |
} |
1022 | 1056 |
for (i = 0; i < nb_cpus; i++) |
1023 |
opp->dst[i].env = envp[i]; |
|
1057 |
opp->dst[i].irqs = irqs[i]; |
|
1058 |
opp->irq_out = irq_out; |
|
1024 | 1059 |
openpic_reset(opp); |
1025 | 1060 |
if (pmem_index) |
1026 | 1061 |
*pmem_index = opp->mem_index; |
1062 |
|
|
1027 | 1063 |
return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ); |
1028 | 1064 |
} |
b/hw/ppc.c | ||
---|---|---|
1 | 1 |
/* |
2 |
* QEMU generic PPC hardware System Emulator |
|
2 |
* QEMU generic PowerPC hardware System Emulator
|
|
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2003-2007 Jocelyn Mayer |
5 | 5 |
* |
... | ... | |
24 | 24 |
#include "vl.h" |
25 | 25 |
#include "m48t59.h" |
26 | 26 |
|
27 |
//#define PPC_DEBUG_IRQ |
|
28 |
|
|
27 | 29 |
extern FILE *logfile; |
28 | 30 |
extern int loglevel; |
29 | 31 |
|
30 |
/*****************************************************************************/ |
|
31 |
/* PowerPC internal fake IRQ controller |
|
32 |
* used to manage multiple sources hardware events |
|
33 |
*/ |
|
34 |
static void ppc_set_irq (void *opaque, int n_IRQ, int level) |
|
32 |
void ppc_set_irq (CPUState *env, int n_IRQ, int level) |
|
35 | 33 |
{ |
36 |
CPUState *env; |
|
37 |
|
|
38 |
env = opaque; |
|
39 | 34 |
if (level) { |
40 | 35 |
env->pending_interrupts |= 1 << n_IRQ; |
41 | 36 |
cpu_interrupt(env, CPU_INTERRUPT_HARD); |
... | ... | |
44 | 39 |
if (env->pending_interrupts == 0) |
45 | 40 |
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); |
46 | 41 |
} |
47 |
#if 0
|
|
42 |
#if defined(PPC_DEBUG_IRQ)
|
|
48 | 43 |
printf("%s: %p n_IRQ %d level %d => pending %08x req %08x\n", __func__, |
49 | 44 |
env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); |
50 | 45 |
#endif |
51 | 46 |
} |
52 | 47 |
|
53 |
void cpu_ppc_irq_init_cpu(CPUState *env) |
|
48 |
/* PowerPC 6xx / 7xx internal IRQ controller */ |
|
49 |
static void ppc6xx_set_irq (void *opaque, int pin, int level) |
|
54 | 50 |
{ |
55 |
qemu_irq *qi;
|
|
56 |
int i;
|
|
51 |
CPUState *env = opaque;
|
|
52 |
int cur_level;
|
|
57 | 53 |
|
58 |
qi = qemu_allocate_irqs(ppc_set_irq, env, 32); |
|
59 |
for (i = 0; i < 32; i++) { |
|
60 |
env->irq[i] = qi[i]; |
|
54 |
#if defined(PPC_DEBUG_IRQ) |
|
55 |
printf("%s: env %p pin %d level %d\n", __func__, env, pin, level); |
|
56 |
#endif |
|
57 |
cur_level = (env->irq_input_state >> pin) & 1; |
|
58 |
/* Don't generate spurious events */ |
|
59 |
if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0) || 0) { |
|
60 |
switch (pin) { |
|
61 |
case PPC_INPUT_INT: |
|
62 |
/* Level sensitive - asserted high */ |
|
63 |
#if defined(PPC_DEBUG_IRQ) |
|
64 |
printf("%s: set the external IRQ state to %d\n", __func__, level); |
|
65 |
#endif |
|
66 |
ppc_set_irq(env, PPC_INTERRUPT_EXT, level); |
|
67 |
break; |
|
68 |
case PPC_INPUT_SMI: |
|
69 |
/* Level sensitive - active high */ |
|
70 |
#if defined(PPC_DEBUG_IRQ) |
|
71 |
printf("%s: set the SMI IRQ state to %d\n", __func__, level); |
|
72 |
#endif |
|
73 |
ppc_set_irq(env, PPC_INTERRUPT_SMI, level); |
|
74 |
break; |
|
75 |
case PPC_INPUT_MCP: |
|
76 |
/* Negative edge sensitive */ |
|
77 |
/* XXX: TODO: actual reaction may depends on HID0 status |
|
78 |
* 603/604/740/750: check HID0[EMCP] |
|
79 |
*/ |
|
80 |
if (cur_level == 1 && level == 0) { |
|
81 |
#if defined(PPC_DEBUG_IRQ) |
|
82 |
printf("%s: raise machine check state\n", __func__); |
|
83 |
#endif |
|
84 |
ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); |
|
85 |
} |
|
86 |
break; |
|
87 |
case PPC_INPUT_CKSTP_IN: |
|
88 |
/* Level sensitive - active low */ |
|
89 |
/* XXX: TODO: relay the signal to CKSTP_OUT pin */ |
|
90 |
if (level) { |
|
91 |
#if defined(PPC_DEBUG_IRQ) |
|
92 |
printf("%s: stop the CPU\n", __func__); |
|
93 |
#endif |
|
94 |
env->halted = 1; |
|
95 |
} else { |
|
96 |
#if defined(PPC_DEBUG_IRQ) |
|
97 |
printf("%s: restart the CPU\n", __func__); |
|
98 |
#endif |
|
99 |
env->halted = 0; |
|
100 |
} |
|
101 |
break; |
|
102 |
case PPC_INPUT_HRESET: |
|
103 |
/* Level sensitive - active low */ |
|
104 |
if (level) { |
|
105 |
#if 0 // XXX: TOFIX |
|
106 |
#if defined(PPC_DEBUG_IRQ) |
|
107 |
printf("%s: reset the CPU\n", __func__); |
|
108 |
#endif |
|
109 |
cpu_reset(env); |
|
110 |
#endif |
|
111 |
} |
|
112 |
break; |
|
113 |
case PPC_INPUT_SRESET: |
|
114 |
#if defined(PPC_DEBUG_IRQ) |
|
115 |
printf("%s: set the RESET IRQ state to %d\n", __func__, level); |
|
116 |
#endif |
|
117 |
ppc_set_irq(env, PPC_INTERRUPT_RESET, level); |
|
118 |
break; |
|
119 |
default: |
|
120 |
/* Unknown pin - do nothing */ |
|
121 |
#if defined(PPC_DEBUG_IRQ) |
|
122 |
printf("%s: unknown IRQ pin %d\n", __func__, pin); |
|
123 |
#endif |
|
124 |
return; |
|
125 |
} |
|
126 |
if (level) |
|
127 |
env->irq_input_state |= 1 << pin; |
|
128 |
else |
|
129 |
env->irq_input_state &= ~(1 << pin); |
|
61 | 130 |
} |
62 | 131 |
} |
63 | 132 |
|
64 |
/* External IRQ callback from OpenPIC IRQ controller */ |
|
65 |
void ppc_openpic_irq (void *opaque, int n_IRQ, int level) |
|
133 |
void ppc6xx_irq_init (CPUState *env) |
|
66 | 134 |
{ |
67 |
switch (n_IRQ) { |
|
68 |
case OPENPIC_EVT_INT: |
|
69 |
n_IRQ = PPC_INTERRUPT_EXT; |
|
70 |
break; |
|
71 |
case OPENPIC_EVT_CINT: |
|
72 |
/* On PowerPC BookE, critical input use vector 0 */ |
|
73 |
n_IRQ = PPC_INTERRUPT_RESET; |
|
74 |
break; |
|
75 |
case OPENPIC_EVT_MCK: |
|
76 |
n_IRQ = PPC_INTERRUPT_MCK; |
|
77 |
break; |
|
78 |
case OPENPIC_EVT_DEBUG: |
|
79 |
n_IRQ = PPC_INTERRUPT_DEBUG; |
|
80 |
break; |
|
81 |
case OPENPIC_EVT_RESET: |
|
82 |
qemu_system_reset_request(); |
|
83 |
return; |
|
84 |
} |
|
85 |
ppc_set_irq(opaque, n_IRQ, level); |
|
135 |
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6); |
|
86 | 136 |
} |
87 | 137 |
|
88 | 138 |
/*****************************************************************************/ |
89 |
/* PPC time base and decrementer emulation */ |
|
139 |
/* PowerPC time base and decrementer emulation */
|
|
90 | 140 |
//#define DEBUG_TB |
91 | 141 |
|
92 | 142 |
struct ppc_tb_t { |
b/hw/ppc_chrp.c | ||
---|---|---|
23 | 23 |
*/ |
24 | 24 |
#include "vl.h" |
25 | 25 |
|
26 |
/* SMP is not enabled, for now */ |
|
27 |
#define MAX_CPUS 1 |
|
28 |
|
|
26 | 29 |
#define BIOS_FILENAME "ppc_rom.bin" |
27 | 30 |
#define VGABIOS_FILENAME "video.x" |
28 | 31 |
#define NVRAM_SIZE 0x2000 |
... | ... | |
296 | 299 |
const char *cpu_model, |
297 | 300 |
int is_heathrow) |
298 | 301 |
{ |
299 |
CPUState *env; |
|
302 |
CPUState *env, *envs[MAX_CPUS];
|
|
300 | 303 |
char buf[1024]; |
301 |
qemu_irq *pic; |
|
304 |
qemu_irq *pic, **openpic_irqs;
|
|
302 | 305 |
m48t59_t *nvram; |
303 | 306 |
int unin_memory; |
304 | 307 |
int linux_boot, i; |
... | ... | |
329 | 332 |
if (def == NULL) { |
330 | 333 |
cpu_abort(env, "Unable to find PowerPC CPU definition\n"); |
331 | 334 |
} |
332 |
cpu_ppc_register(env, def);
|
|
333 |
cpu_ppc_irq_init_cpu(env);
|
|
334 |
|
|
335 |
/* Set time-base frequency to 100 Mhz */
|
|
336 |
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
|
|
337 |
|
|
338 |
env->osi_call = vga_osi_call;
|
|
335 |
for (i = 0; i < smp_cpus; i++) {
|
|
336 |
cpu_ppc_register(env, def);
|
|
337 |
/* Set time-base frequency to 100 Mhz */ |
|
338 |
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
|
|
339 |
env->osi_call = vga_osi_call;
|
|
340 |
envs[i] = env; |
|
341 |
}
|
|
339 | 342 |
|
340 | 343 |
/* allocate RAM */ |
341 | 344 |
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); |
... | ... | |
458 | 461 |
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); |
459 | 462 |
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); |
460 | 463 |
|
461 |
pic = openpic_init(NULL, &ppc_openpic_irq, &openpic_mem_index, 1, &env); |
|
464 |
openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *)); |
|
465 |
openpic_irqs[0] = |
|
466 |
qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB); |
|
467 |
for (i = 0; i < smp_cpus; i++) { |
|
468 |
/* Mac99 IRQ connection between OpenPIC outputs pins |
|
469 |
* and PowerPC input pins |
|
470 |
*/ |
|
471 |
openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB); |
|
472 |
openpic_irqs[i][OPENPIC_OUTPUT_INT] = |
|
473 |
((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; |
|
474 |
openpic_irqs[i][OPENPIC_OUTPUT_CINT] = |
|
475 |
((qemu_irq *)env->irq_inputs)[PPC_INPUT_INT]; |
|
476 |
openpic_irqs[i][OPENPIC_OUTPUT_MCK] = |
|
477 |
((qemu_irq *)env->irq_inputs)[PPC_INPUT_MCP]; |
|
478 |
openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL; /* Not connected ? */ |
|
479 |
openpic_irqs[i][OPENPIC_OUTPUT_RESET] = |
|
480 |
((qemu_irq *)env->irq_inputs)[PPC_INPUT_HRESET]; /* Check this */ |
|
481 |
} |
|
482 |
pic = openpic_init(NULL, &openpic_mem_index, smp_cpus, |
|
483 |
openpic_irqs, NULL); |
|
462 | 484 |
pci_bus = pci_pmac_init(pic); |
463 | 485 |
/* init basic PC hardware */ |
464 | 486 |
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, |
b/hw/ppc_prep.c | ||
---|---|---|
548 | 548 |
cpu_abort(env, "Unable to find PowerPC CPU definition\n"); |
549 | 549 |
} |
550 | 550 |
cpu_ppc_register(env, def); |
551 |
cpu_ppc_irq_init_cpu(env); |
|
552 | 551 |
/* Set time-base frequency to 100 Mhz */ |
553 | 552 |
cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); |
554 | 553 |
|
... | ... | |
599 | 598 |
} |
600 | 599 |
|
601 | 600 |
isa_mem_base = 0xc0000000; |
602 |
i8259 = i8259_init(first_cpu->irq[PPC_INTERRUPT_EXT]);
|
|
601 |
i8259 = i8259_init(first_cpu->irq_inputs[PPC_INPUT_INT]);
|
|
603 | 602 |
pci_bus = pci_prep_init(i8259); |
604 | 603 |
// pci_bus = i440fx_init(); |
605 | 604 |
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */ |
b/target-ppc/cpu.h | ||
---|---|---|
758 | 758 |
int error_code; |
759 | 759 |
int interrupt_request; |
760 | 760 |
uint32_t pending_interrupts; |
761 |
void *irq[32]; |
|
761 |
#if !defined(CONFIG_USER_ONLY) |
|
762 |
/* This is the IRQ controller, which is implementation dependant |
|
763 |
* and only relevant when emulating a complete machine. |
|
764 |
*/ |
|
765 |
uint32_t irq_input_state; |
|
766 |
void **irq_inputs; |
|
767 |
#endif |
|
762 | 768 |
|
763 | 769 |
/* Those resources are used only during code translation */ |
764 | 770 |
/* Next instruction pointer */ |
... | ... | |
801 | 807 |
void *puc); |
802 | 808 |
|
803 | 809 |
void do_interrupt (CPUPPCState *env); |
810 |
void ppc_hw_interrupt (CPUPPCState *env); |
|
804 | 811 |
void cpu_loop_exit(void); |
805 | 812 |
|
806 | 813 |
void dump_stack (CPUPPCState *env); |
... | ... | |
1303 | 1310 |
/* Hardware interruption sources: |
1304 | 1311 |
* all those exception can be raised simulteaneously |
1305 | 1312 |
*/ |
1313 |
/* Input pins definitions */ |
|
1314 |
enum { |
|
1315 |
/* 6xx bus input pins */ |
|
1316 |
PPC_INPUT_HRESET = 0, |
|
1317 |
PPC_INPUT_SRESET = 1, |
|
1318 |
PPC_INPUT_CKSTP_IN = 2, |
|
1319 |
PPC_INPUT_MCP = 3, |
|
1320 |
PPC_INPUT_SMI = 4, |
|
1321 |
PPC_INPUT_INT = 5, |
|
1322 |
/* Embedded PowerPC input pins */ |
|
1323 |
PPC_INPUT_CINT = 6, |
|
1324 |
PPC_INPUT_NB, |
|
1325 |
}; |
|
1326 |
|
|
1327 |
/* Hardware exceptions definitions */ |
|
1306 | 1328 |
enum { |
1307 |
PPC_INTERRUPT_RESET = 0, /* Reset / critical input */ |
|
1308 |
PPC_INTERRUPT_MCK = 1, /* Machine check exception */ |
|
1309 |
PPC_INTERRUPT_EXT = 2, /* External interrupt */ |
|
1310 |
PPC_INTERRUPT_DECR = 3, /* Decrementer exception */ |
|
1311 |
PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */ |
|
1312 |
PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */ |
|
1313 |
PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */ |
|
1314 |
PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */ |
|
1315 |
PPC_INTERRUPT_DEBUG = 8, /* External debug exception */ |
|
1329 |
/* External hardware exception sources */ |
|
1330 |
PPC_INTERRUPT_RESET = 0, /* Reset exception */ |
|
1331 |
PPC_INTERRUPT_MCK = 1, /* Machine check exception */ |
|
1332 |
PPC_INTERRUPT_EXT = 2, /* External interrupt */ |
|
1333 |
PPC_INTERRUPT_SMI = 3, /* System management interrupt */ |
|
1334 |
PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */ |
|
1335 |
PPC_INTERRUPT_DEBUG = 5, /* External debug exception */ |
|
1336 |
/* Internal hardware exception sources */ |
|
1337 |
PPC_INTERRUPT_DECR = 6, /* Decrementer exception */ |
|
1338 |
PPC_INTERRUPT_HDECR = 7, /* Hypervisor decrementer exception */ |
|
1339 |
PPC_INTERRUPT_PIT = 8, /* Programmable inteval timer interrupt */ |
|
1340 |
PPC_INTERRUPT_FIT = 9, /* Fixed interval timer interrupt */ |
|
1341 |
PPC_INTERRUPT_WDT = 10, /* Watchdog timer interrupt */ |
|
1316 | 1342 |
}; |
1317 | 1343 |
|
1318 | 1344 |
/*****************************************************************************/ |
b/target-ppc/helper.c | ||
---|---|---|
1358 | 1358 |
env->exception_index = -1; |
1359 | 1359 |
} |
1360 | 1360 |
|
1361 |
int ppc_hw_interrupt (CPUState *env)
|
|
1361 |
void ppc_hw_interrupt (CPUState *env)
|
|
1362 | 1362 |
{ |
1363 | 1363 |
env->exception_index = -1; |
1364 |
|
|
1365 |
return 0; |
|
1366 | 1364 |
} |
1367 | 1365 |
#else /* defined (CONFIG_USER_ONLY) */ |
1368 | 1366 |
static void dump_syscall(CPUState *env) |
... | ... | |
1927 | 1925 |
env->exception_index = EXCP_NONE; |
1928 | 1926 |
} |
1929 | 1927 |
|
1930 |
int ppc_hw_interrupt (CPUState *env)
|
|
1928 |
void ppc_hw_interrupt (CPUPPCState *env)
|
|
1931 | 1929 |
{ |
1932 | 1930 |
int raised = 0; |
1933 | 1931 |
|
... | ... | |
1940 | 1938 |
/* Raise it */ |
1941 | 1939 |
if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) { |
1942 | 1940 |
/* External reset / critical input */ |
1941 |
/* XXX: critical input should be handled another way. |
|
1942 |
* This code is not correct ! |
|
1943 |
*/ |
|
1943 | 1944 |
env->exception_index = EXCP_RESET; |
1944 | 1945 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET); |
1945 | 1946 |
raised = 1; |
... | ... | |
1984 | 1985 |
/* External interrupt */ |
1985 | 1986 |
} else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) { |
1986 | 1987 |
env->exception_index = EXCP_EXTERNAL; |
1988 |
/* Taking an external interrupt does not clear the external |
|
1989 |
* interrupt status |
|
1990 |
*/ |
|
1991 |
#if 0 |
|
1987 | 1992 |
env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT); |
1993 |
#endif |
|
1988 | 1994 |
raised = 1; |
1989 | 1995 |
} |
1990 | 1996 |
#if 0 // TODO |
... | ... | |
1999 | 2005 |
env->error_code = 0; |
2000 | 2006 |
do_interrupt(env); |
2001 | 2007 |
} |
2002 |
|
|
2003 |
return raised; |
|
2004 | 2008 |
} |
2005 | 2009 |
#endif /* !CONFIG_USER_ONLY */ |
b/target-ppc/translate_init.c | ||
---|---|---|
35 | 35 |
uint64_t msr_mask; |
36 | 36 |
}; |
37 | 37 |
|
38 |
/* For user-mode emulation, we don't emulate any IRQ controller */ |
|
39 |
#if defined(CONFIG_USER_ONLY) |
|
40 |
#define PPC_IRQ_INIT_FN(name) \ |
|
41 |
static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \ |
|
42 |
{ \ |
|
43 |
} |
|
44 |
#else |
|
45 |
#define PPC_IRQ_INIT_FN(name) \ |
|
46 |
void glue(glue(ppc, name),_irq_init) (CPUPPCState *env); |
|
47 |
#endif |
|
48 |
PPC_IRQ_INIT_FN(6xx); |
|
49 |
|
|
38 | 50 |
/* Generic callbacks: |
39 | 51 |
* do nothing but store/retrieve spr value |
40 | 52 |
*/ |
... | ... | |
1865 | 1877 |
env->nb_tlb = 64; |
1866 | 1878 |
env->nb_ways = 1; |
1867 | 1879 |
env->id_tlbs = 0; |
1880 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1868 | 1881 |
break; |
1869 | 1882 |
|
1870 | 1883 |
case CPU_PPC_403GA: /* 403 GA family */ |
... | ... | |
1879 | 1892 |
env->nb_tlb = 64; |
1880 | 1893 |
env->nb_ways = 1; |
1881 | 1894 |
env->id_tlbs = 0; |
1895 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1882 | 1896 |
break; |
1883 | 1897 |
|
1884 | 1898 |
case CPU_PPC_405CR: /* 405 GP/CR family */ |
... | ... | |
1895 | 1909 |
env->nb_tlb = 64; |
1896 | 1910 |
env->nb_ways = 1; |
1897 | 1911 |
env->id_tlbs = 0; |
1912 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1898 | 1913 |
break; |
1899 | 1914 |
|
1900 | 1915 |
case CPU_PPC_NPE405H: /* NPe405 H family */ |
... | ... | |
1909 | 1924 |
env->nb_tlb = 64; |
1910 | 1925 |
env->nb_ways = 1; |
1911 | 1926 |
env->id_tlbs = 0; |
1927 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1912 | 1928 |
break; |
1913 | 1929 |
|
1914 | 1930 |
#if defined (TODO) |
... | ... | |
1940 | 1956 |
env->nb_tlb = 64; |
1941 | 1957 |
env->nb_ways = 1; |
1942 | 1958 |
env->id_tlbs = 0; |
1959 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1943 | 1960 |
break; |
1944 | 1961 |
|
1945 | 1962 |
case CPU_PPC_440EP: /* 440 EP family */ |
... | ... | |
1959 | 1976 |
env->nb_tlb = 64; |
1960 | 1977 |
env->nb_ways = 1; |
1961 | 1978 |
env->id_tlbs = 0; |
1979 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1962 | 1980 |
break; |
1963 | 1981 |
|
1964 | 1982 |
/* Embedded PowerPC from Freescale */ |
... | ... | |
1994 | 2012 |
env->nb_tlb = 64; |
1995 | 2013 |
env->nb_ways = 1; |
1996 | 2014 |
env->id_tlbs = 0; |
2015 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
1997 | 2016 |
break; |
1998 | 2017 |
|
1999 | 2018 |
#if defined (TODO) |
... | ... | |
2038 | 2057 |
env->nb_ways = 2; |
2039 | 2058 |
env->id_tlbs = 0; |
2040 | 2059 |
env->id_tlbs = 0; |
2060 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
2041 | 2061 |
break; |
2042 | 2062 |
|
2043 | 2063 |
case CPU_PPC_602: /* PowerPC 602 */ |
... | ... | |
2060 | 2080 |
SPR_NOACCESS, SPR_NOACCESS, |
2061 | 2081 |
&spr_read_generic, &spr_write_generic, |
2062 | 2082 |
0x00000000); |
2083 |
/* Allocate hardware IRQ controller */ |
|
2084 |
ppc6xx_irq_init(env); |
|
2063 | 2085 |
break; |
2064 | 2086 |
|
2065 | 2087 |
case CPU_PPC_603: /* PowerPC 603 */ |
... | ... | |
2087 | 2109 |
SPR_NOACCESS, SPR_NOACCESS, |
2088 | 2110 |
&spr_read_generic, &spr_write_generic, |
2089 | 2111 |
0x00000000); |
2112 |
/* Allocate hardware IRQ controller */ |
|
2113 |
ppc6xx_irq_init(env); |
|
2090 | 2114 |
break; |
2091 | 2115 |
|
2092 | 2116 |
case CPU_PPC_G2: /* PowerPC G2 family */ |
... | ... | |
2123 | 2147 |
SPR_NOACCESS, SPR_NOACCESS, |
2124 | 2148 |
&spr_read_generic, &spr_write_generic, |
2125 | 2149 |
0x00000000); |
2150 |
/* Allocate hardware IRQ controller */ |
|
2151 |
ppc6xx_irq_init(env); |
|
2126 | 2152 |
break; |
2127 | 2153 |
|
2128 | 2154 |
case CPU_PPC_604: /* PowerPC 604 */ |
... | ... | |
2146 | 2172 |
SPR_NOACCESS, SPR_NOACCESS, |
2147 | 2173 |
&spr_read_generic, &spr_write_generic, |
2148 | 2174 |
0x00000000); |
2175 |
/* Allocate hardware IRQ controller */ |
|
2176 |
ppc6xx_irq_init(env); |
|
2149 | 2177 |
break; |
2150 | 2178 |
|
2151 | 2179 |
case CPU_PPC_74x: /* PowerPC 740 / 750 */ |
... | ... | |
2178 | 2206 |
SPR_NOACCESS, SPR_NOACCESS, |
2179 | 2207 |
&spr_read_generic, &spr_write_generic, |
2180 | 2208 |
0x00000000); |
2209 |
/* Allocate hardware IRQ controller */ |
|
2210 |
ppc6xx_irq_init(env); |
|
2181 | 2211 |
break; |
2182 | 2212 |
|
2183 | 2213 |
case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */ |
... | ... | |
2213 | 2243 |
SPR_NOACCESS, SPR_NOACCESS, |
2214 | 2244 |
&spr_read_generic, &spr_write_generic, |
2215 | 2245 |
0x00000000); |
2246 |
/* Allocate hardware IRQ controller */ |
|
2247 |
ppc6xx_irq_init(env); |
|
2216 | 2248 |
break; |
2217 | 2249 |
|
2218 | 2250 |
case CPU_PPC_755_10: /* PowerPC 755 */ |
... | ... | |
2257 | 2289 |
SPR_NOACCESS, SPR_NOACCESS, |
2258 | 2290 |
&spr_read_generic, &spr_write_generic, |
2259 | 2291 |
0x00000000); |
2292 |
/* Allocate hardware IRQ controller */ |
|
2293 |
ppc6xx_irq_init(env); |
|
2260 | 2294 |
break; |
2261 | 2295 |
|
2262 | 2296 |
#if defined (TODO) |
... | ... | |
2326 | 2360 |
|
2327 | 2361 |
default: |
2328 | 2362 |
gen_spr_generic(env); |
2363 |
/* XXX: TODO: allocate internal IRQ controller */ |
|
2329 | 2364 |
break; |
2330 | 2365 |
} |
2331 | 2366 |
if (env->nb_BATs == -1) |
b/vl.h | ||
---|---|---|
854 | 854 |
int piix4_init(PCIBus *bus, int devfn); |
855 | 855 |
|
856 | 856 |
/* openpic.c */ |
857 |
/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ |
|
857 | 858 |
enum { |
858 |
OPENPIC_EVT_INT = 0, /* IRQ */ |
|
859 |
OPENPIC_EVT_CINT, /* critical IRQ */ |
|
860 |
OPENPIC_EVT_MCK, /* Machine check event */ |
|
861 |
OPENPIC_EVT_DEBUG, /* Inconditional debug event */ |
|
862 |
OPENPIC_EVT_RESET, /* Core reset event */ |
|
859 |
OPENPIC_OUTPUT_INT = 0, /* IRQ */ |
|
860 |
OPENPIC_OUTPUT_CINT, /* critical IRQ */ |
|
861 |
OPENPIC_OUTPUT_MCK, /* Machine check event */ |
|
862 |
OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ |
|
863 |
OPENPIC_OUTPUT_RESET, /* Core reset event */ |
|
864 |
OPENPIC_OUTPUT_NB, |
|
863 | 865 |
}; |
864 |
qemu_irq *openpic_init (PCIBus *bus, SetIRQFunc *set_irq, |
|
865 |
int *pmem_index, int nb_cpus, |
|
866 |
struct CPUState **envp); |
|
866 |
qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, |
|
867 |
qemu_irq **irqs, qemu_irq irq_out); |
|
867 | 868 |
|
868 | 869 |
/* heathrow_pic.c */ |
869 | 870 |
qemu_irq *heathrow_pic_init(int *pmem_index); |
... | ... | |
1145 | 1146 |
|
1146 | 1147 |
#ifdef TARGET_PPC |
1147 | 1148 |
/* PowerPC hardware exceptions management helpers */ |
1148 |
void cpu_ppc_irq_init_cpu(CPUState *env); |
|
1149 |
void ppc_openpic_irq (void *opaque, int n_IRQ, int level); |
|
1150 |
int ppc_hw_interrupt (CPUState *env); |
|
1151 | 1149 |
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq); |
1152 | 1150 |
#endif |
1153 | 1151 |
void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val); |
Also available in: Unified diff