]>
Commit | Line | Data |
---|---|---|
008ff9d7 JM |
1 | /* |
2 | * QEMU PowerPC 4xx embedded processors shared devices emulation | |
3 | * | |
4 | * Copyright (c) 2007 Jocelyn Mayer | |
5 | * | |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | * of this software and associated documentation files (the "Software"), to deal | |
8 | * in the Software without restriction, including without limitation the rights | |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | * copies of the Software, and to permit persons to whom the Software is | |
11 | * furnished to do so, subject to the following conditions: | |
12 | * | |
13 | * The above copyright notice and this permission notice shall be included in | |
14 | * all copies or substantial portions of the Software. | |
15 | * | |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | * THE SOFTWARE. | |
23 | */ | |
87ecb68b PB |
24 | #include "hw.h" |
25 | #include "ppc.h" | |
008ff9d7 | 26 | #include "ppc4xx.h" |
87ecb68b | 27 | #include "sysemu.h" |
008ff9d7 JM |
28 | |
29 | extern int loglevel; | |
30 | extern FILE *logfile; | |
31 | ||
32 | //#define DEBUG_MMIO | |
aae9366a | 33 | //#define DEBUG_UNASSIGNED |
008ff9d7 JM |
34 | #define DEBUG_UIC |
35 | ||
36 | /*****************************************************************************/ | |
37 | /* Generic PowerPC 4xx processor instanciation */ | |
38 | CPUState *ppc4xx_init (const unsigned char *cpu_model, | |
39 | clk_setup_t *cpu_clk, clk_setup_t *tb_clk, | |
40 | uint32_t sysclk) | |
41 | { | |
42 | CPUState *env; | |
008ff9d7 JM |
43 | |
44 | /* init CPUs */ | |
aaed909a FB |
45 | env = cpu_init(cpu_model); |
46 | if (!env) { | |
47 | fprintf(stderr, "Unable to find PowerPC %s CPU definition\n", | |
48 | cpu_model); | |
49 | exit(1); | |
008ff9d7 | 50 | } |
008ff9d7 JM |
51 | cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */ |
52 | cpu_clk->opaque = env; | |
53 | /* Set time-base frequency to sysclk */ | |
54 | tb_clk->cb = ppc_emb_timers_init(env, sysclk); | |
55 | tb_clk->opaque = env; | |
56 | ppc_dcr_init(env, NULL, NULL); | |
57 | /* Register qemu callbacks */ | |
58 | qemu_register_reset(&cpu_ppc_reset, env); | |
008ff9d7 JM |
59 | |
60 | return env; | |
61 | } | |
62 | ||
63 | /*****************************************************************************/ | |
64 | /* Fake device used to map multiple devices in a single memory page */ | |
65 | #define MMIO_AREA_BITS 8 | |
66 | #define MMIO_AREA_LEN (1 << MMIO_AREA_BITS) | |
67 | #define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS)) | |
68 | #define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1)) | |
69 | struct ppc4xx_mmio_t { | |
70 | target_phys_addr_t base; | |
71 | CPUReadMemoryFunc **mem_read[MMIO_AREA_NB]; | |
72 | CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB]; | |
73 | void *opaque[MMIO_AREA_NB]; | |
74 | }; | |
75 | ||
76 | static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr) | |
77 | { | |
78 | #ifdef DEBUG_UNASSIGNED | |
79 | ppc4xx_mmio_t *mmio; | |
80 | ||
81 | mmio = opaque; | |
82 | printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n", | |
83 | addr, mmio->base); | |
84 | #endif | |
85 | ||
86 | return 0; | |
87 | } | |
88 | ||
89 | static void unassigned_mmio_writeb (void *opaque, | |
90 | target_phys_addr_t addr, uint32_t val) | |
91 | { | |
92 | #ifdef DEBUG_UNASSIGNED | |
93 | ppc4xx_mmio_t *mmio; | |
94 | ||
95 | mmio = opaque; | |
96 | printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n", | |
97 | addr, val, mmio->base); | |
98 | #endif | |
99 | } | |
100 | ||
101 | static CPUReadMemoryFunc *unassigned_mmio_read[3] = { | |
102 | unassigned_mmio_readb, | |
103 | unassigned_mmio_readb, | |
104 | unassigned_mmio_readb, | |
105 | }; | |
106 | ||
107 | static CPUWriteMemoryFunc *unassigned_mmio_write[3] = { | |
108 | unassigned_mmio_writeb, | |
109 | unassigned_mmio_writeb, | |
110 | unassigned_mmio_writeb, | |
111 | }; | |
112 | ||
113 | static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio, | |
114 | target_phys_addr_t addr, int len) | |
115 | { | |
116 | CPUReadMemoryFunc **mem_read; | |
117 | uint32_t ret; | |
118 | int idx; | |
119 | ||
120 | idx = MMIO_IDX(addr - mmio->base); | |
121 | #if defined(DEBUG_MMIO) | |
122 | printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__, | |
123 | mmio, len, addr, idx); | |
124 | #endif | |
125 | mem_read = mmio->mem_read[idx]; | |
126 | ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base); | |
127 | ||
128 | return ret; | |
129 | } | |
130 | ||
131 | static void mmio_writelen (ppc4xx_mmio_t *mmio, | |
132 | target_phys_addr_t addr, uint32_t value, int len) | |
133 | { | |
134 | CPUWriteMemoryFunc **mem_write; | |
135 | int idx; | |
136 | ||
137 | idx = MMIO_IDX(addr - mmio->base); | |
138 | #if defined(DEBUG_MMIO) | |
aae9366a JM |
139 | printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08" PRIx32 "\n", |
140 | __func__, mmio, len, addr, idx, value); | |
008ff9d7 JM |
141 | #endif |
142 | mem_write = mmio->mem_write[idx]; | |
143 | (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value); | |
144 | } | |
145 | ||
146 | static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr) | |
147 | { | |
148 | #if defined(DEBUG_MMIO) | |
149 | printf("%s: addr " PADDRX "\n", __func__, addr); | |
150 | #endif | |
151 | ||
152 | return mmio_readlen(opaque, addr, 0); | |
153 | } | |
154 | ||
155 | static void mmio_writeb (void *opaque, | |
156 | target_phys_addr_t addr, uint32_t value) | |
157 | { | |
158 | #if defined(DEBUG_MMIO) | |
aae9366a | 159 | printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); |
008ff9d7 JM |
160 | #endif |
161 | mmio_writelen(opaque, addr, value, 0); | |
162 | } | |
163 | ||
164 | static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr) | |
165 | { | |
166 | #if defined(DEBUG_MMIO) | |
167 | printf("%s: addr " PADDRX "\n", __func__, addr); | |
168 | #endif | |
169 | ||
170 | return mmio_readlen(opaque, addr, 1); | |
171 | } | |
172 | ||
173 | static void mmio_writew (void *opaque, | |
174 | target_phys_addr_t addr, uint32_t value) | |
175 | { | |
176 | #if defined(DEBUG_MMIO) | |
aae9366a | 177 | printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); |
008ff9d7 JM |
178 | #endif |
179 | mmio_writelen(opaque, addr, value, 1); | |
180 | } | |
181 | ||
182 | static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr) | |
183 | { | |
184 | #if defined(DEBUG_MMIO) | |
185 | printf("%s: addr " PADDRX "\n", __func__, addr); | |
186 | #endif | |
187 | ||
188 | return mmio_readlen(opaque, addr, 2); | |
189 | } | |
190 | ||
191 | static void mmio_writel (void *opaque, | |
192 | target_phys_addr_t addr, uint32_t value) | |
193 | { | |
194 | #if defined(DEBUG_MMIO) | |
aae9366a | 195 | printf("%s: addr " PADDRX " val %08" PRIx32 "\n", __func__, addr, value); |
008ff9d7 JM |
196 | #endif |
197 | mmio_writelen(opaque, addr, value, 2); | |
198 | } | |
199 | ||
200 | static CPUReadMemoryFunc *mmio_read[] = { | |
201 | &mmio_readb, | |
202 | &mmio_readw, | |
203 | &mmio_readl, | |
204 | }; | |
205 | ||
206 | static CPUWriteMemoryFunc *mmio_write[] = { | |
207 | &mmio_writeb, | |
208 | &mmio_writew, | |
209 | &mmio_writel, | |
210 | }; | |
211 | ||
212 | int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio, | |
213 | target_phys_addr_t offset, uint32_t len, | |
214 | CPUReadMemoryFunc **mem_read, | |
215 | CPUWriteMemoryFunc **mem_write, void *opaque) | |
216 | { | |
aae9366a | 217 | target_phys_addr_t end; |
008ff9d7 JM |
218 | int idx, eidx; |
219 | ||
220 | if ((offset + len) > TARGET_PAGE_SIZE) | |
221 | return -1; | |
222 | idx = MMIO_IDX(offset); | |
223 | end = offset + len - 1; | |
224 | eidx = MMIO_IDX(end); | |
225 | #if defined(DEBUG_MMIO) | |
aae9366a JM |
226 | printf("%s: offset " PADDRX " len %08" PRIx32 " " PADDRX " %d %d\n", |
227 | __func__, offset, len, end, idx, eidx); | |
008ff9d7 JM |
228 | #endif |
229 | for (; idx <= eidx; idx++) { | |
230 | mmio->mem_read[idx] = mem_read; | |
231 | mmio->mem_write[idx] = mem_write; | |
232 | mmio->opaque[idx] = opaque; | |
233 | } | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base) | |
239 | { | |
240 | ppc4xx_mmio_t *mmio; | |
241 | int mmio_memory; | |
242 | ||
243 | mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t)); | |
244 | if (mmio != NULL) { | |
245 | mmio->base = base; | |
246 | mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio); | |
247 | #if defined(DEBUG_MMIO) | |
aae9366a JM |
248 | printf("%s: base " PADDRX " len %08x %d\n", __func__, |
249 | base, TARGET_PAGE_SIZE, mmio_memory); | |
008ff9d7 JM |
250 | #endif |
251 | cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory); | |
252 | ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE, | |
253 | unassigned_mmio_read, unassigned_mmio_write, | |
254 | mmio); | |
255 | } | |
256 | ||
257 | return mmio; | |
258 | } | |
259 | ||
260 | /*****************************************************************************/ | |
261 | /* "Universal" Interrupt controller */ | |
262 | enum { | |
263 | DCR_UICSR = 0x000, | |
264 | DCR_UICSRS = 0x001, | |
265 | DCR_UICER = 0x002, | |
266 | DCR_UICCR = 0x003, | |
267 | DCR_UICPR = 0x004, | |
268 | DCR_UICTR = 0x005, | |
269 | DCR_UICMSR = 0x006, | |
270 | DCR_UICVR = 0x007, | |
271 | DCR_UICVCR = 0x008, | |
272 | DCR_UICMAX = 0x009, | |
273 | }; | |
274 | ||
275 | #define UIC_MAX_IRQ 32 | |
276 | typedef struct ppcuic_t ppcuic_t; | |
277 | struct ppcuic_t { | |
278 | uint32_t dcr_base; | |
279 | int use_vectors; | |
4c54e875 | 280 | uint32_t level; /* Remembers the state of level-triggered interrupts. */ |
008ff9d7 JM |
281 | uint32_t uicsr; /* Status register */ |
282 | uint32_t uicer; /* Enable register */ | |
283 | uint32_t uiccr; /* Critical register */ | |
284 | uint32_t uicpr; /* Polarity register */ | |
285 | uint32_t uictr; /* Triggering register */ | |
286 | uint32_t uicvcr; /* Vector configuration register */ | |
287 | uint32_t uicvr; | |
288 | qemu_irq *irqs; | |
289 | }; | |
290 | ||
291 | static void ppcuic_trigger_irq (ppcuic_t *uic) | |
292 | { | |
293 | uint32_t ir, cr; | |
294 | int start, end, inc, i; | |
295 | ||
296 | /* Trigger interrupt if any is pending */ | |
297 | ir = uic->uicsr & uic->uicer & (~uic->uiccr); | |
298 | cr = uic->uicsr & uic->uicer & uic->uiccr; | |
299 | #ifdef DEBUG_UIC | |
300 | if (loglevel & CPU_LOG_INT) { | |
aae9366a JM |
301 | fprintf(logfile, "%s: uicsr %08" PRIx32 " uicer %08" PRIx32 |
302 | " uiccr %08" PRIx32 "\n" | |
303 | " %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n", | |
304 | __func__, uic->uicsr, uic->uicer, uic->uiccr, | |
008ff9d7 JM |
305 | uic->uicsr & uic->uicer, ir, cr); |
306 | } | |
307 | #endif | |
308 | if (ir != 0x0000000) { | |
309 | #ifdef DEBUG_UIC | |
310 | if (loglevel & CPU_LOG_INT) { | |
311 | fprintf(logfile, "Raise UIC interrupt\n"); | |
312 | } | |
313 | #endif | |
314 | qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]); | |
315 | } else { | |
316 | #ifdef DEBUG_UIC | |
317 | if (loglevel & CPU_LOG_INT) { | |
318 | fprintf(logfile, "Lower UIC interrupt\n"); | |
319 | } | |
320 | #endif | |
321 | qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]); | |
322 | } | |
323 | /* Trigger critical interrupt if any is pending and update vector */ | |
324 | if (cr != 0x0000000) { | |
325 | qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]); | |
326 | if (uic->use_vectors) { | |
327 | /* Compute critical IRQ vector */ | |
328 | if (uic->uicvcr & 1) { | |
329 | start = 31; | |
330 | end = 0; | |
331 | inc = -1; | |
332 | } else { | |
333 | start = 0; | |
334 | end = 31; | |
335 | inc = 1; | |
336 | } | |
337 | uic->uicvr = uic->uicvcr & 0xFFFFFFFC; | |
338 | for (i = start; i <= end; i += inc) { | |
339 | if (cr & (1 << i)) { | |
340 | uic->uicvr += (i - start) * 512 * inc; | |
341 | break; | |
342 | } | |
343 | } | |
344 | } | |
345 | #ifdef DEBUG_UIC | |
346 | if (loglevel & CPU_LOG_INT) { | |
aae9366a JM |
347 | fprintf(logfile, "Raise UIC critical interrupt - " |
348 | "vector %08" PRIx32 "\n", uic->uicvr); | |
008ff9d7 JM |
349 | } |
350 | #endif | |
351 | } else { | |
352 | #ifdef DEBUG_UIC | |
353 | if (loglevel & CPU_LOG_INT) { | |
354 | fprintf(logfile, "Lower UIC critical interrupt\n"); | |
355 | } | |
356 | #endif | |
357 | qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]); | |
358 | uic->uicvr = 0x00000000; | |
359 | } | |
360 | } | |
361 | ||
362 | static void ppcuic_set_irq (void *opaque, int irq_num, int level) | |
363 | { | |
364 | ppcuic_t *uic; | |
365 | uint32_t mask, sr; | |
366 | ||
367 | uic = opaque; | |
923e5e33 | 368 | mask = 1 << (31-irq_num); |
008ff9d7 JM |
369 | #ifdef DEBUG_UIC |
370 | if (loglevel & CPU_LOG_INT) { | |
aae9366a JM |
371 | fprintf(logfile, "%s: irq %d level %d uicsr %08" PRIx32 |
372 | " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n", | |
373 | __func__, irq_num, level, | |
008ff9d7 JM |
374 | uic->uicsr, mask, uic->uicsr & mask, level << irq_num); |
375 | } | |
376 | #endif | |
377 | if (irq_num < 0 || irq_num > 31) | |
378 | return; | |
379 | sr = uic->uicsr; | |
50bf72b3 | 380 | |
008ff9d7 JM |
381 | /* Update status register */ |
382 | if (uic->uictr & mask) { | |
383 | /* Edge sensitive interrupt */ | |
384 | if (level == 1) | |
385 | uic->uicsr |= mask; | |
386 | } else { | |
387 | /* Level sensitive interrupt */ | |
4c54e875 | 388 | if (level == 1) { |
008ff9d7 | 389 | uic->uicsr |= mask; |
4c54e875 AJ |
390 | uic->level |= mask; |
391 | } else { | |
008ff9d7 | 392 | uic->uicsr &= ~mask; |
4c54e875 AJ |
393 | uic->level &= ~mask; |
394 | } | |
008ff9d7 JM |
395 | } |
396 | #ifdef DEBUG_UIC | |
397 | if (loglevel & CPU_LOG_INT) { | |
aae9366a JM |
398 | fprintf(logfile, "%s: irq %d level %d sr %" PRIx32 " => " |
399 | "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr); | |
008ff9d7 JM |
400 | } |
401 | #endif | |
402 | if (sr != uic->uicsr) | |
403 | ppcuic_trigger_irq(uic); | |
404 | } | |
405 | ||
406 | static target_ulong dcr_read_uic (void *opaque, int dcrn) | |
407 | { | |
408 | ppcuic_t *uic; | |
409 | target_ulong ret; | |
410 | ||
411 | uic = opaque; | |
412 | dcrn -= uic->dcr_base; | |
413 | switch (dcrn) { | |
414 | case DCR_UICSR: | |
415 | case DCR_UICSRS: | |
416 | ret = uic->uicsr; | |
417 | break; | |
418 | case DCR_UICER: | |
419 | ret = uic->uicer; | |
420 | break; | |
421 | case DCR_UICCR: | |
422 | ret = uic->uiccr; | |
423 | break; | |
424 | case DCR_UICPR: | |
425 | ret = uic->uicpr; | |
426 | break; | |
427 | case DCR_UICTR: | |
428 | ret = uic->uictr; | |
429 | break; | |
430 | case DCR_UICMSR: | |
431 | ret = uic->uicsr & uic->uicer; | |
432 | break; | |
433 | case DCR_UICVR: | |
434 | if (!uic->use_vectors) | |
435 | goto no_read; | |
436 | ret = uic->uicvr; | |
437 | break; | |
438 | case DCR_UICVCR: | |
439 | if (!uic->use_vectors) | |
440 | goto no_read; | |
441 | ret = uic->uicvcr; | |
442 | break; | |
443 | default: | |
444 | no_read: | |
445 | ret = 0x00000000; | |
446 | break; | |
447 | } | |
448 | ||
449 | return ret; | |
450 | } | |
451 | ||
452 | static void dcr_write_uic (void *opaque, int dcrn, target_ulong val) | |
453 | { | |
454 | ppcuic_t *uic; | |
455 | ||
456 | uic = opaque; | |
457 | dcrn -= uic->dcr_base; | |
458 | #ifdef DEBUG_UIC | |
459 | if (loglevel & CPU_LOG_INT) { | |
460 | fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val); | |
461 | } | |
462 | #endif | |
463 | switch (dcrn) { | |
464 | case DCR_UICSR: | |
465 | uic->uicsr &= ~val; | |
4c54e875 | 466 | uic->uicsr |= uic->level; |
008ff9d7 JM |
467 | ppcuic_trigger_irq(uic); |
468 | break; | |
469 | case DCR_UICSRS: | |
470 | uic->uicsr |= val; | |
471 | ppcuic_trigger_irq(uic); | |
472 | break; | |
473 | case DCR_UICER: | |
474 | uic->uicer = val; | |
475 | ppcuic_trigger_irq(uic); | |
476 | break; | |
477 | case DCR_UICCR: | |
478 | uic->uiccr = val; | |
479 | ppcuic_trigger_irq(uic); | |
480 | break; | |
481 | case DCR_UICPR: | |
482 | uic->uicpr = val; | |
008ff9d7 JM |
483 | break; |
484 | case DCR_UICTR: | |
485 | uic->uictr = val; | |
486 | ppcuic_trigger_irq(uic); | |
487 | break; | |
488 | case DCR_UICMSR: | |
489 | break; | |
490 | case DCR_UICVR: | |
491 | break; | |
492 | case DCR_UICVCR: | |
493 | uic->uicvcr = val & 0xFFFFFFFD; | |
494 | ppcuic_trigger_irq(uic); | |
495 | break; | |
496 | } | |
497 | } | |
498 | ||
499 | static void ppcuic_reset (void *opaque) | |
500 | { | |
501 | ppcuic_t *uic; | |
502 | ||
503 | uic = opaque; | |
504 | uic->uiccr = 0x00000000; | |
505 | uic->uicer = 0x00000000; | |
506 | uic->uicpr = 0x00000000; | |
507 | uic->uicsr = 0x00000000; | |
508 | uic->uictr = 0x00000000; | |
509 | if (uic->use_vectors) { | |
510 | uic->uicvcr = 0x00000000; | |
511 | uic->uicvr = 0x0000000; | |
512 | } | |
513 | } | |
514 | ||
515 | qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs, | |
516 | uint32_t dcr_base, int has_ssr, int has_vr) | |
517 | { | |
518 | ppcuic_t *uic; | |
519 | int i; | |
520 | ||
521 | uic = qemu_mallocz(sizeof(ppcuic_t)); | |
522 | if (uic != NULL) { | |
523 | uic->dcr_base = dcr_base; | |
524 | uic->irqs = irqs; | |
525 | if (has_vr) | |
526 | uic->use_vectors = 1; | |
527 | for (i = 0; i < DCR_UICMAX; i++) { | |
528 | ppc_dcr_register(env, dcr_base + i, uic, | |
529 | &dcr_read_uic, &dcr_write_uic); | |
530 | } | |
531 | qemu_register_reset(ppcuic_reset, uic); | |
532 | ppcuic_reset(uic); | |
533 | } | |
534 | ||
535 | return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ); | |
536 | } |