qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/8] q800: GLUE updates for A/UX mode
@ 2021-10-20 13:41 Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 1/8] mac_via: update comment for VIA1B_vMystery bit Mark Cave-Ayland
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

This patchset contains a set of GLUE updates to enable switching between
so-called A/UX mode and classic mode which is required to allow the q800
machine to boot both Linux/NetBSD and MacOS.

Patch 1 updates the comment for the VIA1B_vMystery bit indicating that
VIA1 port B bit 6 is used to switch between A/UX and classic mode.

Patch 2 moves the VIA1 IRQ from level 1 to level 6: this is because in
its current configuration the q800 machine is statically wired in A/UX mode
except for VIA1 which is currently still wired according to classic mode.

Patch 3 starts the process of abstracting the CPU IRQ levels from the GPIO
pins by using a set of numbered GPIO defines and using these to map to the
corresponding CPU IRQs accordingly.

Patches 4 and 5 add a GPIO to VIA1 so that updates to the VIA1B_vMystery bit
will set the auxmode variable in the GLUE device to facilitate dynamic CPU
IRQ routing.

Patches 6 and 7 adjust the CPU IRQ routing in GLUE_set_irq() so that the
incoming IRQs are mapped to the appropriate CPU IRQ levels dynamically based
upon the auxmode variable.

Finally patch 8 adds an NMI handler which can be used to invoke the Quadra's
programmer switch from the monitor for debugging.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>

[Laurent: I recently discovered that this patchset is also a fix for the
qemu-m68k issue at https://github.com/vivier/qemu-m68k/issues/45]

v2:
- Rebase onto master
- Add R-B tags from Laurent
- Add comment about VIA1B_vMystery bit in via1_auxmode_update() in patch 4
- Use if statement instead of switch in patch 6
- Fix comment in patch 6 to read "classic mode" instead of "A/UX mode"
- Update cover letter to refer to github issue


Mark Cave-Ayland (8):
  mac_via: update comment for VIA1B_vMystery bit
  q800: move VIA1 IRQ from level 1 to level 6
  q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs
  mac_via: add GPIO for A/UX mode
  q800: wire up auxmode GPIO to GLUE
  q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic
    mode
  q800: wire up remaining IRQs in classic mode
  q800: add NMI handler

 hw/m68k/q800.c            | 167 +++++++++++++++++++++++++++++++++++++-
 hw/misc/mac_via.c         |  23 ++++++
 hw/misc/trace-events      |   1 +
 include/hw/misc/mac_via.h |   1 +
 4 files changed, 188 insertions(+), 4 deletions(-)

-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/8] mac_via: update comment for VIA1B_vMystery bit
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 2/8] q800: move VIA1 IRQ from level 1 to level 6 Mark Cave-Ayland
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

According to both Linux and NetBSD, port B bit 6 is used on the Quadra 800 to
configure the GLUE logic in A/UX mode. Whilst the name VIA1B_vMystery isn't
particularly descriptive, the patch leaves this to ensure that the constants
in mac_via.c remain in sync with Linux's mac_via.h.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/misc/mac_via.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index 993bac017d..7a53a8b4c0 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -130,6 +130,10 @@
                                 * On SE/30, vertical sync interrupt enable.
                                 * 0=enabled. This vSync interrupt shows up
                                 * as a slot $E interrupt.
+                                * On Quadra 800 this bit toggles A/UX mode which
+                                * configures the glue logic to deliver some IRQs
+                                * at different levels compared to a classic
+                                * Mac.
                                 */
 #define VIA1B_vADBS2   0x20    /* ADB state input bit 1 (unused on IIfx) */
 #define VIA1B_vADBS1   0x10    /* ADB state input bit 0 (unused on IIfx) */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/8] q800: move VIA1 IRQ from level 1 to level 6
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 1/8] mac_via: update comment for VIA1B_vMystery bit Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 3/8] q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs Mark Cave-Ayland
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

