]>
Commit | Line | Data |
---|---|---|
e80cfcfc FB |
1 | /* |
2 | * QEMU Sparc SLAVIO interrupt controller emulation | |
5fafdf24 | 3 | * |
66321a11 | 4 | * Copyright (c) 2003-2005 Fabrice Bellard |
5fafdf24 | 5 | * |
e80cfcfc FB |
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 | */ | |
a1961a4b | 24 | |
87ecb68b | 25 | #include "sun4m.h" |
376253ec | 26 | #include "monitor.h" |
a1961a4b | 27 | #include "sysbus.h" |
87ecb68b | 28 | |
e80cfcfc | 29 | //#define DEBUG_IRQ_COUNT |
66321a11 FB |
30 | //#define DEBUG_IRQ |
31 | ||
32 | #ifdef DEBUG_IRQ | |
001faf32 BS |
33 | #define DPRINTF(fmt, ...) \ |
34 | do { printf("IRQ: " fmt , ## __VA_ARGS__); } while (0) | |
66321a11 | 35 | #else |
001faf32 | 36 | #define DPRINTF(fmt, ...) |
66321a11 | 37 | #endif |
e80cfcfc FB |
38 | |
39 | /* | |
40 | * Registers of interrupt controller in sun4m. | |
41 | * | |
42 | * This is the interrupt controller part of chip STP2001 (Slave I/O), also | |
43 | * produced as NCR89C105. See | |
44 | * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt | |
45 | * | |
46 | * There is a system master controller and one for each cpu. | |
5fafdf24 | 47 | * |
e80cfcfc FB |
48 | */ |
49 | ||
50 | #define MAX_CPUS 16 | |
b3a23197 | 51 | #define MAX_PILS 16 |
e80cfcfc | 52 | |
a1961a4b BS |
53 | struct SLAVIO_INTCTLState; |
54 | ||
55 | typedef struct SLAVIO_CPUINTCTLState { | |
56 | uint32_t intreg_pending; | |
57 | struct SLAVIO_INTCTLState *master; | |
58 | uint32_t cpu; | |
59 | } SLAVIO_CPUINTCTLState; | |
a8f48dcc | 60 | |
e80cfcfc | 61 | typedef struct SLAVIO_INTCTLState { |
a1961a4b | 62 | SysBusDevice busdev; |
e80cfcfc FB |
63 | uint32_t intregm_pending; |
64 | uint32_t intregm_disabled; | |
65 | uint32_t target_cpu; | |
66 | #ifdef DEBUG_IRQ_COUNT | |
67 | uint64_t irq_count[32]; | |
68 | #endif | |
a1961a4b | 69 | qemu_irq cpu_irqs[MAX_CPUS][MAX_PILS]; |
e0353fe2 | 70 | const uint32_t *intbit_to_level; |
e3a79bca | 71 | uint32_t cputimer_lbit, cputimer_mbit; |
ee6847d1 | 72 | uint32_t cputimer_bit; |
b3a23197 | 73 | uint32_t pil_out[MAX_CPUS]; |
a1961a4b | 74 | SLAVIO_CPUINTCTLState slaves[MAX_CPUS]; |
e80cfcfc FB |
75 | } SLAVIO_INTCTLState; |
76 | ||
77 | #define INTCTL_MAXADDR 0xf | |
5aca8c3b | 78 | #define INTCTL_SIZE (INTCTL_MAXADDR + 1) |
a8f48dcc | 79 | #define INTCTLM_SIZE 0x14 |
80be36b8 | 80 | #define MASTER_IRQ_MASK ~0x0fa2007f |
9a87ce9b | 81 | #define MASTER_DISABLE 0x80000000 |
6341fdcb | 82 | #define CPU_SOFTIRQ_MASK 0xfffe0000 |
9a87ce9b BS |
83 | #define CPU_IRQ_INT15_IN 0x0004000 |
84 | #define CPU_IRQ_INT15_MASK 0x80000000 | |
85 | ||
0d0a7e69 | 86 | static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs); |
e80cfcfc FB |
87 | |
88 | // per-cpu interrupt controller | |
89 | static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) | |
90 | { | |
a8f48dcc | 91 | SLAVIO_CPUINTCTLState *s = opaque; |
dd4131b3 | 92 | uint32_t saddr, ret; |
e80cfcfc | 93 | |
a8f48dcc | 94 | saddr = addr >> 2; |
e80cfcfc FB |
95 | switch (saddr) { |
96 | case 0: | |
a8f48dcc | 97 | ret = s->intreg_pending; |
dd4131b3 | 98 | break; |
e80cfcfc | 99 | default: |
dd4131b3 BS |
100 | ret = 0; |
101 | break; | |
e80cfcfc | 102 | } |
3c4cf535 | 103 | DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, ret); |
dd4131b3 BS |
104 | |
105 | return ret; | |
e80cfcfc FB |
106 | } |
107 | ||
77f193da BS |
108 | static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, |
109 | uint32_t val) | |
e80cfcfc | 110 | { |
a8f48dcc | 111 | SLAVIO_CPUINTCTLState *s = opaque; |
e80cfcfc | 112 | uint32_t saddr; |
e80cfcfc | 113 | |
a8f48dcc | 114 | saddr = addr >> 2; |
3c4cf535 | 115 | DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", s->cpu, addr, val); |
e80cfcfc FB |
116 | switch (saddr) { |
117 | case 1: // clear pending softints | |
9a87ce9b BS |
118 | if (val & CPU_IRQ_INT15_IN) |
119 | val |= CPU_IRQ_INT15_MASK; | |
6341fdcb | 120 | val &= CPU_SOFTIRQ_MASK; |
a8f48dcc | 121 | s->intreg_pending &= ~val; |
0d0a7e69 | 122 | slavio_check_interrupts(s->master, 1); |
a8f48dcc BS |
123 | DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", s->cpu, val, |
124 | s->intreg_pending); | |
f930d07e | 125 | break; |
e80cfcfc | 126 | case 2: // set softint |
6341fdcb | 127 | val &= CPU_SOFTIRQ_MASK; |
a8f48dcc | 128 | s->intreg_pending |= val; |
0d0a7e69 | 129 | slavio_check_interrupts(s->master, 1); |
a8f48dcc BS |
130 | DPRINTF("Set cpu %d irq mask %x, curmask %x\n", s->cpu, val, |
131 | s->intreg_pending); | |
f930d07e | 132 | break; |
e80cfcfc | 133 | default: |
f930d07e | 134 | break; |
e80cfcfc FB |
135 | } |
136 | } | |
137 | ||
138 | static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = { | |
7c560456 BS |
139 | NULL, |
140 | NULL, | |
e80cfcfc FB |
141 | slavio_intctl_mem_readl, |
142 | }; | |
143 | ||
144 | static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { | |
7c560456 BS |
145 | NULL, |
146 | NULL, | |
e80cfcfc FB |
147 | slavio_intctl_mem_writel, |
148 | }; | |
149 | ||
150 | // master system interrupt controller | |
151 | static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) | |
152 | { | |
153 | SLAVIO_INTCTLState *s = opaque; | |
dd4131b3 | 154 | uint32_t saddr, ret; |
e80cfcfc | 155 | |
a8f48dcc | 156 | saddr = addr >> 2; |
e80cfcfc FB |
157 | switch (saddr) { |
158 | case 0: | |
9a87ce9b | 159 | ret = s->intregm_pending & ~MASTER_DISABLE; |
dd4131b3 | 160 | break; |
e80cfcfc | 161 | case 1: |
80be36b8 | 162 | ret = s->intregm_disabled & MASTER_IRQ_MASK; |
dd4131b3 | 163 | break; |
e80cfcfc | 164 | case 4: |
dd4131b3 BS |
165 | ret = s->target_cpu; |
166 | break; | |
e80cfcfc | 167 | default: |
dd4131b3 BS |
168 | ret = 0; |
169 | break; | |
e80cfcfc | 170 | } |
1569fc29 | 171 | DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret); |
dd4131b3 BS |
172 | |
173 | return ret; | |
e80cfcfc FB |
174 | } |
175 | ||
77f193da BS |
176 | static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, |
177 | uint32_t val) | |
e80cfcfc FB |
178 | { |
179 | SLAVIO_INTCTLState *s = opaque; | |
180 | uint32_t saddr; | |
181 | ||
a8f48dcc | 182 | saddr = addr >> 2; |
1569fc29 | 183 | DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val); |
e80cfcfc FB |
184 | switch (saddr) { |
185 | case 2: // clear (enable) | |
f930d07e | 186 | // Force clear unused bits |
9a87ce9b | 187 | val &= MASTER_IRQ_MASK; |
f930d07e | 188 | s->intregm_disabled &= ~val; |
77f193da BS |
189 | DPRINTF("Enabled master irq mask %x, curmask %x\n", val, |
190 | s->intregm_disabled); | |
0d0a7e69 | 191 | slavio_check_interrupts(s, 1); |
f930d07e | 192 | break; |
e80cfcfc | 193 | case 3: // set (disable, clear pending) |
f930d07e | 194 | // Force clear unused bits |
9a87ce9b | 195 | val &= MASTER_IRQ_MASK; |
f930d07e BS |
196 | s->intregm_disabled |= val; |
197 | s->intregm_pending &= ~val; | |
0d0a7e69 | 198 | slavio_check_interrupts(s, 1); |
77f193da BS |
199 | DPRINTF("Disabled master irq mask %x, curmask %x\n", val, |
200 | s->intregm_disabled); | |
f930d07e | 201 | break; |
e80cfcfc | 202 | case 4: |
f930d07e | 203 | s->target_cpu = val & (MAX_CPUS - 1); |
0d0a7e69 | 204 | slavio_check_interrupts(s, 1); |
f930d07e BS |
205 | DPRINTF("Set master irq cpu %d\n", s->target_cpu); |
206 | break; | |
e80cfcfc | 207 | default: |
f930d07e | 208 | break; |
e80cfcfc FB |
209 | } |
210 | } | |
211 | ||
212 | static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = { | |
7c560456 BS |
213 | NULL, |
214 | NULL, | |
e80cfcfc FB |
215 | slavio_intctlm_mem_readl, |
216 | }; | |
217 | ||
218 | static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = { | |
7c560456 BS |
219 | NULL, |
220 | NULL, | |
e80cfcfc FB |
221 | slavio_intctlm_mem_writel, |
222 | }; | |
223 | ||
376253ec | 224 | void slavio_pic_info(Monitor *mon, void *opaque) |
e80cfcfc FB |
225 | { |
226 | SLAVIO_INTCTLState *s = opaque; | |
227 | int i; | |
228 | ||
229 | for (i = 0; i < MAX_CPUS; i++) { | |
376253ec | 230 | monitor_printf(mon, "per-cpu %d: pending 0x%08x\n", i, |
a1961a4b | 231 | s->slaves[i].intreg_pending); |
e80cfcfc | 232 | } |
376253ec AL |
233 | monitor_printf(mon, "master: pending 0x%08x, disabled 0x%08x\n", |
234 | s->intregm_pending, s->intregm_disabled); | |
e80cfcfc FB |
235 | } |
236 | ||
376253ec | 237 | void slavio_irq_info(Monitor *mon, void *opaque) |
e80cfcfc FB |
238 | { |
239 | #ifndef DEBUG_IRQ_COUNT | |
376253ec | 240 | monitor_printf(mon, "irq statistic code not compiled.\n"); |
e80cfcfc FB |
241 | #else |
242 | SLAVIO_INTCTLState *s = opaque; | |
243 | int i; | |
244 | int64_t count; | |
245 | ||
376253ec | 246 | monitor_printf(mon, "IRQ statistics:\n"); |
e80cfcfc FB |
247 | for (i = 0; i < 32; i++) { |
248 | count = s->irq_count[i]; | |
249 | if (count > 0) | |
376253ec | 250 | monitor_printf(mon, "%2d: %" PRId64 "\n", i, count); |
e80cfcfc FB |
251 | } |
252 | #endif | |
253 | } | |
254 | ||
0d0a7e69 | 255 | static void slavio_check_interrupts(SLAVIO_INTCTLState *s, int set_irqs) |
66321a11 | 256 | { |
327ac2e7 BS |
257 | uint32_t pending = s->intregm_pending, pil_pending; |
258 | unsigned int i, j; | |
66321a11 FB |
259 | |
260 | pending &= ~s->intregm_disabled; | |
261 | ||
b3a23197 | 262 | DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); |
ba3c64fb | 263 | for (i = 0; i < MAX_CPUS; i++) { |
327ac2e7 | 264 | pil_pending = 0; |
9a87ce9b | 265 | if (pending && !(s->intregm_disabled & MASTER_DISABLE) && |
b3a23197 BS |
266 | (i == s->target_cpu)) { |
267 | for (j = 0; j < 32; j++) { | |
327ac2e7 BS |
268 | if (pending & (1 << j)) |
269 | pil_pending |= 1 << s->intbit_to_level[j]; | |
b3a23197 BS |
270 | } |
271 | } | |
a1961a4b | 272 | pil_pending |= (s->slaves[i].intreg_pending & CPU_SOFTIRQ_MASK) >> 16; |
327ac2e7 | 273 | |
0d0a7e69 BS |
274 | if (set_irqs) { |
275 | for (j = 0; j < MAX_PILS; j++) { | |
276 | if (pil_pending & (1 << j)) { | |
277 | if (!(s->pil_out[i] & (1 << j))) { | |
278 | qemu_irq_raise(s->cpu_irqs[i][j]); | |
279 | } | |
280 | } else { | |
281 | if (s->pil_out[i] & (1 << j)) { | |
282 | qemu_irq_lower(s->cpu_irqs[i][j]); | |
283 | } | |
284 | } | |
ba3c64fb FB |
285 | } |
286 | } | |
327ac2e7 | 287 | s->pil_out[i] = pil_pending; |
ba3c64fb | 288 | } |
66321a11 FB |
289 | } |
290 | ||
e80cfcfc FB |
291 | /* |
292 | * "irq" here is the bit number in the system interrupt register to | |
293 | * separate serial and keyboard interrupts sharing a level. | |
294 | */ | |
d7edfd27 | 295 | static void slavio_set_irq(void *opaque, int irq, int level) |
e80cfcfc FB |
296 | { |
297 | SLAVIO_INTCTLState *s = opaque; | |
b3a23197 BS |
298 | uint32_t mask = 1 << irq; |
299 | uint32_t pil = s->intbit_to_level[irq]; | |
300 | ||
301 | DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil, | |
302 | level); | |
303 | if (pil > 0) { | |
304 | if (level) { | |
327ac2e7 BS |
305 | #ifdef DEBUG_IRQ_COUNT |
306 | s->irq_count[pil]++; | |
307 | #endif | |
b3a23197 | 308 | s->intregm_pending |= mask; |
a1961a4b | 309 | s->slaves[s->target_cpu].intreg_pending |= 1 << pil; |
b3a23197 BS |
310 | } else { |
311 | s->intregm_pending &= ~mask; | |
a1961a4b | 312 | s->slaves[s->target_cpu].intreg_pending &= ~(1 << pil); |
b3a23197 | 313 | } |
0d0a7e69 | 314 | slavio_check_interrupts(s, 1); |
e80cfcfc FB |
315 | } |
316 | } | |
317 | ||
d7edfd27 | 318 | static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level) |
ba3c64fb FB |
319 | { |
320 | SLAVIO_INTCTLState *s = opaque; | |
321 | ||
b3a23197 | 322 | DPRINTF("Set cpu %d local timer level %d\n", cpu, level); |
d7edfd27 | 323 | |
e3a79bca BS |
324 | if (level) { |
325 | s->intregm_pending |= s->cputimer_mbit; | |
a1961a4b | 326 | s->slaves[cpu].intreg_pending |= s->cputimer_lbit; |
e3a79bca BS |
327 | } else { |
328 | s->intregm_pending &= ~s->cputimer_mbit; | |
a1961a4b | 329 | s->slaves[cpu].intreg_pending &= ~s->cputimer_lbit; |
e3a79bca | 330 | } |
d7edfd27 | 331 | |
0d0a7e69 | 332 | slavio_check_interrupts(s, 1); |
ba3c64fb FB |
333 | } |
334 | ||
a1961a4b BS |
335 | static void slavio_set_irq_all(void *opaque, int irq, int level) |
336 | { | |
337 | if (irq < 32) { | |
338 | slavio_set_irq(opaque, irq, level); | |
339 | } else { | |
340 | slavio_set_timer_irq_cpu(opaque, irq - 32, level); | |
341 | } | |
342 | } | |
343 | ||
e80cfcfc FB |
344 | static void slavio_intctl_save(QEMUFile *f, void *opaque) |
345 | { | |
346 | SLAVIO_INTCTLState *s = opaque; | |
347 | int i; | |
3b46e624 | 348 | |
e80cfcfc | 349 | for (i = 0; i < MAX_CPUS; i++) { |
a1961a4b | 350 | qemu_put_be32s(f, &s->slaves[i].intreg_pending); |
e80cfcfc FB |
351 | } |
352 | qemu_put_be32s(f, &s->intregm_pending); | |
353 | qemu_put_be32s(f, &s->intregm_disabled); | |
354 | qemu_put_be32s(f, &s->target_cpu); | |
355 | } | |
356 | ||
357 | static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) | |
358 | { | |
359 | SLAVIO_INTCTLState *s = opaque; | |
360 | int i; | |
361 | ||
362 | if (version_id != 1) | |
363 | return -EINVAL; | |
364 | ||
365 | for (i = 0; i < MAX_CPUS; i++) { | |
a1961a4b | 366 | qemu_get_be32s(f, &s->slaves[i].intreg_pending); |
e80cfcfc FB |
367 | } |
368 | qemu_get_be32s(f, &s->intregm_pending); | |
369 | qemu_get_be32s(f, &s->intregm_disabled); | |
370 | qemu_get_be32s(f, &s->target_cpu); | |
0d0a7e69 | 371 | slavio_check_interrupts(s, 0); |
e80cfcfc FB |
372 | return 0; |
373 | } | |
374 | ||
375 | static void slavio_intctl_reset(void *opaque) | |
376 | { | |
377 | SLAVIO_INTCTLState *s = opaque; | |
378 | int i; | |
379 | ||
380 | for (i = 0; i < MAX_CPUS; i++) { | |
a1961a4b | 381 | s->slaves[i].intreg_pending = 0; |
e80cfcfc | 382 | } |
9a87ce9b | 383 | s->intregm_disabled = ~MASTER_IRQ_MASK; |
e80cfcfc FB |
384 | s->intregm_pending = 0; |
385 | s->target_cpu = 0; | |
0d0a7e69 | 386 | slavio_check_interrupts(s, 0); |
e80cfcfc FB |
387 | } |
388 | ||
a1961a4b | 389 | static void slavio_intctl_init1(SysBusDevice *dev) |
e80cfcfc | 390 | { |
a1961a4b | 391 | SLAVIO_INTCTLState *s = FROM_SYSBUS(SLAVIO_INTCTLState, dev); |
ee6847d1 | 392 | int io_memory; |
a1961a4b | 393 | unsigned int i, j; |
e80cfcfc | 394 | |
a1961a4b BS |
395 | qdev_init_gpio_in(&dev->qdev, slavio_set_irq_all, 32 + MAX_CPUS); |
396 | io_memory = cpu_register_io_memory(slavio_intctlm_mem_read, | |
397 | slavio_intctlm_mem_write, s); | |
398 | sysbus_init_mmio(dev, INTCTLM_SIZE, io_memory); | |
ee6847d1 GH |
399 | s->cputimer_mbit = 1 << s->cputimer_bit; |
400 | s->cputimer_lbit = 1 << s->intbit_to_level[s->cputimer_bit]; | |
e80cfcfc FB |
401 | |
402 | for (i = 0; i < MAX_CPUS; i++) { | |
a1961a4b BS |
403 | for (j = 0; j < MAX_PILS; j++) { |
404 | sysbus_init_irq(dev, &s->cpu_irqs[i][j]); | |
405 | } | |
406 | io_memory = cpu_register_io_memory(slavio_intctl_mem_read, | |
407 | slavio_intctl_mem_write, | |
408 | &s->slaves[i]); | |
409 | sysbus_init_mmio(dev, INTCTL_SIZE, io_memory); | |
410 | s->slaves[i].cpu = i; | |
411 | s->slaves[i].master = s; | |
412 | } | |
413 | register_savevm("slavio_intctl", -1, 1, slavio_intctl_save, | |
414 | slavio_intctl_load, s); | |
415 | qemu_register_reset(slavio_intctl_reset, s); | |
416 | slavio_intctl_reset(s); | |
417 | } | |
418 | ||
419 | DeviceState *slavio_intctl_init(target_phys_addr_t addr, | |
420 | target_phys_addr_t addrg, | |
421 | const uint32_t *intbit_to_level, | |
422 | qemu_irq **parent_irq, unsigned int cputimer) | |
423 | { | |
424 | DeviceState *dev; | |
425 | SysBusDevice *s; | |
426 | unsigned int i, j; | |
a8f48dcc | 427 | |
a1961a4b | 428 | dev = qdev_create(NULL, "slavio_intctl"); |
ee6847d1 GH |
429 | qdev_prop_set_ptr(dev, "intbit_to_level", (void *)intbit_to_level); |
430 | qdev_prop_set_uint32(dev, "cputimer_bit", cputimer); | |
a1961a4b | 431 | qdev_init(dev); |
a8f48dcc | 432 | |
a1961a4b | 433 | s = sysbus_from_qdev(dev); |
a8f48dcc | 434 | |
a1961a4b BS |
435 | for (i = 0; i < MAX_CPUS; i++) { |
436 | for (j = 0; j < MAX_PILS; j++) { | |
437 | sysbus_connect_irq(s, i * MAX_PILS + j, parent_irq[i][j]); | |
438 | } | |
439 | } | |
440 | sysbus_mmio_map(s, 0, addrg); | |
441 | for (i = 0; i < MAX_CPUS; i++) { | |
442 | sysbus_mmio_map(s, i + 1, addr + i * TARGET_PAGE_SIZE); | |
e80cfcfc FB |
443 | } |
444 | ||
a1961a4b BS |
445 | return dev; |
446 | } | |
e80cfcfc | 447 | |
a1961a4b BS |
448 | static SysBusDeviceInfo slavio_intctl_info = { |
449 | .init = slavio_intctl_init1, | |
450 | .qdev.name = "slavio_intctl", | |
451 | .qdev.size = sizeof(SLAVIO_INTCTLState), | |
ee6847d1 GH |
452 | .qdev.props = (Property[]) { |
453 | { | |
454 | .name = "intbit_to_level", | |
455 | .info = &qdev_prop_ptr, | |
456 | .offset = offsetof(SLAVIO_INTCTLState, intbit_to_level), | |
457 | }, | |
458 | { | |
459 | .name = "cputimer_bit", | |
460 | .info = &qdev_prop_uint32, | |
461 | .offset = offsetof(SLAVIO_INTCTLState, cputimer_bit), | |
462 | }, | |
463 | {/* end of property list */} | |
a1961a4b BS |
464 | } |
465 | }; | |
d7edfd27 | 466 | |
a1961a4b BS |
467 | static void slavio_intctl_register_devices(void) |
468 | { | |
469 | sysbus_register_withprop(&slavio_intctl_info); | |
e80cfcfc | 470 | } |
a1961a4b BS |
471 | |
472 | device_init(slavio_intctl_register_devices) |