]> git.proxmox.com Git - mirror_qemu.git/commitdiff
Initial SPARC SMP support (Blue Swirl)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 5 Dec 2005 20:31:52 +0000 (20:31 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 5 Dec 2005 20:31:52 +0000 (20:31 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1694 c046a42c-6fe2-441c-8c8c-71466251a162

12 files changed:
Changelog
cpu-all.h
cpu-exec.c
hw/slavio_intctl.c
hw/slavio_misc.c
hw/slavio_serial.c
hw/slavio_timer.c
hw/sun4m.c
monitor.c
target-sparc/cpu.h
vl.c
vl.h

index a96a5a9dccb2811b046c90831be2bef5a112f9a7..737f3ede28f92a69606eaeb756f942c58fea10f4 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -16,6 +16,7 @@ version 0.7.3:
   - MIPS User Linux emulation
   - MIPS fixes to boot Linux (Daniel Jacobowitz)
   - NX bit support
+  - Initial SPARC SMP support (Blue Swirl)
 
 version 0.7.2:
   
index d2086d56b149ef7528863c249c411ad6d1989920..b374fe86b059d2e3573b097045949652d2e0639b 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -734,6 +734,7 @@ extern int code_copy_enabled;
 #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
 #define CPU_INTERRUPT_TIMER  0x08 /* internal timer exception pending */
 #define CPU_INTERRUPT_FIQ    0x10 /* Fast interrupt pending.  */
+#define CPU_INTERRUPT_HALT   0x20 /* CPU halt wanted */
 
 void cpu_interrupt(CPUState *s, int mask);
 void cpu_reset_interrupt(CPUState *env, int mask);
index 128b5ff7a8b52ea8fd1d70b96fcdd06e1a0245d7..740037e4bb34166a222142a18d3428591b47e78f 100644 (file)
@@ -274,6 +274,15 @@ int cpu_exec(CPUState *env1)
             return EXCP_HALTED;
         }
     }