On a Quadra 800 machine Linux sets via_alt_mapping to 1 and clears port B bit 6 to
ensure that the VIA1 IRQ is delivered at level 6 rather than level 1. Even though
QEMU doesn't yet emulate this behaviour, Linux still installs the VIA1 level 1 IRQ
handler regardless of the value of via_alt_mapping which is why the kernel has been
able to boot until now.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/m68k/q800.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index fd4855047e..15f3067811 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -284,7 +284,7 @@ static void q800_init(MachineState *machine)
     sysbus = SYS_BUS_DEVICE(via1_dev);
     sysbus_realize_and_unref(sysbus, &error_fatal);
     sysbus_mmio_map(sysbus, 1, VIA_BASE);
-    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 0));
+    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 5));
 
     adb_bus = qdev_get_child_bus(via1_dev, "adb.0");
     dev = qdev_new(TYPE_ADB_KEYBOARD);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/8] q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 1/8] mac_via: update comment for VIA1B_vMystery bit Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 2/8] q800: move VIA1 IRQ from level 1 to level 6 Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 14:04   ` Laurent Vivier
  2021-10-20 13:41 ` [PATCH v2 4/8] mac_via: add GPIO for A/UX mode Mark Cave-Ayland
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

In order to allow dynamic routing of IRQs to different IRQ levels on the CPU
depending upon port B bit 6, use GLUE IRQ numbers and map them to the the
corresponding CPU IRQ level accordingly.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/m68k/q800.c | 32 ++++++++++++++++++++++++++++----
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 15f3067811..81c335bf16 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -102,11 +102,34 @@ struct GLUEState {
     uint8_t ipr;
 };
 
+#define GLUE_IRQ_IN_VIA1       0
+#define GLUE_IRQ_IN_VIA2       1
+#define GLUE_IRQ_IN_SONIC      2
+#define GLUE_IRQ_IN_ESCC       3
+
 static void GLUE_set_irq(void *opaque, int irq, int level)
 {
     GLUEState *s = opaque;
     int i;
 
+    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;
+    }
+
     if (level) {
         s->ipr |= 1 << irq;
     } else {
@@ -284,7 +307,7 @@ static void q800_init(MachineState *machine)
     sysbus = SYS_BUS_DEVICE(via1_dev);
     sysbus_realize_and_unref(sysbus, &error_fatal);
     sysbus_mmio_map(sysbus, 1, VIA_BASE);
-    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 5));
+    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA1));
 
     adb_bus = qdev_get_child_bus(via1_dev, "adb.0");
     dev = qdev_new(TYPE_ADB_KEYBOARD);
@@ -297,7 +320,7 @@ static void q800_init(MachineState *machine)
     sysbus = SYS_BUS_DEVICE(via2_dev);
     sysbus_realize_and_unref(sysbus, &error_fatal);
     sysbus_mmio_map(sysbus, 1, VIA_BASE + VIA_SIZE);
-    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 1));
+    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA2));
 
     /* MACSONIC */
 
@@ -330,7 +353,7 @@ static void q800_init(MachineState *machine)
     sysbus = SYS_BUS_DEVICE(dev);
     sysbus_realize_and_unref(sysbus, &error_fatal);
     sysbus_mmio_map(sysbus, 0, SONIC_BASE);
-    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 2));
+    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_SONIC));
 
     memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-q800.prom",
                            SONIC_PROM_SIZE, &error_fatal);
@@ -366,7 +389,8 @@ static void q800_init(MachineState *machine)
     qdev_realize_and_unref(escc_orgate, NULL, &error_fatal);
     sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(escc_orgate, 0));
     sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(escc_orgate, 1));
-    qdev_connect_gpio_out(DEVICE(escc_orgate), 0, qdev_get_gpio_in(glue, 3));
+    qdev_connect_gpio_out(DEVICE(escc_orgate), 0,
+                          qdev_get_gpio_in(glue, GLUE_IRQ_IN_ESCC));
     sysbus_mmio_map(sysbus, 0, SCC_BASE);
 
     /* SCSI */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/8] mac_via: add GPIO for A/UX mode
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
                   ` (2 preceding siblings ...)
  2021-10-20 13:41 ` [PATCH v2 3/8] q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 5/8] q800: wire up auxmode GPIO to GLUE Mark Cave-Ayland
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

