aboutsummaryrefslogtreecommitdiff
path: root/hw/sun4u.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/sun4u.c')
-rw-r--r--hw/sun4u.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 00dac2d03e..59418f69e5 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -33,6 +33,15 @@
#include "firmware_abi.h"
#include "fw_cfg.h"
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, args...) \
+ do { printf("CPUIRQ: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
#define KERNEL_LOAD_ADDR 0x00404000
#define CMDLINE_ADDR 0x003ff000
#define INITRD_LOAD_ADDR 0x00300000
@@ -47,6 +56,8 @@
#define MAX_IDE_BUS 2
#define BIOS_CFG_IOPORT 0x510
+#define MAX_PILS 16
+
struct hwdef {
const char * const default_cpu_model;
uint16_t machine_id;
@@ -201,6 +212,50 @@ void irq_info(void)
{
}
+void cpu_check_irqs(CPUState *env)
+{
+ uint32_t pil = env->pil_in | (env->softint & ~SOFTINT_TIMER) |
+ ((env->softint & SOFTINT_TIMER) << 14);
+
+ if (pil && (env->interrupt_index == 0 ||
+ (env->interrupt_index & ~15) == TT_EXTINT)) {
+ unsigned int i;
+
+ for (i = 15; i > 0; i--) {
+ if (pil & (1 << i)) {
+ int old_interrupt = env->interrupt_index;
+
+ env->interrupt_index = TT_EXTINT | i;
+ if (old_interrupt != env->interrupt_index) {
+ DPRINTF("Set CPU IRQ %d\n", i);
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ break;
+ }
+ }
+ } else if (!pil && (env->interrupt_index & ~15) == TT_EXTINT) {
+ DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15);
+ env->interrupt_index = 0;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void cpu_set_irq(void *opaque, int irq, int level)
+{
+ CPUState *env = opaque;
+
+ if (level) {
+ DPRINTF("Raise CPU IRQ %d\n", irq);
+ env->halted = 0;
+ env->pil_in |= 1 << irq;
+ cpu_check_irqs(env);
+ } else {
+ DPRINTF("Lower CPU IRQ %d\n", irq);
+ env->pil_in &= ~(1 << irq);
+ cpu_check_irqs(env);
+ }
+}
+
void qemu_system_powerdown(void)
{
}
@@ -222,6 +277,7 @@ static void tick_irq(void *opaque)
{
CPUState *env = opaque;
+ env->softint |= SOFTINT_TIMER;
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
}
@@ -229,6 +285,7 @@ static void stick_irq(void *opaque)
{
CPUState *env = opaque;
+ env->softint |= SOFTINT_TIMER;
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
}
@@ -236,13 +293,10 @@ static void hstick_irq(void *opaque)
{
CPUState *env = opaque;
+ env->softint |= SOFTINT_TIMER;
cpu_interrupt(env, CPU_INTERRUPT_TIMER);
}
-static void dummy_cpu_set_irq(void *opaque, int irq, int level)
-{
-}
-
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
@@ -383,7 +437,7 @@ static void sun4uv_init(ram_addr_t RAM_size, int vga_ram_size,
pci_nic_init(pci_bus, &nd_table[i], -1);
}
- irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32);
+ irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
fprintf(stderr, "qemu: too many IDE bus\n");
exit(1);