+#elif defined(TARGET_SPARC)
+    if (env1->halted) {
+        if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
+            (env1->psret != 0)) {
+            env1->halted = 0;
+        } else {
+            return EXCP_HALTED;
+        }
+    }
 #elif defined(TARGET_ARM)
     if (env1->halted) {
         /* An interrupt wakes the CPU even if the I and F CPSR bits are
@@ -522,7 +531,10 @@ int cpu_exec(CPUState *env1)
                    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
                        //do_interrupt(0, 0, 0, 0, 0);
                        env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
-                   }
+                   } else if (interrupt_request & CPU_INTERRUPT_HALT) {
+                        env1->halted = 1;
+                        return EXCP_HALTED;
+                    }
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->uncached_cpsr & CPSR_F)) {
index 9780785a47d6d2077b00eb79dd9da3bbda962af2..e43151fad882514b39c7f8e2c84379ffb82585ba 100644 (file)
@@ -53,6 +53,7 @@ typedef struct SLAVIO_INTCTLState {
 #ifdef DEBUG_IRQ_COUNT
     uint64_t irq_count[32];
 #endif
+    CPUState *cpu_envs[MAX_CPUS];
 } SLAVIO_INTCTLState;
 
 #define INTCTL_MAXADDR 0xf
@@ -96,6 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint
     case 2: // set softint
        val &= 0xfffe0000;
        s->intreg_pending[cpu] |= val;
+        slavio_check_interrupts(s);
        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
        break;
     default:
@@ -216,7 +218,7 @@ static void slavio_check_interrupts(void *opaque)
     CPUState *env;
     SLAVIO_INTCTLState *s = opaque;
     uint32_t pending = s->intregm_pending;
-    unsigned int i, max = 0;
+    unsigned int i, j, max = 0;
 
     pending &= ~s->intregm_disabled;
 
@@ -227,20 +229,52 @@ static void slavio_check_interrupts(void *opaque)
                    max = intbit_to_level[i];
            }
        }
-        env = first_cpu;
-       if (env->interrupt_index == 0) {
-           DPRINTF("Triggered pil %d\n", max);
+        env = s->cpu_envs[s->target_cpu];
+        if (!env) {
+           DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
+        }
+       else {
+            if (env->halted)
+                env->halted = 0;
+            if (env->interrupt_index == 0) {
+                DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
 #ifdef DEBUG_IRQ_COUNT
-           s->irq_count[max]++;
+                s->irq_count[max]++;
 #endif
-           env->interrupt_index = TT_EXTINT | max;
-           cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                env->interrupt_index = TT_EXTINT | max;
+                cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            }
+            else
+                DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
        }
-       else
-           DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
     }
     else
        DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
+    
+    for (i = 0; i < MAX_CPUS; i++) {
+        max = 0;
+        env = s->cpu_envs[i];
+        if (!env)
+            continue;
+        for (j = 17; j < 32; j++) {
+            if (s->intreg_pending[i] & (1 << j)) {
+                if (max < j - 16)
+                    max = j - 16;
+            }
+        }
+       if (max > 0) {
+            if (env->halted)
+                env->halted = 0;
+            if (env->interrupt_index == 0) {
+                DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
+#ifdef DEBUG_IRQ_COUNT
+                s->irq_count[max]++;
+#endif
+                env->interrupt_index = TT_EXTINT | max;
+                cpu_interrupt(env, CPU_INTERRUPT_HARD);
+            }
+        }
+    }
 }
 
 /*
@@ -251,7 +285,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level)
 {
     SLAVIO_INTCTLState *s = opaque;
 
-    DPRINTF("Set irq %d level %d\n", irq, level);
+    DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
     if (irq < 32) {
        uint32_t mask = 1 << irq;
        uint32_t pil = intbit_to_level[irq];
@@ -269,6 +303,29 @@ void slavio_pic_set_irq(void *opaque, int irq, int level)
     slavio_check_interrupts(s);
 }
 
+void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
+{
+    SLAVIO_INTCTLState *s = opaque;
+
+    DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
+    if (cpu == (unsigned int)-1) {
+        slavio_pic_set_irq(opaque, irq, level);
+        return;
+    }
+    if (irq < 32) {
+       uint32_t pil = intbit_to_level[irq];
+       if (pil > 0) {
+           if (level) {
+               s->intreg_pending[cpu] |= 1 << pil;
+           }
+           else {
+               s->intreg_pending[cpu] &= ~(1 << pil);
+           }
+       }
+    }
+    slavio_check_interrupts(s);
+}
+
 static void slavio_intctl_save(QEMUFile *f, void *opaque)
 {
     SLAVIO_INTCTLState *s = opaque;
@@ -312,6 +369,12 @@ static void slavio_intctl_reset(void *opaque)
     s->target_cpu = 0;
 }
 
+void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
+{
+    SLAVIO_INTCTLState *s = opaque;
+    s->cpu_envs[cpu] = env;
+}
+
 void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
 {
     int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
index 1b681be48375e869deedd409610268a1fe7599b2..904f44e515c0593c7c4d595f7fc98051da40f8b2 100644 (file)
@@ -124,9 +124,8 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32
     case 0xa000000:
        MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
 #if 0
-       // XXX: halting CPU does not work
-       raise_exception(EXCP_HLT);
-       cpu_loop_exit();
+        // XXX almost works
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
 #endif
        break;
     }
index de45cc5de1e3c0ae8ed1ec51e25c3c2798a3ac42..2b89c6d62ac79bf22aa08f7e7ce2f2f770c843ae 100644 (file)
@@ -45,6 +45,8 @@
 #ifdef DEBUG_SERIAL
 #define SER_DPRINTF(fmt, args...) \
 do { printf("SER: " fmt , ##args); } while (0)
+#define pic_set_irq(irq, level) \
+do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
 #else
 #define SER_DPRINTF(fmt, args...)
 #endif
@@ -174,6 +176,50 @@ static void slavio_serial_reset(void *opaque)
     slavio_serial_reset_chn(&s->chn[1]);
 }
 
+static inline void clr_rxint(ChannelState *s)
+{
+    s->rxint = 0;
+    if (s->chn == 0)
+        s->rregs[3] &= ~0x20;
+    else {
+        s->otherchn->rregs[3] &= ~4;
+    }
+    slavio_serial_update_irq(s);
+}
+
+static inline void set_rxint(ChannelState *s)
+{
+    s->rxint = 1;
+    if (s->chn == 0)
+        s->rregs[3] |= 0x20;
+    else {
+        s->otherchn->rregs[3] |= 4;
+    }
+    slavio_serial_update_irq(s);
+}
+
+static inline void clr_txint(ChannelState *s)
+{
+    s->txint = 0;
+    if (s->chn == 0)
+        s->rregs[3] &= ~0x10;
+    else {
+        s->otherchn->rregs[3] &= ~2;
+    }
+    slavio_serial_update_irq(s);
+}
+
+static inline void set_txint(ChannelState *s)
+{
+    s->txint = 1;
+    if (s->chn == 0)
+        s->rregs[3] |= 0x10;
+    else {
+        s->otherchn->rregs[3] |= 2;
+    }
+    slavio_serial_update_irq(s);
+}
+
 static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     SerialState *ser = opaque;
@@ -198,10 +244,14 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
                newreg |= 0x8;
                break;
            case 0x20:
-               s->rxint = 0;
+                clr_rxint(s);
                break;
            case 0x28:
-               s->txint = 0;
+                clr_txint(s);
+               break;
+           case 0x38:
+                clr_rxint(s);
+                clr_txint(s);
                break;
            default:
                break;
@@ -247,12 +297,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
            s->txint = 1;
            s->rregs[0] |= 4; // Tx buffer empty
            s->rregs[1] |= 1; // All sent
-           // Interrupts reported only on channel A
-           if (s->chn == 0)
-               s->rregs[3] |= 0x10;
-           else {
-               s->otherchn->rregs[3] |= 2;
-           }
+            set_txint(s);
            slavio_serial_update_irq(s);
        }
        break;
@@ -280,6 +325,7 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
        return ret;
     case 1:
        s->rregs[0] &= ~1;
+        clr_rxint(s);
        if (s->type == kbd)
            ret = get_queue(s);
        else
@@ -304,16 +350,10 @@ static int serial_can_receive(void *opaque)
 
 static void serial_receive_byte(ChannelState *s, int ch)
 {
+    SER_DPRINTF("put ch %d\n", ch);
     s->rregs[0] |= 1;
-    // Interrupts reported only on channel A
-    if (s->chn == 0)
-       s->rregs[3] |= 0x20;
-    else {
-       s->otherchn->rregs[3] |= 4;
-    }
     s->rx = ch;
-    s->rxint = 1;
-    slavio_serial_update_irq(s);
+    set_rxint(s);
 }
 
 static void serial_receive_break(ChannelState *s)
index 47d538529e9cafce3c087cc71537a11e877cd632..d75a76a636f6f1b0670c639c56a2be279b31e160 100644 (file)
@@ -42,6 +42,9 @@ do { printf("TIMER: " fmt , ##args); } while (0)
  * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
  * are zero. Bit 31 is 1 when count has been reached.
  *
+ * Per-CPU timers interrupt local CPU, system timer uses normal
+ * interrupt routing.
+ *
  */
 
 typedef struct SLAVIO_TIMERState {
@@ -53,11 +56,11 @@ typedef struct SLAVIO_TIMERState {
     int irq;
     int reached, stopped;
     int mode; // 0 = processor, 1 = user, 2 = system
+    unsigned int cpu;
 } SLAVIO_TIMERState;
 
 #define TIMER_MAXADDR 0x1f
 #define CNT_FREQ 2000000
-#define MAX_CPUS 16
 
 // Update count, set irq, update expire_time
 static void slavio_timer_get_out(SLAVIO_TIMERState *s)
@@ -73,7 +76,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s)
     else
        ticks = qemu_get_clock(vm_clock) - s->tick_offset;
 
-    out = (ticks >= s->expire_time);
+    out = (ticks > s->expire_time);
     if (out)
        s->reached = 0x80000000;
     if (!s->limit)
@@ -100,7 +103,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s)
     DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
 
     if (s->mode != 1)