Add a new auxmode GPIO that is updated when port B bit 6 is changed indicating
whether the hardware is configured for A/UX mode.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/misc/mac_via.c         | 19 +++++++++++++++++++
 hw/misc/trace-events      |  1 +
 include/hw/misc/mac_via.h |  1 +
 3 files changed, 21 insertions(+)

diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c
index 7a53a8b4c0..b378e6b305 100644
--- a/hw/misc/mac_via.c
+++ b/hw/misc/mac_via.c
@@ -880,6 +880,21 @@ static void via1_adb_update(MOS6522Q800VIA1State *v1s)
     }
 }
 
+static void via1_auxmode_update(MOS6522Q800VIA1State *v1s)
+{
+    MOS6522State *s = MOS6522(v1s);
+    int oldirq, irq;
+
+    oldirq = (v1s->last_b & VIA1B_vMystery) ? 1 : 0;
+    irq = (s->b & VIA1B_vMystery) ? 1 : 0;
+
+    /* Check to see if the A/UX mode bit has changed */
+    if (irq != oldirq) {
+        trace_via1_auxmode(irq);
+        qemu_set_irq(v1s->auxmode_irq, irq);
+    }
+}
+
 static uint64_t mos6522_q800_via1_read(void *opaque, hwaddr addr, unsigned size)
 {
     MOS6522Q800VIA1State *s = MOS6522_Q800_VIA1(opaque);
@@ -902,6 +917,7 @@ static void mos6522_q800_via1_write(void *opaque, hwaddr addr, uint64_t val,
     case VIA_REG_B:
         via1_rtc_update(v1s);
         via1_adb_update(v1s);
+        via1_auxmode_update(v1s);
 
         v1s->last_b = ms->b;
         break;
@@ -1046,6 +1062,9 @@ static void mos6522_q800_via1_init(Object *obj)
               TYPE_ADB_BUS, DEVICE(v1s), "adb.0");
 
     qdev_init_gpio_in(DEVICE(obj), via1_irq_request, VIA1_IRQ_NB);
+
+    /* A/UX mode */
+    qdev_init_gpio_out(DEVICE(obj), &v1s->auxmode_irq, 1);
 }
 
 static const VMStateDescription vmstate_q800_via1 = {
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index ede413965b..2da96d167a 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -228,6 +228,7 @@ via1_rtc_cmd_pram_sect_write(int sector, int offset, int addr, int value) "secto
 via1_adb_send(const char *state, uint8_t data, const char *vadbint) "state %s data=0x%02x vADBInt=%s"
 via1_adb_receive(const char *state, uint8_t data, const char *vadbint, int status, int index, int size) "state %s data=0x%02x vADBInt=%s status=0x%x index=%d size=%d"
 via1_adb_poll(uint8_t data, const char *vadbint, int status, int index, int size) "data=0x%02x vADBInt=%s status=0x%x index=%d size=%d"
+via1_auxmode(int mode) "setting auxmode to %d"
 
 # grlib_ahb_apb_pnp.c
 grlib_ahb_pnp_read(uint64_t addr, uint32_t value) "AHB PnP read addr:0x%03"PRIx64" data:0x%08x"
diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h
index 4506abe5d0..b445565866 100644
--- a/include/hw/misc/mac_via.h
+++ b/include/hw/misc/mac_via.h
@@ -43,6 +43,7 @@ struct MOS6522Q800VIA1State {
     MemoryRegion via_mem;
 
     qemu_irq irqs[VIA1_IRQ_NB];
+    qemu_irq auxmode_irq;
     uint8_t last_b;
 
     /* RTC */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 5/8] q800: wire up auxmode GPIO to GLUE
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
                   ` (3 preceding siblings ...)
  2021-10-20 13:41 ` [PATCH v2 4/8] mac_via: add GPIO for A/UX mode Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 6/8] q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic mode Mark Cave-Ayland
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

