sun4m: don't connect two qemu_irqs directly to the same input

The sun4m board code connects both of the IRQ outputs of each ESCC to the
same slavio input qemu_irq. Connecting two qemu_irqs outputs directly to the
same input is not valid as it produces subtly wrong behaviour (for instance
if both the IRQ lines are high, and then one goes low, the PIC input will see
this as a high-to-low transition even though the second IRQ line should still
be holding it high).

This kind of wiring needs an explicitly created OR gate; add one.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Message-Id: <20201219111934.5540-1-mark.cave-ayland@ilande.co.uk>
Reviewed-by: Artyom Tarasenko <atar4qemu@gmail.com>
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
This commit is contained in:
Mark Cave-Ayland 2020-12-19 11:19:34 +00:00
parent aecf994bca
commit a879306ca1
2 changed files with 20 additions and 5 deletions

View File

@ -14,6 +14,7 @@ config SUN4M
select M48T59
select STP2000
select CHRP_NVRAM
select OR_IRQ
config LEON3
bool

View File

@ -50,6 +50,7 @@
#include "hw/misc/empty_slot.h"
#include "hw/misc/unimp.h"
#include "hw/irq.h"
#include "hw/or-irq.h"
#include "hw/loader.h"
#include "elf.h"
#include "trace.h"
@ -848,7 +849,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
uint32_t initrd_size;
DriveInfo *fd[MAX_FD];
FWCfgState *fw_cfg;
DeviceState *dev;
DeviceState *dev, *ms_kb_orgate, *serial_orgate;
SysBusDevice *s;
unsigned int smp_cpus = machine->smp.cpus;
unsigned int max_cpus = machine->smp.max_cpus;
@ -994,10 +995,16 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
qdev_prop_set_uint32(dev, "chnAtype", escc_kbd);
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_connect_irq(s, 0, slavio_irq[14]);
sysbus_connect_irq(s, 1, slavio_irq[14]);
sysbus_mmio_map(s, 0, hwdef->ms_kb_base);
/* Logically OR both its IRQs together */
ms_kb_orgate = DEVICE(object_new(TYPE_OR_IRQ));
object_property_set_int(OBJECT(ms_kb_orgate), "num-lines", 2, &error_fatal);
qdev_realize_and_unref(ms_kb_orgate, NULL, &error_fatal);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(ms_kb_orgate, 0));
sysbus_connect_irq(s, 1, qdev_get_gpio_in(ms_kb_orgate, 1));
qdev_connect_gpio_out(DEVICE(ms_kb_orgate), 0, slavio_irq[14]);
dev = qdev_new(TYPE_ESCC);
qdev_prop_set_uint32(dev, "disabled", 0);
qdev_prop_set_uint32(dev, "frequency", ESCC_CLOCK);
@ -1009,10 +1016,17 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal);
sysbus_connect_irq(s, 0, slavio_irq[15]);
sysbus_connect_irq(s, 1, slavio_irq[15]);
sysbus_mmio_map(s, 0, hwdef->serial_base);
/* Logically OR both its IRQs together */
serial_orgate = DEVICE(object_new(TYPE_OR_IRQ));
object_property_set_int(OBJECT(serial_orgate), "num-lines", 2,
&error_fatal);
qdev_realize_and_unref(serial_orgate, NULL, &error_fatal);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(serial_orgate, 0));
sysbus_connect_irq(s, 1, qdev_get_gpio_in(serial_orgate, 1));
qdev_connect_gpio_out(DEVICE(serial_orgate), 0, slavio_irq[15]);
if (hwdef->apc_base) {
apc_init(hwdef->apc_base, qemu_allocate_irq(cpu_halt_signal, NULL, 0));
}