-       pic_set_irq(s->irq, out);
+       pic_set_irq_cpu(s->irq, out, s->cpu);
 }
 
 // timer callback
@@ -127,7 +130,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
        // part of counter (user mode)
        if (s->mode != 1) {
            // clear irq
-           pic_set_irq(s->irq, 0);
+           pic_set_irq_cpu(s->irq, 0, s->cpu);
            s->count_load_time = qemu_get_clock(vm_clock);
            s->reached = 0;
            return s->limit;
@@ -263,7 +266,7 @@ static void slavio_timer_reset(void *opaque)
     slavio_timer_get_out(s);
 }
 
-static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
+void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu)
 {
     int slavio_timer_io_memory;
     SLAVIO_TIMERState *s;
@@ -273,6 +276,7 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
         return;
     s->irq = irq;
     s->mode = mode;
+    s->cpu = cpu;
     s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
 
     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
@@ -282,14 +286,3 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
     qemu_register_reset(slavio_timer_reset, s);
     slavio_timer_reset(s);
 }
-
-void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2)
-{
-    int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-       slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0);
-    }
-
-    slavio_timer_init_internal(addr2, irq2, 2);
-}
index 3ac0886a407a022fa5a9d33d6d79d30dd7ade2f5..5733fce5ab8ffa31a961c423c468cd096e38b9f4 100644 (file)
@@ -56,6 +56,7 @@
 #define PHYS_JJ_FDC    0x71400000      /* Floppy */
 #define PHYS_JJ_FLOPPY_IRQ 22
 #define PHYS_JJ_ME_IRQ 30              /* Module error, power fail */
+#define MAX_CPUS 16
 
 /* TSC handling */
 
@@ -128,6 +129,8 @@ static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline,
     nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
     nvram_set_lword(nvram,  0x10, 0x00000001); /* structure v1 */
     // NVRAM_size, arch not applicable
