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