1 /* 2 * SPDX-License-Identifer: GPL-2.0-or-later 3 * 4 * QEMU Motorola 680x0 IRQ Controller 5 * 6 * (c) 2020 Laurent Vivier <laurent@vivier.eu> 7 * 8 */ 9 10 #include "qemu/osdep.h" 11 #include "cpu.h" 12 #include "migration/vmstate.h" 13 #include "monitor/monitor.h" 14 #include "hw/nmi.h" 15 #include "hw/intc/intc.h" 16 #include "hw/intc/m68k_irqc.h" 17 18 19 static bool m68k_irqc_get_statistics(InterruptStatsProvider *obj, 20 uint64_t **irq_counts, unsigned int *nb_irqs) 21 { 22 M68KIRQCState *s = M68K_IRQC(obj); 23 24 *irq_counts = s->stats_irq_count; 25 *nb_irqs = ARRAY_SIZE(s->stats_irq_count); 26 return true; 27 } 28 29 static void m68k_irqc_print_info(InterruptStatsProvider *obj, Monitor *mon) 30 { 31 M68KIRQCState *s = M68K_IRQC(obj); 32 monitor_printf(mon, "m68k-irqc: ipr=0x%x\n", s->ipr); 33 } 34 35 static void m68k_set_irq(void *opaque, int irq, int level) 36 { 37 M68KIRQCState *s = opaque; 38 M68kCPU *cpu = M68K_CPU(first_cpu); 39 int i; 40 41 if (level) { 42 s->ipr |= 1 << irq; 43 s->stats_irq_count[irq]++; 44 } else { 45 s->ipr &= ~(1 << irq); 46 } 47 48 for (i = M68K_IRQC_LEVEL_7; i >= M68K_IRQC_LEVEL_1; i--) { 49 if ((s->ipr >> i) & 1) { 50 m68k_set_irq_level(cpu, i + 1, i + M68K_IRQC_AUTOVECTOR_BASE); 51 return; 52 } 53 } 54 m68k_set_irq_level(cpu, 0, 0); 55 } 56 57 static void m68k_irqc_reset(DeviceState *d) 58 { 59 M68KIRQCState *s = M68K_IRQC(d); 60 int i; 61 62 s->ipr = 0; 63 for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) { 64 s->stats_irq_count[i] = 0; 65 } 66 } 67 68 static void m68k_irqc_instance_init(Object *obj) 69 { 70 qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM); 71 } 72 73 static void m68k_nmi(NMIState *n, int cpu_index, Error **errp) 74 { 75 m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1); 76 } 77 78 static const VMStateDescription vmstate_m68k_irqc = { 79 .name = "m68k-irqc", 80 .version_id = 1, 81 .minimum_version_id = 1, 82 .fields = (VMStateField[]) { 83 VMSTATE_UINT8(ipr, M68KIRQCState), 84 VMSTATE_END_OF_LIST() 85 } 86 }; 87 88 static void m68k_irqc_class_init(ObjectClass *oc, void *data) 89 { 90 DeviceClass *dc = DEVICE_CLASS(oc); 91 NMIClass *nc = NMI_CLASS(oc); 92 InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); 93 94 nc->nmi_monitor_handler = m68k_nmi; 95 dc->reset = m68k_irqc_reset; 96 dc->vmsd = &vmstate_m68k_irqc; 97 ic->get_statistics = m68k_irqc_get_statistics; 98 ic->print_info = m68k_irqc_print_info; 99 } 100 101 static const TypeInfo m68k_irqc_type_info = { 102 .name = TYPE_M68K_IRQC, 103 .parent = TYPE_SYS_BUS_DEVICE, 104 .instance_size = sizeof(M68KIRQCState), 105 .instance_init = m68k_irqc_instance_init, 106 .class_init = m68k_irqc_class_init, 107 .interfaces = (InterfaceInfo[]) { 108 { TYPE_NMI }, 109 { TYPE_INTERRUPT_STATS_PROVIDER }, 110 { } 111 }, 112 }; 113 114 static void q800_irq_register_types(void) 115 { 116 type_register_static(&m68k_irqc_type_info); 117 } 118 119 type_init(q800_irq_register_types); 120