+    m48t59_write(nvram, 0x2D, smp_cpus & 0xff);
+    m48t59_write(nvram, 0x2E, 0);
     m48t59_write(nvram, 0x2F, nographic & 0xff);
     nvram_set_lword(nvram,  0x30, RAM_size);
     m48t59_write(nvram, 0x34, boot_device & 0xff);
@@ -179,6 +182,11 @@ void pic_set_irq(int irq, int level)
     slavio_pic_set_irq(slavio_intctl, irq, level);
 }
 
+void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
+{
+    slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
+}
+
 static void *tcx;
 
 void vga_update_display()
@@ -222,7 +230,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
                        const char *kernel_filename, const char *kernel_cmdline,
                        const char *initrd_filename)
 {
-    CPUState *env;
+    CPUState *env, *envs[MAX_CPUS];
     char buf[1024];
     int ret, linux_boot;
     unsigned int i;
@@ -230,19 +238,31 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
 
     linux_boot = (kernel_filename != NULL);
 
-    env = cpu_init();
-    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
-    qemu_register_reset(main_cpu_reset, env);
-
+    /* init CPUs */
+    for(i = 0; i < smp_cpus; i++) {
+        env = cpu_init();
+        envs[i] = env;
+        if (i != 0)
+            env->halted = 1;
+        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
+        qemu_register_reset(main_cpu_reset, env);
+    }
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, 0);
 
     iommu = iommu_init(PHYS_JJ_IOMMU);
     slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
+    for(i = 0; i < smp_cpus; i++) {
+        slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
+    }
+
     tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
     lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
     nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8);
-    slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
+    for (i = 0; i < MAX_CPUS; i++) {
+        slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i);
+    }
+    slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1);
     slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
     // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
index 2f0e84d86ebe80d867fc18fabfdf356b65425ace..d7acaa420d764749c461b2526e652ffe54d9644a 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -259,6 +259,10 @@ static void do_info_cpus(void)
         term_printf(" nip=0x" TARGET_FMT_lx, env->nip);
         if (env->halted)
             term_printf(" (halted)");
+#elif defined(TARGET_SPARC)
+        term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
+        if (env->halted)
+            term_printf(" (halted)");
 #endif
         term_printf("\n");
     }
index baff0c4602858c213d10bbd737bb274bd87771a4..28efab758f64dce58b91d9cf3da2753ab32a5662 100644 (file)
@@ -166,6 +166,7 @@ typedef struct CPUSPARCState {
     int exception_index;
     int interrupt_index;
     int interrupt_request;
+    int halted;
     /* NOTE: we allow 8 more registers to handle wrapping */
     target_ulong regbase[NWINDOWS * 16 + 8];
 
diff --git a/vl.c b/vl.c
index aa28032b41fdc6a31c32b4fe104a14fced5fcb50..4b1e72e9eb813cc21053bbb4713b899ea59a5729 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -153,6 +153,11 @@ USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
 USBDevice *vm_usb_hub;
 static VLANState *first_vlan;
 int smp_cpus = 1;
+#ifdef TARGET_SPARC
+#define MAX_CPUS 16
+#else
+#define MAX_CPUS 8
+#endif
 
 /***********************************************************/
 /* x86 ISA bus support */
@@ -4547,7 +4552,7 @@ int main(int argc, char **argv)
                 break;
             case QEMU_OPTION_smp:
                 smp_cpus = atoi(optarg);
-                if (smp_cpus < 1 || smp_cpus > 8) {
+                if (smp_cpus < 1 || smp_cpus > MAX_CPUS) {
                     fprintf(stderr, "Invalid number of CPUs\n");
                     exit(1);
                 }
diff --git a/vl.h b/vl.h
index 2ade7e9e990fd4946223b8bac12e2b4c46f1cd2f..fbac8072530ac4dc03a74644fbffb9e9c4a2af03 100644 (file)
--- a/vl.h
+++ b/vl.h
@@ -806,6 +806,7 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
 /* sun4m.c */
 extern QEMUMachine sun4m_machine;
 uint32_t iommu_translate(uint32_t addr);
+void pic_set_irq_cpu(int irq, int level, unsigned int cpu);
 
 /* iommu.c */
 void *iommu_init(uint32_t addr);
@@ -823,16 +824,18 @@ void tcx_screen_dump(void *opaque, const char *filename);
 
 /* slavio_intctl.c */
 void *slavio_intctl_init();
+void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env);
 void slavio_pic_info(void *opaque);
 void slavio_irq_info(void *opaque);
 void slavio_pic_set_irq(void *opaque, int irq, int level);
+void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu);
 
 /* magic-load.c */
 int load_elf(const char *filename, uint8_t *addr);
 int load_aout(const char *filename, uint8_t *addr);
 
 /* slavio_timer.c */
-void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2);
+void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu);
 
 /* slavio_serial.c */
 SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);