diff options
author | Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | 2023-06-21 09:53:36 +0100 |
---|---|---|
committer | Laurent Vivier <laurent@vivier.eu> | 2023-06-22 09:21:57 +0200 |
commit | 8e0932802f5fd6d8c5c12080d144f01b09863c3c (patch) | |
tree | a626cbf9f6f05c585b22e59cf8cf652f48d2130f /hw | |
parent | 0b9b41fb8b4879d4dd3d2ce0a13493541c2d8d66 (diff) |
q800: move GLUE device into separate q800-glue.c file
This will allow the q800-glue.h header to be included separately so that the
GLUE device can be referenced externally.
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-Id: <20230621085353.113233-8-mark.cave-ayland@ilande.co.uk>
[lv: update comment]
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/m68k/meson.build | 2 | ||||
-rw-r--r-- | hw/m68k/q800-glue.c | 252 | ||||
-rw-r--r-- | hw/m68k/q800.c | 238 |
3 files changed, 254 insertions, 238 deletions
diff --git a/hw/m68k/meson.build b/hw/m68k/meson.build index 31248641d3..84bc68fa4e 100644 --- a/hw/m68k/meson.build +++ b/hw/m68k/meson.build @@ -2,7 +2,7 @@ m68k_ss = ss.source_set() m68k_ss.add(when: 'CONFIG_AN5206', if_true: files('an5206.c', 'mcf5206.c')) m68k_ss.add(when: 'CONFIG_MCF5208', if_true: files('mcf5208.c', 'mcf_intc.c')) m68k_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-kbd.c', 'next-cube.c')) -m68k_ss.add(when: 'CONFIG_Q800', if_true: files('q800.c')) +m68k_ss.add(when: 'CONFIG_Q800', if_true: files('q800.c', 'q800-glue.c')) m68k_ss.add(when: 'CONFIG_M68K_VIRT', if_true: files('virt.c')) hw_arch += {'m68k': m68k_ss} diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c new file mode 100644 index 0000000000..e81f9438f1 --- /dev/null +++ b/hw/m68k/q800-glue.c @@ -0,0 +1,252 @@ +/* + * QEMU q800 logic GLUE (General Logic Unit) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "hw/m68k/q800-glue.h" +#include "hw/boards.h" +#include "hw/irq.h" +#include "hw/nmi.h" +#include "hw/qdev-properties.h" +#include "migration/vmstate.h" + +/* + * The GLUE (General Logic Unit) is an Apple custom integrated circuit chip + * that performs a variety of functions (RAM management, clock generation, ...). + * The GLUE chip receives interrupt requests from various devices, + * assign priority to each, and asserts one or more interrupt line to the + * CPU. + */ + +/* + * The GLUE logic on the Quadra 800 supports 2 different IRQ routing modes + * controlled from the VIA1 auxmode GPIO (port B bit 6) which are documented + * in NetBSD as follows: + * + * A/UX mode (Linux, NetBSD, auxmode GPIO low) + * + * Level 0: Spurious: ignored + * Level 1: Software + * Level 2: VIA2 (except ethernet, sound) + * Level 3: Ethernet + * Level 4: Serial (SCC) + * Level 5: Sound + * Level 6: VIA1 + * Level 7: NMIs: parity errors, RESET button, YANCC error + * + * Classic mode (default: used by MacOS, A/UX 3.0.1, auxmode GPIO high) + * + * Level 0: Spurious: ignored + * Level 1: VIA1 (clock, ADB) + * Level 2: VIA2 (NuBus, SCSI) + * Level 3: + * Level 4: Serial (SCC) + * Level 5: + * Level 6: + * Level 7: Non-maskable: parity errors, RESET button + * + * Note that despite references to A/UX mode in Linux and NetBSD, at least + * A/UX 3.0.1 still uses Classic mode. + */ + +static void GLUE_set_irq(void *opaque, int irq, int level) +{ + GLUEState *s = opaque; + int i; + + if (s->auxmode) { + /* Classic mode */ + switch (irq) { + case GLUE_IRQ_IN_VIA1: + irq = 0; + break; + + case GLUE_IRQ_IN_VIA2: + irq = 1; + break; + + case GLUE_IRQ_IN_SONIC: + /* Route to VIA2 instead */ + qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level); + return; + + case GLUE_IRQ_IN_ESCC: + irq = 3; + break; + + case GLUE_IRQ_IN_NMI: + irq = 6; + break; + + default: + g_assert_not_reached(); + } + } else { + /* A/UX mode */ + switch (irq) { + case GLUE_IRQ_IN_VIA1: + irq = 5; + break; + + case GLUE_IRQ_IN_VIA2: + irq = 1; + break; + + case GLUE_IRQ_IN_SONIC: + irq = 2; + break; + + case GLUE_IRQ_IN_ESCC: + irq = 3; + break; + + case GLUE_IRQ_IN_NMI: + irq = 6; + break; + + default: + g_assert_not_reached(); + } + } + + if (level) { + s->ipr |= 1 << irq; + } else { + s->ipr &= ~(1 << irq); + } + + for (i = 7; i >= 0; i--) { + if ((s->ipr >> i) & 1) { + m68k_set_irq_level(s->cpu, i + 1, i + 25); + return; + } + } + m68k_set_irq_level(s->cpu, 0, 0); +} + +static void glue_auxmode_set_irq(void *opaque, int irq, int level) +{ + GLUEState *s = GLUE(opaque); + + s->auxmode = level; +} + +static void glue_nmi(NMIState *n, int cpu_index, Error **errp) +{ + GLUEState *s = GLUE(n); + + /* Hold NMI active for 100ms */ + GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 1); + timer_mod(s->nmi_release, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); +} + +static void glue_nmi_release(void *opaque) +{ + GLUEState *s = GLUE(opaque); + + GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0); +} + +static void glue_reset(DeviceState *dev) +{ + GLUEState *s = GLUE(dev); + + s->ipr = 0; + s->auxmode = 0; + + timer_del(s->nmi_release); +} + +static const VMStateDescription vmstate_glue = { + .name = "q800-glue", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT8(ipr, GLUEState), + VMSTATE_UINT8(auxmode, GLUEState), + VMSTATE_TIMER_PTR(nmi_release, GLUEState), + VMSTATE_END_OF_LIST(), + }, +}; + +/* + * If the m68k CPU implemented its inbound irq lines as GPIO lines + * rather than via the m68k_set_irq_level() function we would not need + * this cpu link property and could instead provide outbound IRQ lines + * that the board could wire up to the CPU. + */ +static Property glue_properties[] = { + DEFINE_PROP_LINK("cpu", GLUEState, cpu, TYPE_M68K_CPU, M68kCPU *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void glue_finalize(Object *obj) +{ + GLUEState *s = GLUE(obj); + + timer_free(s->nmi_release); +} + +static void glue_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + GLUEState *s = GLUE(dev); + + qdev_init_gpio_in(dev, GLUE_set_irq, 8); + qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1); + + qdev_init_gpio_out(dev, s->irqs, 1); + + /* NMI release timer */ + s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s); +} + +static void glue_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + NMIClass *nc = NMI_CLASS(klass); + + dc->vmsd = &vmstate_glue; + dc->reset = glue_reset; + device_class_set_props(dc, glue_properties); + nc->nmi_monitor_handler = glue_nmi; +} + +static const TypeInfo glue_info = { + .name = TYPE_GLUE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(GLUEState), + .instance_init = glue_init, + .instance_finalize = glue_finalize, + .class_init = glue_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, +}; + +static void glue_register_types(void) +{ + type_register_static(&glue_info); +} + +type_init(glue_register_types) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 9f9668c2b4..9f9de2ebaf 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -28,7 +28,6 @@ #include "cpu.h" #include "hw/boards.h" #include "hw/or-irq.h" -#include "hw/nmi.h" #include "elf.h" #include "hw/loader.h" #include "ui/console.h" @@ -39,6 +38,7 @@ #include "standard-headers/asm-m68k/bootinfo-mac.h" #include "bootinfo.h" #include "hw/m68k/q800.h" +#include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" #include "hw/input/adb.h" #include "hw/nubus/mac-nubus-bridge.h" @@ -88,241 +88,6 @@ #define Q800_NUBUS_SLOTS_AVAILABLE (BIT(0x9) | BIT(0xc) | BIT(0xd) | \ BIT(0xe)) -/* - * The GLUE (General Logic Unit) is an Apple custom integrated circuit chip - * that performs a variety of functions (RAM management, clock generation, ...). - * The GLUE chip receives interrupt requests from various devices, - * assign priority to each, and asserts one or more interrupt line to the - * CPU. - */ - -#define TYPE_GLUE "q800-glue" -OBJECT_DECLARE_SIMPLE_TYPE(GLUEState, GLUE) - -struct GLUEState { - SysBusDevice parent_obj; - - M68kCPU *cpu; - uint8_t ipr; - uint8_t auxmode; - qemu_irq irqs[1]; - QEMUTimer *nmi_release; -}; - -#define GLUE_IRQ_IN_VIA1 0 -#define GLUE_IRQ_IN_VIA2 1 -#define GLUE_IRQ_IN_SONIC 2 -#define GLUE_IRQ_IN_ESCC 3 -#define GLUE_IRQ_IN_NMI 4 - -#define GLUE_IRQ_NUBUS_9 0 - -/* - * The GLUE logic on the Quadra 800 supports 2 different IRQ routing modes - * controlled from the VIA1 auxmode GPIO (port B bit 6) which are documented - * in NetBSD as follows: - * - * A/UX mode (Linux, NetBSD, auxmode GPIO low) - * - * Level 0: Spurious: ignored - * Level 1: Software - * Level 2: VIA2 (except ethernet, sound) - * Level 3: Ethernet - * Level 4: Serial (SCC) - * Level 5: Sound - * Level 6: VIA1 - * Level 7: NMIs: parity errors, RESET button, YANCC error - * - * Classic mode (default: used by MacOS, A/UX 3.0.1, auxmode GPIO high) - * - * Level 0: Spurious: ignored - * Level 1: VIA1 (clock, ADB) - * Level 2: VIA2 (NuBus, SCSI) - * Level 3: - * Level 4: Serial (SCC) - * Level 5: - * Level 6: - * Level 7: Non-maskable: parity errors, RESET button - * - * Note that despite references to A/UX mode in Linux and NetBSD, at least - * A/UX 3.0.1 still uses Classic mode. - */ - -static void GLUE_set_irq(void *opaque, int irq, int level) -{ - GLUEState *s = opaque; - int i; - - if (s->auxmode) { - /* Classic mode */ - switch (irq) { - case GLUE_IRQ_IN_VIA1: - irq = 0; - break; - - case GLUE_IRQ_IN_VIA2: - irq = 1; - break; - - case GLUE_IRQ_IN_SONIC: - /* Route to VIA2 instead */ - qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level); - return; - - case GLUE_IRQ_IN_ESCC: - irq = 3; - break; - - case GLUE_IRQ_IN_NMI: - irq = 6; - break; - - default: - g_assert_not_reached(); - } - } else { - /* A/UX mode */ - switch (irq) { - case GLUE_IRQ_IN_VIA1: - irq = 5; - break; - - case GLUE_IRQ_IN_VIA2: - irq = 1; - break; - - case GLUE_IRQ_IN_SONIC: - irq = 2; - break; - - case GLUE_IRQ_IN_ESCC: - irq = 3; - break; - - case GLUE_IRQ_IN_NMI: - irq = 6; - break; - - default: - g_assert_not_reached(); - } - } - - if (level) { - s->ipr |= 1 << irq; - } else { - s->ipr &= ~(1 << irq); - } - - for (i = 7; i >= 0; i--) { - if ((s->ipr >> i) & 1) { - m68k_set_irq_level(s->cpu, i + 1, i + 25); - return; - } - } - m68k_set_irq_level(s->cpu, 0, 0); -} - -static void glue_auxmode_set_irq(void *opaque, int irq, int level) -{ - GLUEState *s = GLUE(opaque); - - s->auxmode = level; -} - -static void glue_nmi(NMIState *n, int cpu_index, Error **errp) -{ - GLUEState *s = GLUE(n); - - /* Hold NMI active for 100ms */ - GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 1); - timer_mod(s->nmi_release, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); -} - -static void glue_nmi_release(void *opaque) -{ - GLUEState *s = GLUE(opaque); - - GLUE_set_irq(s, GLUE_IRQ_IN_NMI, 0); -} - -static void glue_reset(DeviceState *dev) -{ - GLUEState *s = GLUE(dev); - - s->ipr = 0; - s->auxmode = 0; - - timer_del(s->nmi_release); -} - -static const VMStateDescription vmstate_glue = { - .name = "q800-glue", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT8(ipr, GLUEState), - VMSTATE_UINT8(auxmode, GLUEState), - VMSTATE_TIMER_PTR(nmi_release, GLUEState), - VMSTATE_END_OF_LIST(), - }, -}; - -/* - * If the m68k CPU implemented its inbound irq lines as GPIO lines - * rather than via the m68k_set_irq_level() function we would not need - * this cpu link property and could instead provide outbound IRQ lines - * that the board could wire up to the CPU. - */ -static Property glue_properties[] = { - DEFINE_PROP_LINK("cpu", GLUEState, cpu, TYPE_M68K_CPU, M68kCPU *), - DEFINE_PROP_END_OF_LIST(), -}; - -static void glue_finalize(Object *obj) -{ - GLUEState *s = GLUE(obj); - - timer_free(s->nmi_release); -} - -static void glue_init(Object *obj) -{ - DeviceState *dev = DEVICE(obj); - GLUEState *s = GLUE(dev); - - qdev_init_gpio_in(dev, GLUE_set_irq, 8); - qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1); - - qdev_init_gpio_out(dev, s->irqs, 1); - - /* NMI release timer */ - s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s); -} - -static void glue_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - NMIClass *nc = NMI_CLASS(klass); - - dc->vmsd = &vmstate_glue; - dc->reset = glue_reset; - device_class_set_props(dc, glue_properties); - nc->nmi_monitor_handler = glue_nmi; -} - -static const TypeInfo glue_info = { - .name = TYPE_GLUE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(GLUEState), - .instance_init = glue_init, - .instance_finalize = glue_finalize, - .class_init = glue_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_NMI }, - { } - }, -}; static void main_cpu_reset(void *opaque) { @@ -763,7 +528,6 @@ static const TypeInfo q800_machine_typeinfo = { static void q800_machine_register_types(void) { type_register_static(&q800_machine_typeinfo); - type_register_static(&glue_info); } type_init(q800_machine_register_types) |