Add ARM RealView Emulation Baseboard.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2164 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/Makefile.target b/Makefile.target
index d61b8e5..3d6fdc1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -368,6 +368,7 @@
 VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
 VL_OBJS+= versatile_pci.o
+VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
 endif
 ifeq ($(TARGET_BASE_ARCH), sh4)
 VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
new file mode 100644
index 0000000..c7cc380
--- /dev/null
+++ b/hw/arm_gic.c
@@ -0,0 +1,544 @@
+/* 
+ * ARM AMBA Generic/Distributed Interrupt Controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+/* TODO: Some variants of this controller can handle multiple CPUs.
+   Currently only single CPU operation is implemented.  */
+
+#include "vl.h"
+#include "arm_pic.h"
+
+//#define DEBUG_GIC
+
+#ifdef DEBUG_GIC
+#define DPRINTF(fmt, args...) \
+do { printf("arm_gic: " fmt , (int)s->base, ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+/* Distributed interrupt controller.  */
+
+static const uint8_t gic_id[] =
+{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+#define GIC_NIRQ 96
+
+typedef struct gic_irq_state
+{
+    unsigned enabled:1;
+    unsigned pending:1;
+    unsigned active:1;
+    unsigned level:1;
+    unsigned model:1; /* 0 = 1:N, 1 = N:N */
+    unsigned trigger:1; /* nonzero = edge triggered.  */
+} gic_irq_state;
+
+#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
+#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
+#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
+#define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1
+#define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0
+#define GIC_TEST_PENDING(irq) s->irq_state[irq].pending
+#define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1
+#define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0
+#define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active
+#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
+#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
+#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
+#define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1
+#define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0
+#define GIC_TEST_LEVEL(irq) s->irq_state[irq].level
+#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
+#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
+#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
+
+typedef struct gic_state
+{
+    arm_pic_handler handler;
+    uint32_t base;
+    void *parent;
+    int parent_irq;
+    int enabled;
+    int cpu_enabled;
+
+    gic_irq_state irq_state[GIC_NIRQ];
+    int irq_target[GIC_NIRQ];
+    int priority[GIC_NIRQ];
+    int last_active[GIC_NIRQ];
+
+    int priority_mask;
+    int running_irq;
+    int running_priority;
+    int current_pending;
+} gic_state;
+
+/* TODO: Many places that call this routine could be optimized.  */
+/* Update interrupt status after enabled or pending bits have been changed.  */
+static void gic_update(gic_state *s)
+{
+    int best_irq;
+    int best_prio;
+    int irq;
+
+    s->current_pending = 1023;
+    if (!s->enabled || !s->cpu_enabled) {
+        pic_set_irq_new(s->parent, s->parent_irq, 0);
+        return;
+    }
+    best_prio = 0x100;
+    best_irq = 1023;
+    for (irq = 0; irq < 96; irq++) {
+        if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) {
+            if (s->priority[irq] < best_prio) {
+                best_prio = s->priority[irq];
+                best_irq = irq;
+            }
+        }
+    }
+    if (best_prio > s->priority_mask) {
+        pic_set_irq_new(s->parent, s->parent_irq, 0);
+    } else {
+        s->current_pending = best_irq;
+        if (best_prio < s->running_priority) {
+            DPRINTF("Raised pending IRQ %d\n", best_irq);
+            pic_set_irq_new(s->parent, s->parent_irq, 1);
+        }
+    }
+}
+
+static void gic_set_irq(void *opaque, int irq, int level)
+{
+    gic_state *s = (gic_state *)opaque;
+    /* The first external input line is internal interrupt 32.  */
+    irq += 32;
+    if (level == GIC_TEST_LEVEL(irq)) 
+        return;
+
+    if (level) {
+        GIC_SET_LEVEL(irq);
+        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
+            DPRINTF("Set %d pending\n", irq);
+            GIC_SET_PENDING(irq);
+        }
+    } else {
+        GIC_CLEAR_LEVEL(irq);
+    }
+    gic_update(s);
+}
+
+static void gic_set_running_irq(gic_state *s, int irq)
+{
+    s->running_irq = irq;
+    s->running_priority = s->priority[irq];
+    gic_update(s);
+}
+
+static uint32_t gic_acknowledge_irq(gic_state *s)
+{
+    int new_irq;
+    new_irq = s->current_pending;
+    if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) {
+        DPRINTF("ACK no pending IRQ\n");
+        return 1023;
+    }
+    pic_set_irq_new(s->parent, s->parent_irq, 0);
+    s->last_active[new_irq] = s->running_irq;
+    /* For level triggered interrupts we clear the pending bit while
+       the interrupt is active.  */
+    GIC_CLEAR_PENDING(new_irq);
+    gic_set_running_irq(s, new_irq);
+    DPRINTF("ACK %d\n", new_irq);
+    return new_irq;
+}
+
+static void gic_complete_irq(gic_state * s, int irq)
+{
+    int update = 0;
+    DPRINTF("EIO %d\n", irq);
+    if (s->running_irq == 1023)
+        return; /* No active IRQ.  */
+    if (irq != 1023) {
+        /* Mark level triggered interrupts as pending if they are still
+           raised.  */
+        if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
+                && GIC_TEST_LEVEL(irq)) {
+            GIC_SET_PENDING(irq);
+            update = 1;
+        }
+    }
+    if (irq != s->running_irq) {
+        /* Complete an IRQ that is not currently running.  */
+        int tmp = s->running_irq;
+        while (s->last_active[tmp] != 1023) {
+            if (s->last_active[tmp] == irq) {
+                s->last_active[tmp] = s->last_active[irq];
+                break;
+            }
+            tmp = s->last_active[tmp];
+        }
+        if (update) {
+            gic_update(s);
+        }
+    } else {
+        /* Complete the current running IRQ.  */
+        gic_set_running_irq(s, s->last_active[s->running_irq]);
+    }
+}
+
+static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
+{
+    gic_state *s = (gic_state *)opaque;
+    uint32_t res;
+    int irq;
+    int i;
+
+    offset -= s->base + 0x1000;
+    if (offset < 0x100) {
+        if (offset == 0)
+            return s->enabled;
+        if (offset == 4)
+            return (GIC_NIRQ / 32) - 1;
+        if (offset < 0x08)
+            return 0;
+        goto bad_reg;
+    } else if (offset < 0x200) {
+        /* Interrupt Set/Clear Enable.  */
+        if (offset < 0x180)
+            irq = (offset - 0x100) * 8;
+        else
+            irq = (offset - 0x180) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ENABLED(irq + i)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Set/Clear Pending.  */
+        if (offset < 0x280)
+            irq = (offset - 0x200) * 8;
+        else
+            irq = (offset - 0x280) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_PENDING(irq + i)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        irq = (offset - 0x300) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 8; i++) {
+            if (GIC_TEST_ACTIVE(irq + i)) {
+                res |= (1 << i);
+            }
+        }
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = offset - 0x400;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = s->priority[irq];
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target.  */
+        irq = offset - 0x800;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = s->irq_target[irq];
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 2;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        res = 0;
+        for (i = 0; i < 4; i++) {
+            if (GIC_TEST_MODEL(irq + i))
+                res |= (1 << (i * 2));
+            if (GIC_TEST_TRIGGER(irq + i))
+                res |= (2 << (i * 2));
+        }
+    } else if (offset < 0xfe0) {
+        goto bad_reg;
+    } else /* offset >= 0xfe0 */ {
+        if (offset & 3) {
+            res = 0;
+        } else {
+            res = gic_id[(offset - 0xfe0) >> 2];
+        }
+    }
+    return res;
+bad_reg:
+    cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset);
+    return 0;
+}
+
+static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = gic_dist_readb(opaque, offset);
+    val |= gic_dist_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = gic_dist_readw(opaque, offset);
+    val |= gic_dist_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    gic_state *s = (gic_state *)opaque;
+    int irq;
+    int i;
+
+    offset -= s->base + 0x1000;
+    if (offset < 0x100) {
+        if (offset == 0) {
+            s->enabled = (value & 1);
+            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
+        } else if (offset < 4) {
+            /* ignored.  */
+        } else {
+            goto bad_reg;
+        }
+    } else if (offset < 0x180) {
+        /* Interrupt Set Enable.  */
+        irq = (offset - 0x100) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                if (!GIC_TEST_ENABLED(irq + i))
+                    DPRINTF("Enabled IRQ %d\n", irq + i);
+                GIC_SET_ENABLED(irq + i);
+                /* If a raised level triggered IRQ enabled then mark
+                   is as pending.  */
+                if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i))
+                    GIC_SET_PENDING(irq + i);
+            }
+        }
+    } else if (offset < 0x200) {
+        /* Interrupt Clear Enable.  */
+        irq = (offset - 0x180) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                if (GIC_TEST_ENABLED(irq + i))
+                    DPRINTF("Disabled IRQ %d\n", irq + i);
+                GIC_CLEAR_ENABLED(irq + i);
+            }
+        }
+    } else if (offset < 0x280) {
+        /* Interrupt Set Pending.  */
+        irq = (offset - 0x200) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                GIC_SET_PENDING(irq + i);
+            }
+        }
+    } else if (offset < 0x300) {
+        /* Interrupt Clear Pending.  */
+        irq = (offset - 0x280) * 8;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        for (i = 0; i < 8; i++) {
+            if (value & (1 << i)) {
+                GIC_CLEAR_PENDING(irq + i);
+            }
+        }
+    } else if (offset < 0x400) {
+        /* Interrupt Active.  */
+        goto bad_reg;
+    } else if (offset < 0x800) {
+        /* Interrupt Priority.  */
+        irq = offset - 0x400;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        s->priority[irq] = value;
+    } else if (offset < 0xc00) {
+        /* Interrupt CPU Target.  */
+        irq = offset - 0x800;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        s->irq_target[irq] = value;
+    } else if (offset < 0xf00) {
+        /* Interrupt Configuration.  */
+        irq = (offset - 0xc00) * 2;
+        if (irq >= GIC_NIRQ)
+            goto bad_reg;
+        for (i = 0; i < 4; i++) {
+            if (value & (1 << (i * 2))) {
+                GIC_SET_MODEL(irq + i);
+            } else {
+                GIC_CLEAR_MODEL(irq + i);
+            }
+            if (value & (2 << (i * 2))) {
+                GIC_SET_TRIGGER(irq + i);
+            } else {
+                GIC_CLEAR_TRIGGER(irq + i);
+            }
+        }
+    } else {
+        /* 0xf00 is only handled for word writes.  */
+        goto bad_reg;
+    }
+    gic_update(s);
+    return;
+bad_reg:
+    cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset);
+}
+
+static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    gic_state *s = (gic_state *)opaque;
+    if (offset - s->base == 0xf00) {
+        GIC_SET_PENDING(value & 0x3ff);
+        gic_update(s);
+        return;
+    }
+    gic_dist_writeb(opaque, offset, value & 0xff);
+    gic_dist_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    gic_dist_writew(opaque, offset, value & 0xffff);
+    gic_dist_writew(opaque, offset + 2, value >> 16);
+}
+
+static CPUReadMemoryFunc *gic_dist_readfn[] = {
+   gic_dist_readb,
+   gic_dist_readw,
+   gic_dist_readl
+};
+
+static CPUWriteMemoryFunc *gic_dist_writefn[] = {
+   gic_dist_writeb,
+   gic_dist_writew,
+   gic_dist_writel
+};
+
+static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset)
+{
+    gic_state *s = (gic_state *)opaque;
+    offset -= s->base;
+    switch (offset) {
+    case 0x00: /* Control */
+        return s->cpu_enabled;
+    case 0x04: /* Priority mask */
+        return s->priority_mask;
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        return 0;
+    case 0x0c: /* Acknowledge */
+        return gic_acknowledge_irq(s);
+    case 0x14: /* Runing Priority */
+        return s->running_priority;
+    case 0x18: /* Highest Pending Interrupt */
+        return s->current_pending;
+    default:
+        cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void gic_cpu_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    gic_state *s = (gic_state *)opaque;
+    offset -= s->base;
+    switch (offset) {
+    case 0x00: /* Control */
+        s->cpu_enabled = (value & 1);
+        DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
+        break;
+    case 0x04: /* Priority mask */
+        s->priority_mask = (value & 0x3ff);
+        break;
+    case 0x08: /* Binary Point */
+        /* ??? Not implemented.  */
+        break;
+    case 0x10: /* End Of Interrupt */
+        return gic_complete_irq(s, value & 0x3ff);
+    default:
+        cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
+        return;
+    }
+    gic_update(s);
+}
+
+static CPUReadMemoryFunc *gic_cpu_readfn[] = {
+   gic_cpu_read,
+   gic_cpu_read,
+   gic_cpu_read
+};
+
+static CPUWriteMemoryFunc *gic_cpu_writefn[] = {
+   gic_cpu_write,
+   gic_cpu_write,
+   gic_cpu_write
+};
+
+static void gic_reset(gic_state *s)
+{
+    int i;
+    memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
+    s->priority_mask = 0xf0;
+    s->current_pending = 1023;
+    s->running_irq = 1023;
+    s->running_priority = 0x100;
+    for (i = 0; i < 15; i++) {
+        GIC_SET_ENABLED(i);
+        GIC_SET_TRIGGER(i);
+    }
+    s->enabled = 0;
+    s->cpu_enabled = 0;
+}
+
+void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
+{
+    gic_state *s;
+    int iomemtype;
+
+    s = (gic_state *)qemu_mallocz(sizeof(gic_state));
+    if (!s)
+        return NULL;
+    s->handler = gic_set_irq;
+    s->parent = parent;
+    s->parent_irq = parent_irq;
+    if (base != 0xffffffff) {
+        iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
+                                           gic_cpu_writefn, s);
+        cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+        iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
+                                           gic_dist_writefn, s);
+        cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype);
+        s->base = base;
+    } else {
+        s->base = 0;
+    }
+    gic_reset(s);
+    return s;
+}
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
new file mode 100644
index 0000000..e9de998
--- /dev/null
+++ b/hw/arm_sysctl.c
@@ -0,0 +1,208 @@
+/* 
+ * Status and system control registers for ARM RealView/Versatile boards.
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+#include "arm_pic.h"
+
+#define LOCK_VALUE 0xa05f
+
+typedef struct {
+    uint32_t base;
+    uint32_t sys_id;
+    uint32_t leds;
+    uint16_t lockval;
+    uint32_t cfgdata1;
+    uint32_t cfgdata2;
+    uint32_t flags;
+    uint32_t nvflags;
+    uint32_t resetlevel;
+} arm_sysctl_state;
+
+static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+
+    offset -= s->base;
+    switch (offset) {
+    case 0x00: /* ID */
+        return s->sys_id;
+    case 0x04: /* SW */
+        /* General purpose hardware switches.
+           We don't have a useful way of exposing these to the user.  */
+        return 0;
+    case 0x08: /* LED */
+        return s->leds;
+    case 0x20: /* LOCK */
+        return s->lockval;
+    case 0x0c: /* OSC0 */
+    case 0x10: /* OSC1 */
+    case 0x14: /* OSC2 */
+    case 0x18: /* OSC3 */
+    case 0x1c: /* OSC4 */
+    case 0x24: /* 100HZ */
+        /* ??? Implement these.  */
+        return 0;
+    case 0x28: /* CFGDATA1 */
+        return s->cfgdata1;
+    case 0x2c: /* CFGDATA2 */
+        return s->cfgdata2;
+    case 0x30: /* FLAGS */
+        return s->flags;
+    case 0x38: /* NVFLAGS */
+        return s->nvflags;
+    case 0x40: /* RESETCTL */
+        return s->resetlevel;
+    case 0x44: /* PCICTL */
+        return 1;
+    case 0x48: /* MCI */
+        return 0;
+    case 0x4c: /* FLASH */
+        return 0;
+    case 0x50: /* CLCD */
+        return 0x1000;
+    case 0x54: /* CLCDSER */
+        return 0;
+    case 0x58: /* BOOTCS */
+        return 0;
+    case 0x5c: /* 24MHz */
+        /* ??? not implemented.  */
+        return 0;
+    case 0x60: /* MISC */
+        return 0;
+    case 0x84: /* PROCID0 */
+        /* ??? Don't know what the proper value for the core tile ID is.  */
+        return 0x02000000;
+    case 0x88: /* PROCID1 */
+        return 0xff000000;
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x70: /* IOSEL */
+    case 0x74: /* PLDCTL */
+    case 0x80: /* BUSID */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+    case 0xc0: /* SYS_TEST_OSC0 */
+    case 0xc4: /* SYS_TEST_OSC1 */
+    case 0xc8: /* SYS_TEST_OSC2 */
+    case 0xcc: /* SYS_TEST_OSC3 */
+    case 0xd0: /* SYS_TEST_OSC4 */
+        return 0;
+    default:
+        printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t val)
+{
+    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case 0x08: /* LED */
+        s->leds = val;
+    case 0x0c: /* OSC0 */
+    case 0x10: /* OSC1 */
+    case 0x14: /* OSC2 */
+    case 0x18: /* OSC3 */
+    case 0x1c: /* OSC4 */
+        /* ??? */
+        break;
+    case 0x20: /* LOCK */
+        if (val == LOCK_VALUE)
+            s->lockval = val;
+        else
+            s->lockval = val & 0x7fff;
+        break;
+    case 0x28: /* CFGDATA1 */
+        /* ??? Need to implement this.  */
+        s->cfgdata1 = val;
+        break;
+    case 0x2c: /* CFGDATA2 */
+        /* ??? Need to implement this.  */
+        s->cfgdata2 = val;
+        break;
+    case 0x30: /* FLAGSSET */
+        s->flags |= val;
+        break;
+    case 0x34: /* FLAGSCLR */
+        s->flags &= ~val;
+        break;
+    case 0x38: /* NVFLAGSSET */
+        s->nvflags |= val;
+        break;
+    case 0x3c: /* NVFLAGSCLR */
+        s->nvflags &= ~val;
+        break;
+    case 0x40: /* RESETCTL */
+        if (s->lockval == LOCK_VALUE) {
+            s->resetlevel = val;
+            if (val & 0x100)
+                cpu_abort(cpu_single_env, "Board reset\n");
+        }
+        break;
+    case 0x44: /* PCICTL */
+        /* nothing to do.  */
+        break;
+    case 0x4c: /* FLASH */
+    case 0x50: /* CLCD */
+    case 0x54: /* CLCDSER */
+    case 0x64: /* DMAPSR0 */
+    case 0x68: /* DMAPSR1 */
+    case 0x6c: /* DMAPSR2 */
+    case 0x70: /* IOSEL */
+    case 0x74: /* PLDCTL */
+    case 0x80: /* BUSID */
+    case 0x84: /* PROCID0 */
+    case 0x88: /* PROCID1 */
+    case 0x8c: /* OSCRESET0 */
+    case 0x90: /* OSCRESET1 */
+    case 0x94: /* OSCRESET2 */
+    case 0x98: /* OSCRESET3 */
+    case 0x9c: /* OSCRESET4 */
+        break;
+    default:
+        printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
+        return;
+    }
+}
+
+static CPUReadMemoryFunc *arm_sysctl_readfn[] = {
+   arm_sysctl_read,
+   arm_sysctl_read,
+   arm_sysctl_read
+};
+
+static CPUWriteMemoryFunc *arm_sysctl_writefn[] = {
+   arm_sysctl_write,
+   arm_sysctl_write,
+   arm_sysctl_write
+};
+
+void arm_sysctl_init(uint32_t base, uint32_t sys_id)
+{
+    arm_sysctl_state *s;
+    int iomemtype;
+
+    s = (arm_sysctl_state *)qemu_mallocz(sizeof(arm_sysctl_state));
+    if (!s)
+        return;
+    s->base = base;
+    s->sys_id = sys_id;
+    iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn,
+                                       arm_sysctl_writefn, s);
+    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    /* ??? Save/restore.  */
+}
+
diff --git a/hw/pl080.c b/hw/pl080.c
index 49996ca..549b3bf 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -1,5 +1,5 @@
 /* 
- * Arm PrimeCell PL080 DMA controller
+ * Arm PrimeCell PL080/PL081 DMA controller
  *
  * Copyright (c) 2006 CodeSourcery.
  * Written by Paul Brook
@@ -9,7 +9,7 @@
 
 #include "vl.h"
 
-#define PL080_NUM_CHANNELS 8
+#define PL080_MAX_CHANNELS 8
 #define PL080_CONF_E    0x1
 #define PL080_CONF_M1   0x2
 #define PL080_CONF_M2   0x4
@@ -45,7 +45,8 @@
     uint32_t sync;
     uint32_t req_single;
     uint32_t req_burst;
-    pl080_channel chan[PL080_NUM_CHANNELS];
+    pl080_channel chan[PL080_MAX_CHANNELS];
+    int nchannels;
     /* Flag to avoid recursive DMA invocations.  */
     int running;
     void *pic;
