diff options
author | Laurent Vivier <laurent@vivier.eu> | 2021-03-12 22:41:43 +0100 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2021-03-15 21:02:20 +0100 |
commit | 2fde99ee3120416251922282c364833473135765 (patch) | |
tree | 78a7cdca9e7442bdc12cb978335b9eb5f94071d7 /hw/intc | |
parent | 87855593903fdc1809d6f6c2ac7f344c31cea799 (diff) |
m68k: add an interrupt controller
A (generic) copy of the GLUE device we already have for q800 to use with
the m68k-virt machine.
The q800 one would disappear in the future as q800 uses actually the djMEMC
controller.
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <20210312214145.2936082-4-laurent@vivier.eu>
Diffstat (limited to 'hw/intc')
-rw-r--r-- | hw/intc/Kconfig | 3 | ||||
-rw-r--r-- | hw/intc/m68k_irqc.c | 119 | ||||
-rw-r--r-- | hw/intc/meson.build | 1 |
3 files changed, 123 insertions, 0 deletions
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index 186cb5daa0..f4694088a4 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -70,3 +70,6 @@ config SIFIVE_PLIC config GOLDFISH_PIC bool + +config M68K_IRQC + bool diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c new file mode 100644 index 0000000000..2133d2a698 --- /dev/null +++ b/hw/intc/m68k_irqc.c @@ -0,0 +1,119 @@ +/* + * SPDX-License-Identifer: GPL-2.0-or-later + * + * QEMU Motorola 680x0 IRQ Controller + * + * (c) 2020 Laurent Vivier <laurent@vivier.eu> + * + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "migration/vmstate.h" +#include "monitor/monitor.h" +#include "hw/nmi.h" +#include "hw/intc/intc.h" +#include "hw/intc/m68k_irqc.h" + + +static bool m68k_irqc_get_statistics(InterruptStatsProvider *obj, + uint64_t **irq_counts, unsigned int *nb_irqs) +{ + M68KIRQCState *s = M68K_IRQC(obj); + + *irq_counts = s->stats_irq_count; + *nb_irqs = ARRAY_SIZE(s->stats_irq_count); + return true; +} + +static void m68k_irqc_print_info(InterruptStatsProvider *obj, Monitor *mon) +{ + M68KIRQCState *s = M68K_IRQC(obj); + monitor_printf(mon, "m68k-irqc: ipr=0x%x\n", s->ipr); +} + +static void m68k_set_irq(void *opaque, int irq, int level) +{ + M68KIRQCState *s = opaque; + M68kCPU *cpu = M68K_CPU(first_cpu); + int i; + + if (level) { + s->ipr |= 1 << irq; + s->stats_irq_count[irq]++; + } else { + s->ipr &= ~(1 << irq); + } + + for (i = M68K_IRQC_LEVEL_7; i >= M68K_IRQC_LEVEL_1; i--) { + if ((s->ipr >> i) & 1) { + m68k_set_irq_level(cpu, i + 1, i + M68K_IRQC_AUTOVECTOR_BASE); + return; + } + } + m68k_set_irq_level(cpu, 0, 0); +} + +static void m68k_irqc_reset(DeviceState *d) +{ + M68KIRQCState *s = M68K_IRQC(d); + int i; + + s->ipr = 0; + for (i = 0; i < ARRAY_SIZE(s->stats_irq_count); i++) { + s->stats_irq_count[i] = 0; + } +} + +static void m68k_irqc_instance_init(Object *obj) +{ + qdev_init_gpio_in(DEVICE(obj), m68k_set_irq, M68K_IRQC_LEVEL_NUM); +} + +static void m68k_nmi(NMIState *n, int cpu_index, Error **errp) +{ + m68k_set_irq(n, M68K_IRQC_LEVEL_7, 1); +} + +static const VMStateDescription vmstate_m68k_irqc = { + .name = "m68k-irqc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8(ipr, M68KIRQCState), + VMSTATE_END_OF_LIST() + } +}; + +static void m68k_irqc_class_init(ObjectClass *oc, void *data) + { + DeviceClass *dc = DEVICE_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); + InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); + + nc->nmi_monitor_handler = m68k_nmi; + dc->reset = m68k_irqc_reset; + dc->vmsd = &vmstate_m68k_irqc; + ic->get_statistics = m68k_irqc_get_statistics; + ic->print_info = m68k_irqc_print_info; +} + +static const TypeInfo m68k_irqc_type_info = { + .name = TYPE_M68K_IRQC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(M68KIRQCState), + .instance_init = m68k_irqc_instance_init, + .class_init = m68k_irqc_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NMI }, + { TYPE_INTERRUPT_STATS_PROVIDER }, + { } + }, +}; + +static void q800_irq_register_types(void) +{ + type_register_static(&m68k_irqc_type_info); +} + +type_init(q800_irq_register_types); diff --git a/hw/intc/meson.build b/hw/intc/meson.build index 5fcb923dd1..1c299039f6 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -58,3 +58,4 @@ specific_ss.add(when: 'CONFIG_XIVE', if_true: files('xive.c')) specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'], if_true: files('spapr_xive_kvm.c')) specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c')) +specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c')) |