This enables the GLUE logic to change its CPU level IRQ routing depending upon
whether the hardware has been configured for A/UX mode.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/m68k/q800.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 81c335bf16..0093872d89 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -100,6 +100,7 @@ struct GLUEState {
     SysBusDevice parent_obj;
     M68kCPU *cpu;
     uint8_t ipr;
+    uint8_t auxmode;
 };
 
 #define GLUE_IRQ_IN_VIA1       0
@@ -145,11 +146,19 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
     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_reset(DeviceState *dev)
 {
     GLUEState *s = GLUE(dev);
 
     s->ipr = 0;
+    s->auxmode = 0;
 }
 
 static const VMStateDescription vmstate_glue = {
@@ -158,6 +167,7 @@ static const VMStateDescription vmstate_glue = {
     .minimum_version_id = 0,
     .fields = (VMStateField[]) {
         VMSTATE_UINT8(ipr, GLUEState),
+        VMSTATE_UINT8(auxmode, GLUEState),
         VMSTATE_END_OF_LIST(),
     },
 };
@@ -178,6 +188,7 @@ static void glue_init(Object *obj)
     DeviceState *dev = DEVICE(obj);
 
     qdev_init_gpio_in(dev, GLUE_set_irq, 8);
+    qdev_init_gpio_in_named(dev, glue_auxmode_set_irq, "auxmode", 1);
 }
 
 static void glue_class_init(ObjectClass *klass, void *data)
@@ -308,6 +319,9 @@ static void q800_init(MachineState *machine)
     sysbus_realize_and_unref(sysbus, &error_fatal);
     sysbus_mmio_map(sysbus, 1, VIA_BASE);
     sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA1));
+    /* A/UX mode */
+    qdev_connect_gpio_out(via1_dev, 0,
+                          qdev_get_gpio_in_named(glue, "auxmode", 0));
 
     adb_bus = qdev_get_child_bus(via1_dev, "adb.0");
     dev = qdev_new(TYPE_ADB_KEYBOARD);
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 6/8] q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic mode
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
                   ` (4 preceding siblings ...)
  2021-10-20 13:41 ` [PATCH v2 5/8] q800: wire up auxmode GPIO to GLUE Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 14:07   ` Laurent Vivier
  2021-10-20 13:41 ` [PATCH v2 7/8] q800: wire up remaining IRQs " Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 8/8] q800: add NMI handler Mark Cave-Ayland
  7 siblings, 1 reply; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

When the hardware is operating in classic mode the SONIC on-board Ethernet IRQ is
routed to nubus IRQ 9 instead of directly to the CPU at level 3. This does not
affect the framebuffer which although it exists in slot 9, has its own
dedicated IRQ on the Quadra 800 hardware.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/m68k/q800.c | 57 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 41 insertions(+), 16 deletions(-)

diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 0093872d89..7a8de089f4 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -101,6 +101,7 @@ struct GLUEState {
     M68kCPU *cpu;
     uint8_t ipr;
     uint8_t auxmode;
+    qemu_irq irqs[1];
 };
 
 #define GLUE_IRQ_IN_VIA1       0
@@ -108,27 +109,40 @@ struct GLUEState {
 #define GLUE_IRQ_IN_SONIC      2
 #define GLUE_IRQ_IN_ESCC       3
 
+#define GLUE_IRQ_NUBUS_9       0
+
 static void GLUE_set_irq(void *opaque, int irq, int level)
 {
     GLUEState *s = opaque;
     int i;
 
-    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;
+    if (s->auxmode) {
+        /* Classic mode */
+        switch (irq) {
+        case GLUE_IRQ_IN_SONIC:
+            /* Route to VIA2 instead */
+            qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level);
+            return;
+        }
+    } 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;
+        }
     }
 
     if (level) {
@@ -186,9 +200,12 @@ static Property glue_properties[] = {
 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);
 }
 
 static void glue_class_init(ObjectClass *klass, void *data)