@@ -55,6 +56,9 @@
 static const unsigned char pl080_id[] =
 { 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
 
+static const unsigned char pl081_id[] =
+{ 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
+
 static void pl080_update(pl080_state *s)
 {
     if ((s->tc_int & s->tc_mask)
@@ -80,7 +84,7 @@
     uint32_t req;
 
     s->tc_mask = 0;
-    for (c = 0; c < PL080_NUM_CHANNELS; c++) {
+    for (c = 0; c < s->nchannels; c++) {
         if (s->chan[c].conf & PL080_CCONF_ITC)
             s->tc_mask |= 1 << c;
         if (s->chan[c].conf & PL080_CCONF_IE)
@@ -99,7 +103,7 @@
     }
     s->running = 1;
     while (s->running) {
-        for (c = 0; c < PL080_NUM_CHANNELS; c++) {
+        for (c = 0; c < s->nchannels; c++) {
             ch = &s->chan[c];
 again:
             /* Test if thiws channel has any pending DMA requests.  */
@@ -185,10 +189,16 @@
 
     offset -= s->base;
     if (offset >= 0xfe0 && offset < 0x1000) {
-        return pl080_id[(offset - 0xfe0) >> 2];
+        if (s->nchannels == 8) {
+            return pl080_id[(offset - 0xfe0) >> 2];
+        } else {
+            return pl081_id[(offset - 0xfe0) >> 2];
+        }
     }
     if (offset >= 0x100 && offset < 0x200) {
         i = (offset & 0xe0) >> 5;
+        if (i >= s->nchannels)
+            goto bad_offset;
         switch (offset >> 2) {
         case 0: /* SrcAddr */
             return s->chan[i].src;
@@ -217,7 +227,7 @@
         return s->err_int;
     case 7: /* EnbldChns */
         mask = 0;
-        for (i = 0; i < PL080_NUM_CHANNELS; i++) {
+        for (i = 0; i < s->nchannels; i++) {
             if (s->chan[i].conf & PL080_CCONF_E)
                 mask |= 1 << i;
         }
@@ -248,6 +258,8 @@
     offset -= s->base;
     if (offset >= 0x100 && offset < 0x200) {
         i = (offset & 0xe0) >> 5;
+        if (i >= s->nchannels)
+            goto bad_offset;
         switch (offset >> 2) {
         case 0: /* SrcAddr */
             s->chan[i].src = value;
@@ -293,6 +305,7 @@
         s->sync = value;
         break;
     default:
+    bad_offset:
         cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset);
     }
     pl080_update(s);
@@ -310,7 +323,9 @@
    pl080_write
 };
 
-void *pl080_init(uint32_t base, void *pic, int irq)
+/* The PL080 and PL081 are the same except for the number of channels
+   they implement (8 and 2 respectively).  */
+void *pl080_init(uint32_t base, void *pic, int irq, int nchannels)
 {
     int iomemtype;
     pl080_state *s;
@@ -322,6 +337,7 @@
     s->base = base;
     s->pic = pic;
     s->irq = irq;
+    s->nchannels = nchannels;
     /* ??? Save/restore.  */
     return s;
 }
diff --git a/hw/realview.c b/hw/realview.c
new file mode 100644
index 0000000..11b0916
--- /dev/null
+++ b/hw/realview.c
@@ -0,0 +1,138 @@
+/* 
+ * ARM RealView Baseboard System emulation.
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+#include "arm_pic.h"
+
+/* Board init.  */
+
+static void realview_init(int ram_size, int vga_ram_size, int boot_device,
+                     DisplayState *ds, const char **fd_filename, int snapshot,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename)
+{
+    CPUState *env;
+    void *pic;
+    void *scsi_hba;
+    PCIBus *pci_bus;
+    NICInfo *nd;
+    int n;
+    int done_smc = 0;
+
+    env = cpu_init();
+    cpu_arm_set_model(env, ARM_CPUID_ARM926);
+    //cpu_arm_set_model(env, ARM_CPUID_ARM11MPCORE);
+    /* ??? RAM shoud repeat to fill physical memory space.  */
+    /* SDRAM at address zero.  */
+    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+
+    arm_sysctl_init(0x10000000, 0xc1400400);
+    pic = arm_pic_init_cpu(env);
+    /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
+       is nIRQ (there are inconsistencies).  However Linux 2.6.17 expects
+       GIC1 to be nIRQ and ignores all the others, so do that for now.  */
+    pic = arm_gic_init(0x10040000, pic, ARM_PIC_CPU_IRQ);
+    pl050_init(0x10006000, pic, 20, 0);
+    pl050_init(0x10007000, pic, 21, 1);
+
+    pl011_init(0x10009000, pic, 12, serial_hds[0]);
+    pl011_init(0x1000a000, pic, 13, serial_hds[1]);
+    pl011_init(0x1000b000, pic, 14, serial_hds[2]);
+    pl011_init(0x1000c000, pic, 15, serial_hds[3]);
+
+    /* DMA controller is optional, apparently.  */
+    pl080_init(0x10030000, pic, 24, 2);
+
+    sp804_init(0x10011000, pic, 4);
+    sp804_init(0x10012000, pic, 5);
+
+    pl110_init(ds, 0x10020000, pic, 23, 1);
+
+    pci_bus = pci_vpb_init(pic, 48, 1);
+    if (usb_enabled) {
+        usb_ohci_init(pci_bus, 3, -1);
+    }
+    scsi_hba = lsi_scsi_init(pci_bus, -1);
+    for (n = 0; n < MAX_DISKS; n++) {
+        if (bs_table[n]) {
+            lsi_scsi_attach(scsi_hba, bs_table[n], n);
+        }
+    }
+    for(n = 0; n < nb_nics; n++) {
+        nd = &nd_table[n];
+        if (!nd->model)
+            nd->model = done_smc ? "rtl8139" : "smc91c111";
+        if (strcmp(nd->model, "smc91c111") == 0) {
+            smc91c111_init(nd, 0x4e000000, pic, 28);
+        } else {
+            pci_nic_init(pci_bus, nd);
+        }
+    }
+
+    /* Memory map for RealView Emulation Baseboard:  */
+    /* 0x10000000 System registers.  */
+    /*  0x10001000 System controller.  */
+    /*  0x10002000 Two-Wire Serial Bus.  */
+    /* 0x10003000 Reserved.  */
+    /*  0x10004000 AACI.  */
+    /*  0x10005000 MCI.  */
+    /* 0x10006000 KMI0.  */
+    /* 0x10007000 KMI1.  */
+    /*  0x10008000 Character LCD.  */
+    /* 0x10009000 UART0.  */
+    /* 0x1000a000 UART1.  */
+    /* 0x1000b000 UART2.  */
+    /* 0x1000c000 UART3.  */
+    /*  0x1000d000 SSPI.  */
+    /*  0x1000e000 SCI.  */
+    /* 0x1000f000 Reserved.  */
+    /*  0x10010000 Watchdog.  */
+    /* 0x10011000 Timer 0+1.  */
+    /* 0x10012000 Timer 2+3.  */
+    /*  0x10013000 GPIO 0.  */
+    /*  0x10014000 GPIO 1.  */
+    /*  0x10015000 GPIO 2.  */
+    /* 0x10016000 Reserved.  */
+    /*  0x10017000 RTC.  */
+    /*  0x10018000 DMC.  */
+    /*  0x10019000 PCI controller config.  */
+    /*  0x10020000 CLCD.  */
+    /* 0x10030000 DMA Controller.  */
+    /* 0x10040000 GIC1 (FIQ1).  */
+    /* 0x10050000 GIC2 (IRQ1).  */
+    /*  0x10060000 GIC3 (FIQ2).  */
+    /*  0x10070000 GIC4 (IRQ2).  */
+    /*  0x10080000 SMC.  */
+    /*  0x40000000 NOR flash.  */
+    /*  0x44000000 DoC flash.  */
+    /*  0x48000000 SRAM.  */
+    /*  0x4c000000 Configuration flash.  */
+    /* 0x4e000000 Ethernet.  */
+    /*  0x4f000000 USB.  */
+    /*  0x50000000 PISMO.  */
+    /*  0x54000000 PISMO.  */
+    /*  0x58000000 PISMO.  */
+    /*  0x5c000000 PISMO.  */
+    /* 0x60000000 PCI.  */
+    /* 0x61000000 PCI Self Config.  */
+    /* 0x62000000 PCI Config.  */
+    /* 0x63000000 PCI IO.  */
+    /* 0x64000000 PCI mem 0.  */
+    /* 0x68000000 PCI mem 1.  */
+    /* 0x6c000000 PCI mem 2.  */
+
+    arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
+                    initrd_filename, 0x33b);
+}
+
+QEMUMachine realview_machine = {
+    "realview",
+    "ARM RealView Emulation Baseboard (ARM926EJ-S)",
+    realview_init
+};
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 34a4bc6..aac61c7 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -77,31 +77,49 @@
     &pci_vpb_config_readl,
 };
 
+static int pci_vpb_irq;
+
 static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
 {
-    pic_set_irq_new(pic, 27 + irq_num, level);
+    pic_set_irq_new(pic, pci_vpb_irq + irq_num, level);
 }
 
-PCIBus *pci_vpb_init(void *pic)
+PCIBus *pci_vpb_init(void *pic, int irq, int realview)
 {
     PCIBus *s;
     PCIDevice *d;
     int mem_config;
+    uint32_t base;
+    const char * name;
 
+    pci_vpb_irq = irq;
+    if (realview) {
+        base = 0x60000000;
+        name = "RealView EB PCI Controller";
+    } else {
+        base = 0x40000000;
+        name = "Versatile/PB PCI Controller";
+    }
     s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3);
     /* ??? Register memory space.  */
 
     mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
                                         pci_vpb_config_write, s);
     /* Selfconfig area.  */
-    cpu_register_physical_memory(0x41000000, 0x10000, mem_config);
+    cpu_register_physical_memory(base + 0x01000000, 0x10000, mem_config);
     /* Normal config area.  */
-    cpu_register_physical_memory(0x42000000, 0x10000, mem_config);
+    cpu_register_physical_memory(base + 0x02000000, 0x10000, mem_config);
 
-    d = pci_register_device(s, "Versatile/PB PCI Controller",
-                            sizeof(PCIDevice), -1, NULL, NULL);
+    d = pci_register_device(s, name, sizeof(PCIDevice), -1, NULL, NULL);
+
+    if (realview) {
+        /* IO memory area.  */
+        isa_mmio_init(base + 0x03000000, 0x00100000);
+    }
+
     d->config[0x00] = 0xee; // vendor_id
     d->config[0x01] = 0x10;
+    /* Both boards have the same device ID.  Oh well.  */
     d->config[0x02] = 0x00; // device_id
     d->config[0x03] = 0x03;
     d->config[0x04] = 0x00;
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 28ec137..475cb48 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -10,8 +10,6 @@
 #include "vl.h"
 #include "arm_pic.h"
 
-#define LOCK_VALUE 0xa05f
-
 /* Primary interrupt controller.  */
 
 typedef struct vpb_sic_state
@@ -75,7 +73,7 @@
     case 8: /* PICENABLE */
         return s->pic_enable;
     default:
-        printf ("vpb_sic_read: Bad register offset 0x%x\n", offset);
+        printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
         return 0;
     }
 }
@@ -110,7 +108,7 @@
         vpb_sic_update_pic(s);
         break;
     default:
-        printf ("vpb_sic_write: Bad register offset 0x%x\n", offset);
+        printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
         return;
     }
     vpb_sic_update(s);
@@ -147,188 +145,6 @@
     return s;
 }
 
-/* System controller.  */
-
-typedef struct {
-    uint32_t base;
-    uint32_t leds;
-    uint16_t lockval;
-    uint32_t cfgdata1;
-    uint32_t cfgdata2;
-    uint32_t flags;
-    uint32_t nvflags;
-    uint32_t resetlevel;
-} vpb_sys_state;
-
-static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
-{
-    vpb_sys_state *s = (vpb_sys_state *)opaque;
-
-    offset -= s->base;
-    switch (offset) {
-    case 0x00: /* ID */
-        return 0x41007004;
-    case 0x04: /* SW */
-        /* General purpose hardware switches.
-           We don't have a useful way of exposing these to the user.  */
-        return 0;
-    case 0x08: /* LED */
-        return s->leds;
-    case 0x20: /* LOCK */
-        return s->lockval;
-    case 0x0c: /* OSC0 */
-    case 0x10: /* OSC1 */
-    case 0x14: /* OSC2 */
-    case 0x18: /* OSC3 */
-    case 0x1c: /* OSC4 */
-    case 0x24: /* 100HZ */
-        /* ??? Implement these.  */
-        return 0;
-    case 0x28: /* CFGDATA1 */
-        return s->cfgdata1;
-    case 0x2c: /* CFGDATA2 */
-        return s->cfgdata2;
-    case 0x30: /* FLAGS */
-        return s->flags;
-    case 0x38: /* NVFLAGS */
-        return s->nvflags;
-    case 0x40: /* RESETCTL */
-        return s->resetlevel;
-    case 0x44: /* PCICTL */
-        return 1;
-    case 0x48: /* MCI */
-        return 0;
-    case 0x4c: /* FLASH */
-        return 0;
-    case 0x50: /* CLCD */
-        return 0x1000;
-    case 0x54: /* CLCDSER */
-        return 0;
-    case 0x58: /* BOOTCS */
-        return 0;
-    case 0x5c: /* 24MHz */
-        /* ??? not implemented.  */
-        return 0;
-    case 0x60: /* MISC */
-        return 0;
-    case 0x64: /* DMAPSR0 */
-    case 0x68: /* DMAPSR1 */
-    case 0x6c: /* DMAPSR2 */
-    case 0x8c: /* OSCRESET0 */
-    case 0x90: /* OSCRESET1 */
-    case 0x94: /* OSCRESET2 */
-    case 0x98: /* OSCRESET3 */
-    case 0x9c: /* OSCRESET4 */
-    case 0xc0: /* SYS_TEST_OSC0 */
-    case 0xc4: /* SYS_TEST_OSC1 */
-    case 0xc8: /* SYS_TEST_OSC2 */
-    case 0xcc: /* SYS_TEST_OSC3 */
-    case 0xd0: /* SYS_TEST_OSC4 */
-        return 0;
-    default:
-        printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
-        return 0;
-    }
-}
-
-static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
-                          uint32_t val)
-{
-    vpb_sys_state *s = (vpb_sys_state *)opaque;
-    offset -= s->base;
-
-    switch (offset) {
-    case 0x08: /* LED */
-        s->leds = val;
-    case 0x0c: /* OSC0 */
-    case 0x10: /* OSC1 */
-    case 0x14: /* OSC2 */
-    case 0x18: /* OSC3 */
-    case 0x1c: /* OSC4 */
-        /* ??? */
-        break;
-    case 0x20: /* LOCK */
-        if (val == LOCK_VALUE)
-            s->lockval = val;
-        else
-            s->lockval = val & 0x7fff;
-        break;
-    case 0x28: /* CFGDATA1 */
-        /* ??? Need to implement this.  */
-        s->cfgdata1 = val;
-        break;
-    case 0x2c: /* CFGDATA2 */
-        /* ??? Need to implement this.  */
-        s->cfgdata2 = val;
-        break;
-    case 0x30: /* FLAGSSET */
-        s->flags |= val;
-        break;
-    case 0x34: /* FLAGSCLR */
-        s->flags &= ~val;
-        break;
-    case 0x38: /* NVFLAGSSET */
-        s->nvflags |= val;
-        break;
-    case 0x3c: /* NVFLAGSCLR */
-        s->nvflags &= ~val;
-        break;
-    case 0x40: /* RESETCTL */
-        if (s->lockval == LOCK_VALUE) {
-            s->resetlevel = val;
-            if (val & 0x100)
-                cpu_abort(cpu_single_env, "Board reset\n");
-        }
-        break;
-    case 0x44: /* PCICTL */
-        /* nothing to do.  */
-        break;
-    case 0x4c: /* FLASH */
-    case 0x50: /* CLCD */
-    case 0x54: /* CLCDSER */
-    case 0x64: /* DMAPSR0 */
-    case 0x68: /* DMAPSR1 */
-    case 0x6c: /* DMAPSR2 */
-    case 0x8c: /* OSCRESET0 */
-    case 0x90: /* OSCRESET1 */
-    case 0x94: /* OSCRESET2 */
-    case 0x98: /* OSCRESET3 */
-    case 0x9c: /* OSCRESET4 */
-        break;
-    default:
-        printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
-        return;
-    }
-}
-
-static CPUReadMemoryFunc *vpb_sys_readfn[] = {
-   vpb_sys_read,
-   vpb_sys_read,
-   vpb_sys_read
-};
-
-static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
-   vpb_sys_write,
-   vpb_sys_write,
-   vpb_sys_write
-};
-
-static vpb_sys_state *vpb_sys_init(uint32_t base)
-{
-    vpb_sys_state *s;
-    int iomemtype;
-
-    s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
-    if (!s)
-        return NULL;
-    s->base = base;
-    iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
-                                       vpb_sys_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
-    /* ??? Save/restore.  */
-    return s;
-}
-
 /* Board init.  */
 
 /* The AB and PB boards both use the same core, just with different
@@ -355,14 +171,14 @@
     /* SDRAM at address zero.  */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 
-    vpb_sys_init(0x10000000);
+    arm_sysctl_init(0x10000000, 0x41007004);
     pic = arm_pic_init_cpu(env);
     pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
     sic = vpb_sic_init(0x10003000, pic, 31);
     pl050_init(0x10006000, sic, 3, 0);
     pl050_init(0x10007000, sic, 4, 1);
 
-    pci_bus = pci_vpb_init(sic);
+    pci_bus = pci_vpb_init(sic, 27, 0);
     /* The Versatile PCI bridge does not provide access to PCI IO space,
        so many of the qemu PCI devices are not useable.  */
     for(n = 0; n < nb_nics; n++) {
@@ -390,7 +206,7 @@
     pl011_init(0x101f3000, pic, 14, serial_hds[2]);
     pl011_init(0x10009000, sic, 6, serial_hds[3]);
 
-    pl080_init(0x10130000, pic, 17);
+    pl080_init(0x10130000, pic, 17, 8);
     sp804_init(0x101e2000, pic, 4);
     sp804_init(0x101e3000, pic, 5);
 
diff --git a/vl.c b/vl.c
index d422fed..d3efbbd 100644
--- a/vl.c
+++ b/vl.c
@@ -6150,6 +6150,7 @@
     qemu_register_machine(&integratorcp1026_machine);
     qemu_register_machine(&versatilepb_machine);
     qemu_register_machine(&versatileab_machine);
+    qemu_register_machine(&realview_machine);
 #elif defined(TARGET_SH4)
     qemu_register_machine(&shix_machine);
 #else
diff --git a/vl.h b/vl.h
index e16fd92..fef2ef8 100644
--- a/vl.h
+++ b/vl.h
@@ -778,7 +778,7 @@
 PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
                      void *pic);
 
-PCIBus *pci_vpb_init(void *pic);
+PCIBus *pci_vpb_init(void *pic, int irq, int realview);
 
 /* piix_pci.c */
 PCIBus *i440fx_init(void);
@@ -1222,6 +1222,9 @@
 extern QEMUMachine versatilepb_machine;
 extern QEMUMachine versatileab_machine;
 
+/* realview.c */
+extern QEMUMachine realview_machine;
+
 /* ps2.c */
 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
@@ -1244,7 +1247,7 @@
 void pl050_init(uint32_t base, void *pic, int irq, int is_mouse);
 
 /* pl080.c */
-void *pl080_init(uint32_t base, void *pic, int irq);
+void *pl080_init(uint32_t base, void *pic, int irq, int nchannels);
 
 /* pl190.c */
 void *pl190_init(uint32_t base, void *parent, int irq, int fiq);
@@ -1253,6 +1256,12 @@
 void sp804_init(uint32_t base, void *pic, int irq);
 void icp_pit_init(uint32_t base, void *pic, int irq);
 
+/* arm_sysctl.c */
+void arm_sysctl_init(uint32_t base, uint32_t sys_id);
+
+/* arm_gic.c */
+void *arm_gic_init(uint32_t base, void *parent, int parent_irq);
+
 /* arm_boot.c */
 
 void arm_load_kernel(int ram_size, const char *kernel_filename,