m68k_irqc.c (2933B)
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 19static 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 29static 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 35static 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 57static 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 68static void m68k_irqc_instance_init(Object *obj) 69{ 70 qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM); 71} 72 73static void m68k_nmi(NMIState *n, int cpu_index, Error **errp) 74{ 75 m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1); 76} 77 78static 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 88static 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 101static 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 114static void q800_irq_register_types(void) 115{ 116 type_register_static(&m68k_irqc_type_info); 117} 118 119type_init(q800_irq_register_types);