@@ -454,6 +471,14 @@ static void q800_init(MachineState *machine)
                                                      VIA2_NUBUS_IRQ_9 + i));
     }
 
+    /*
+     * Since the framebuffer in slot 0x9 uses a separate IRQ, wire the unused
+     * IRQ via GLUE for use by SONIC Ethernet in classic mode
+     */
+    qdev_connect_gpio_out(glue, GLUE_IRQ_NUBUS_9,
+                          qdev_get_gpio_in_named(via2_dev, "nubus-irq",
+                                                 VIA2_NUBUS_IRQ_9));
+
     nubus = &NUBUS_BRIDGE(dev)->bus;
 
     /* framebuffer in nubus slot #9 */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 7/8] q800: wire up remaining IRQs in classic mode
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
                   ` (5 preceding siblings ...)
  2021-10-20 13:41 ` [PATCH v2 6/8] q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic mode Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  2021-10-20 13:41 ` [PATCH v2 8/8] q800: add NMI handler Mark Cave-Ayland
  7 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

Explicitly wire up the remaining IRQs in classic mode to enable the use of
g_assert_not_reached() in the default case to detect any unexpected IRQs.

Add a comment explaining the IRQ routing differences in A/UX mode based
upon the comments in NetBSD (also noting that at least A/UX 3.0.1 still
uses classic mode).

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/m68k/q800.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 7a8de089f4..83fde39298 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -111,6 +111,37 @@ struct GLUEState {
 
 #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;
@@ -119,10 +150,25 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
     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;
+
+        default:
+            g_assert_not_reached();
         }
     } else {
         /* A/UX mode */
@@ -142,6 +188,9 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
         case GLUE_IRQ_IN_ESCC:
             irq = 3;
             break;
+
+        default:
+            g_assert_not_reached();
         }
     }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 8/8] q800: add NMI handler
  2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
                   ` (6 preceding siblings ...)
  2021-10-20 13:41 ` [PATCH v2 7/8] q800: wire up remaining IRQs " Mark Cave-Ayland
@ 2021-10-20 13:41 ` Mark Cave-Ayland
  7 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2021-10-20 13:41 UTC (permalink / raw)
  To: laurent, qemu-devel

This allows the programmer's switch to be triggered via the monitor for debugging
purposes. Since the CPU level 7 interrupt is level-triggered, use a timer to hold
the NMI active for 100ms before releasing it again.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewied-by: Laurent Vivier <laurent@vivier.eu>
---
 hw/m68k/q800.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
index 83fde39298..a081051a8d 100644
--- a/hw/m68k/q800.c
+++ b/hw/m68k/q800.c
@@ -28,6 +28,7 @@
 #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"
@@ -102,12 +103,14 @@ struct GLUEState {
     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
 
@@ -167,6 +170,10 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
             irq = 3;
             break;
 
+        case GLUE_IRQ_IN_NMI:
+            irq = 6;
+            break;
+
         default:
             g_assert_not_reached();
         }
@@ -189,6 +196,10 @@ static void GLUE_set_irq(void *opaque, int irq, int level)
             irq = 3;
             break;
 
+        case GLUE_IRQ_IN_NMI:
+            irq = 6;
+            break;
+
         default:
             g_assert_not_reached();
         }
@@ -216,12 +227,30 @@ static void glue_auxmode_set_irq(void *opaque, int irq, int level)
     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 = {
@@ -231,6 +260,7 @@ static const VMStateDescription vmstate_glue = {
     .fields = (VMStateField[]) {
         VMSTATE_UINT8(ipr, GLUEState),
         VMSTATE_UINT8(auxmode, GLUEState),
+        VMSTATE_TIMER_PTR(nmi_release, GLUEState),
         VMSTATE_END_OF_LIST(),
     },
 };
@@ -246,6 +276,13 @@ static Property glue_properties[] = {
     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);
@@ -255,15 +292,20 @@ static void glue_init(Object *obj)
     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 = {
@@ -271,7 +313,12 @@ static const TypeInfo glue_info = {
     .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)
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/8] q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs
  2021-10-20 13:41 ` [PATCH v2 3/8] q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs Mark Cave-Ayland
@ 2021-10-20 14:04   ` Laurent Vivier
  0 siblings, 0 replies; 11+ messages in thread
From: Laurent Vivier @ 2021-10-20 14:04 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel

Le 20/10/2021 à 15:41, Mark Cave-Ayland a écrit :
> In order to allow dynamic routing of IRQs to different IRQ levels on the CPU
> depending upon port B bit 6, use GLUE IRQ numbers and map them to the the
> corresponding CPU IRQ level accordingly.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   hw/m68k/q800.c | 32 ++++++++++++++++++++++++++++----
>   1 file changed, 28 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
> index 15f3067811..81c335bf16 100644
> --- a/hw/m68k/q800.c
> +++ b/hw/m68k/q800.c
> @@ -102,11 +102,34 @@ struct GLUEState {
>       uint8_t ipr;
>   };
>   
> +#define GLUE_IRQ_IN_VIA1       0
> +#define GLUE_IRQ_IN_VIA2       1
> +#define GLUE_IRQ_IN_SONIC      2
> +#define GLUE_IRQ_IN_ESCC       3
> +
>   static void GLUE_set_irq(void *opaque, int irq, int level)
>   {
>       GLUEState *s = opaque;
>       int i;
>   
> +    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;
> +    }
> +
>       if (level) {
>           s->ipr |= 1 << irq;
>       } else {
> @@ -284,7 +307,7 @@ static void q800_init(MachineState *machine)
>       sysbus = SYS_BUS_DEVICE(via1_dev);
>       sysbus_realize_and_unref(sysbus, &error_fatal);
>       sysbus_mmio_map(sysbus, 1, VIA_BASE);
> -    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 5));
> +    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA1));
>   
>       adb_bus = qdev_get_child_bus(via1_dev, "adb.0");
>       dev = qdev_new(TYPE_ADB_KEYBOARD);
> @@ -297,7 +320,7 @@ static void q800_init(MachineState *machine)
>       sysbus = SYS_BUS_DEVICE(via2_dev);
>       sysbus_realize_and_unref(sysbus, &error_fatal);
>       sysbus_mmio_map(sysbus, 1, VIA_BASE + VIA_SIZE);
> -    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 1));
> +    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_VIA2));
>   
>       /* MACSONIC */
>   
> @@ -330,7 +353,7 @@ static void q800_init(MachineState *machine)
>       sysbus = SYS_BUS_DEVICE(dev);
>       sysbus_realize_and_unref(sysbus, &error_fatal);
>       sysbus_mmio_map(sysbus, 0, SONIC_BASE);
> -    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, 2));
> +    sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(glue, GLUE_IRQ_IN_SONIC));
>   
>       memory_region_init_rom(dp8393x_prom, NULL, "dp8393x-q800.prom",
>                              SONIC_PROM_SIZE, &error_fatal);
> @@ -366,7 +389,8 @@ static void q800_init(MachineState *machine)
>       qdev_realize_and_unref(escc_orgate, NULL, &error_fatal);
>       sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(escc_orgate, 0));
>       sysbus_connect_irq(sysbus, 1, qdev_get_gpio_in(escc_orgate, 1));
> -    qdev_connect_gpio_out(DEVICE(escc_orgate), 0, qdev_get_gpio_in(glue, 3));
> +    qdev_connect_gpio_out(DEVICE(escc_orgate), 0,
> +                          qdev_get_gpio_in(glue, GLUE_IRQ_IN_ESCC));
>       sysbus_mmio_map(sysbus, 0, SCC_BASE);
>   
>       /* SCSI */
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 6/8] q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic mode
  2021-10-20 13:41 ` [PATCH v2 6/8] q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic mode Mark Cave-Ayland
@ 2021-10-20 14:07   ` Laurent Vivier
  0 siblings, 0 replies; 11+ messages in thread
From: Laurent Vivier @ 2021-10-20 14:07 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel

Le 20/10/2021 à 15:41, Mark Cave-Ayland a écrit :
> When the hardware is operating in classic mode the SONIC on-board Ethernet IRQ is
> routed to nubus IRQ 9 instead of directly to the CPU at level 3. This does not
> affect the framebuffer which although it exists in slot 9, has its own
> dedicated IRQ on the Quadra 800 hardware.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   hw/m68k/q800.c | 57 ++++++++++++++++++++++++++++++++++++--------------
>   1 file changed, 41 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c
> index 0093872d89..7a8de089f4 100644
> --- a/hw/m68k/q800.c
> +++ b/hw/m68k/q800.c
> @@ -101,6 +101,7 @@ struct GLUEState {
>       M68kCPU *cpu;
>       uint8_t ipr;
>       uint8_t auxmode;
> +    qemu_irq irqs[1];
>   };
>   
>   #define GLUE_IRQ_IN_VIA1       0
> @@ -108,27 +109,40 @@ struct GLUEState {
>   #define GLUE_IRQ_IN_SONIC      2
>   #define GLUE_IRQ_IN_ESCC       3
>   
> +#define GLUE_IRQ_NUBUS_9       0
> +
>   static void GLUE_set_irq(void *opaque, int irq, int level)
>   {
>       GLUEState *s = opaque;
>       int i;
>   
> -    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;
> +    if (s->auxmode) {
> +        /* Classic mode */
> +        switch (irq) {
> +        case GLUE_IRQ_IN_SONIC:
> +            /* Route to VIA2 instead */
> +            qemu_set_irq(s->irqs[GLUE_IRQ_NUBUS_9], level);
> +            return;
> +        }
> +    } 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;
> +        }
>       }
>   
>       if (level) {
> @@ -186,9 +200,12 @@ static Property glue_properties[] = {
>   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);
>   }
>   
>   static void glue_class_init(ObjectClass *klass, void *data)
> @@ -454,6 +471,14 @@ static void q800_init(MachineState *machine)
>                                                        VIA2_NUBUS_IRQ_9 + i));
>       }
>   
> +    /*
> +     * Since the framebuffer in slot 0x9 uses a separate IRQ, wire the unused
> +     * IRQ via GLUE for use by SONIC Ethernet in classic mode
> +     */
> +    qdev_connect_gpio_out(glue, GLUE_IRQ_NUBUS_9,
> +                          qdev_get_gpio_in_named(via2_dev, "nubus-irq",
> +                                                 VIA2_NUBUS_IRQ_9));
> +
>       nubus = &NUBUS_BRIDGE(dev)->bus;
>   
>       /* framebuffer in nubus slot #9 */
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2021-10-20 14:15 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-20 13:41 [PATCH v2 0/8] q800: GLUE updates for A/UX mode Mark Cave-Ayland
2021-10-20 13:41 ` [PATCH v2 1/8] mac_via: update comment for VIA1B_vMystery bit Mark Cave-Ayland
2021-10-20 13:41 ` [PATCH v2 2/8] q800: move VIA1 IRQ from level 1 to level 6 Mark Cave-Ayland
2021-10-20 13:41 ` [PATCH v2 3/8] q800: use GLUE IRQ numbers instead of IRQ level for GLUE IRQs Mark Cave-Ayland
2021-10-20 14:04   ` Laurent Vivier
2021-10-20 13:41 ` [PATCH v2 4/8] mac_via: add GPIO for A/UX mode Mark Cave-Ayland
2021-10-20 13:41 ` [PATCH v2 5/8] q800: wire up auxmode GPIO to GLUE Mark Cave-Ayland
2021-10-20 13:41 ` [PATCH v2 6/8] q800: route SONIC on-board Ethernet IRQ via nubus IRQ 9 in classic mode Mark Cave-Ayland
2021-10-20 14:07   ` Laurent Vivier
2021-10-20 13:41 ` [PATCH v2 7/8] q800: wire up remaining IRQs " Mark Cave-Ayland
2021-10-20 13:41 ` [PATCH v2 8/8] q800: add NMI handler Mark Cave-Ayland

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).