diff --git a/exec.c b/exec.c
index 5ef911b..493818a 100644
--- a/exec.c
+++ b/exec.c
@@ -67,12 +67,10 @@
 
 //#define DEBUG_TB_INVALIDATE
 //#define DEBUG_FLUSH
-//#define DEBUG_UNASSIGNED
 
 /* make various TB consistency checks */
 //#define DEBUG_TB_CHECK
 
-//#define DEBUG_IOPORT
 //#define DEBUG_SUBPAGE
 
 #if !defined(CONFIG_USER_ONLY)
@@ -2334,33 +2332,37 @@ void cpu_register_physical_memory_log(MemoryRegionSection *section,
     }
 }
 
-#if defined(TARGET_ARM)
-#include <disas.h>
-static const char *backtrace(char *buffer, size_t length)
+static int qemu_target_backtrace(target_ulong *array, size_t size)
 {
-    char *p = buffer;
-    if (cpu_single_env) {
-        const char *symbol;
-        symbol = lookup_symbol(cpu_single_env->regs[15]);
-        p += sprintf(p, "[%s]", symbol);
-        symbol = lookup_symbol(cpu_single_env->regs[14]);
-        p += sprintf(p, "[%s]", symbol);
-    } else {
-        p += sprintf(p, "[cpu not running]");
+    int n = 0;
+    if (size >= 2) {
+#if defined(TARGET_ARM)
+        array[0] = cpu_single_env->regs[15];
+        array[1] = cpu_single_env->regs[14];
+#elif defined(TARGET_MIPS)
+        array[0] = cpu_single_env->active_tc.PC;
+        array[1] = cpu_single_env->active_tc.gpr[31];
+#else
+        array[0] = 0;
+        array[1] = 0;
+#endif
+        n = 2;
     }
-    assert((p - buffer) < length);
-    return buffer;
+    return n;
 }
-#elif defined(TARGET_MIPS)
+
 #include <disas.h>
-static const char *backtrace(char *buffer, size_t length)
+const char *qemu_sprint_backtrace(char *buffer, size_t length);
+const char *qemu_sprint_backtrace(char *buffer, size_t length)
 {
     char *p = buffer;
     if (cpu_single_env) {
+        target_ulong caller[2];
         const char *symbol;
-        symbol = lookup_symbol(cpu_single_env->active_tc.PC);
+        qemu_target_backtrace(caller, 2);
+        symbol = lookup_symbol(caller[0]);
         p += sprintf(p, "[%s]", symbol);
-        symbol = lookup_symbol(cpu_single_env->active_tc.gpr[31]);
+        symbol = lookup_symbol(caller[1]);
         p += sprintf(p, "[%s]", symbol);
     } else {
         p += sprintf(p, "[cpu not running]");
@@ -2368,12 +2370,6 @@ static const char *backtrace(char *buffer, size_t length)
     assert((p - buffer) < length);
     return buffer;
 }
-#else
-static const char *backtrace(char *buffer, size_t length)
-{
-    return "unknown caller";
-}
-#endif /* TARGET_MIPS */
 
 void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
 {
@@ -2878,7 +2874,7 @@ static uint64_t unassigned_mem_read(void *opaque, target_phys_addr_t addr,
     if (trace_unassigned) {
         char buffer[256];
         fprintf(stderr, "Unassigned mem read " TARGET_FMT_plx " %s\n",
-                addr, backtrace(buffer, sizeof(buffer)));
+                addr, qemu_sprint_backtrace(buffer, sizeof(buffer)));
     }
     //~ vm_stop(0);
 #if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
@@ -2893,7 +2889,7 @@ static void unassigned_mem_write(void *opaque, target_phys_addr_t addr,
     if (trace_unassigned) {
         char buffer[256];
         fprintf(stderr, "Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64" %s\n",
-                addr, val, backtrace(buffer, sizeof(buffer)));
+                addr, val, qemu_sprint_backtrace(buffer, sizeof(buffer)));
     }
 #if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
     cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index fed471c..c9dbce8 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -57,3 +57,5 @@ obj-y += pl041.o lm4549.o
 obj-$(CONFIG_FDT) += ../device_tree.o
 
 obj-y := $(addprefix ../,$(obj-y))
+
+obj-y += raspi.o
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
new file mode 100644
index 0000000..685441c
--- /dev/null
+++ b/hw/arm/raspi.c
@@ -0,0 +1,956 @@
+/*
+ * ARM Raspberry Pi System emulation.
+ *
+ * Copyright (c) 2012 Stefan Weil
+ *
+ * This code is licensed under the GNU GPL 2 or later.
+ *
+ * This very basic emulation of Broadcom's BCM2835 media processor
+ * works (partially as of 2012-07) with the Linux BCM2708 code.
+ *
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0183g/DDI0183G_uart_pl011_r1p5_trm.pdf
+ * http://elinux.org/RPi_Framebuffer
+ * https://github.com/raspberrypi/firmware/wiki/Mailboxes
+ *
+ */
+
+#include "qemu-common.h"
+#include "hw/arm-misc.h"
+#include "hw/devices.h"
+#include "hw/boards.h"
+#include "hw/flash.h"
+#include "hw/sysbus.h"
+#include "blockdev.h"
+#include "exec-memory.h"
+#include "net.h"
+#include "sysemu.h"
+//~ #include "i2c.h"
+
+// TODO: put in header file
+extern const char *qemu_sprint_backtrace(char *buffer, size_t length);
+
+static char bt_buffer[256];
+
+#define logout(fmt, ...) \
+    fprintf(stderr, "RPI\t%-24s" fmt, __func__, ##__VA_ARGS__)
+
+#define BCM2708
+#include "hw/pl011.c"
+#include "hw/arm_timer.c"
+
+/* Code copied from Linux arch/arm/mach-bcm2708/include/mach/platform.h. */
+
+/* macros to get at IO space when running virtually */
+#define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
+
+#define BCM2708_SDRAM_BASE 0x00000000
+
+// TODO: 0x7e000000?
+#define BCM2708_PERI_BASE  0x20000000
+#define ST_BASE            (BCM2708_PERI_BASE + 0x3000)   /* System Timer */
+#define DMA_BASE           (BCM2708_PERI_BASE + 0x7000)   /* DMA controller */
+#define ARM_BASE           (BCM2708_PERI_BASE + 0xB000)   /* BCM2708 ARM control block */
+#define PM_BASE            (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
+#define GPIO_BASE          (BCM2708_PERI_BASE + 0x200000) /* GPIO */
+#define UART0_BASE         (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
+#define MMCI0_BASE         (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
+#define UART1_BASE         (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
+#define EMMC_BASE          (BCM2708_PERI_BASE + 0x300000) /* eMMC interface */
+#define SMI_BASE           (BCM2708_PERI_BASE + 0x600000) /* SMI */
+#define USB_BASE           (BCM2708_PERI_BASE + 0x980000) /* DTC_OTG USB controller */
+#define MCORE_BASE         (BCM2708_PERI_BASE + 0x0000)   /* Fake frame buffer device (actually the multicore sync block*/
+
+#define ARMCTRL_BASE             (ARM_BASE + 0x000)
+#define ARMCTRL_IC_BASE          (ARM_BASE + 0x200)           /* ARM interrupt controller */
+#define ARMCTRL_TIMER0_1_BASE    (ARM_BASE + 0x400)           /* Timer 0 and 1 */
+#define ARMCTRL_0_SBM_BASE       (ARM_BASE + 0x800)           /* User 0 (ARM)'s Semaphores Doorbells and Mailboxes */
+
+#define ARM_IRQ1_BASE                  0
+#define INTERRUPT_TIMER0               (ARM_IRQ1_BASE + 0)
+#define INTERRUPT_TIMER1               (ARM_IRQ1_BASE + 1)
+#define INTERRUPT_TIMER2               (ARM_IRQ1_BASE + 2)
+#define INTERRUPT_TIMER3               (ARM_IRQ1_BASE + 3)
+#define INTERRUPT_CODEC0               (ARM_IRQ1_BASE + 4)
+#define INTERRUPT_CODEC1               (ARM_IRQ1_BASE + 5)
+#define INTERRUPT_CODEC2               (ARM_IRQ1_BASE + 6)
+#define INTERRUPT_VC_JPEG              (ARM_IRQ1_BASE + 7)
+#define INTERRUPT_ISP                  (ARM_IRQ1_BASE + 8)
+#define INTERRUPT_VC_USB               (ARM_IRQ1_BASE + 9)
+#define INTERRUPT_VC_3D                (ARM_IRQ1_BASE + 10)
+#define INTERRUPT_TRANSPOSER           (ARM_IRQ1_BASE + 11)
+#define INTERRUPT_MULTICORESYNC0       (ARM_IRQ1_BASE + 12)
+#define INTERRUPT_MULTICORESYNC1       (ARM_IRQ1_BASE + 13)
+#define INTERRUPT_MULTICORESYNC2       (ARM_IRQ1_BASE + 14)
+#define INTERRUPT_MULTICORESYNC3       (ARM_IRQ1_BASE + 15)
+#define INTERRUPT_DMA0                 (ARM_IRQ1_BASE + 16)
+#define INTERRUPT_DMA1                 (ARM_IRQ1_BASE + 17)
+#define INTERRUPT_VC_DMA2              (ARM_IRQ1_BASE + 18)
+#define INTERRUPT_VC_DMA3              (ARM_IRQ1_BASE + 19)
+#define INTERRUPT_DMA4                 (ARM_IRQ1_BASE + 20)
+#define INTERRUPT_DMA5                 (ARM_IRQ1_BASE + 21)
+#define INTERRUPT_DMA6                 (ARM_IRQ1_BASE + 22)
+#define INTERRUPT_DMA7                 (ARM_IRQ1_BASE + 23)
+#define INTERRUPT_DMA8                 (ARM_IRQ1_BASE + 24)
+#define INTERRUPT_DMA9                 (ARM_IRQ1_BASE + 25)
+#define INTERRUPT_DMA10                (ARM_IRQ1_BASE + 26)
+#define INTERRUPT_DMA11                (ARM_IRQ1_BASE + 27)
+#define INTERRUPT_DMA12                (ARM_IRQ1_BASE + 28)
+#define INTERRUPT_AUX                  (ARM_IRQ1_BASE + 29)
+#define INTERRUPT_ARM                  (ARM_IRQ1_BASE + 30)
+#define INTERRUPT_VPUDMA               (ARM_IRQ1_BASE + 31)
+
+#define ARM_IRQ2_BASE                  32
+#define INTERRUPT_HOSTPORT             (ARM_IRQ2_BASE + 0)
+#define INTERRUPT_VIDEOSCALER          (ARM_IRQ2_BASE + 1)
+#define INTERRUPT_CCP2TX               (ARM_IRQ2_BASE + 2)
+#define INTERRUPT_SDC                  (ARM_IRQ2_BASE + 3)
+#define INTERRUPT_DSI0                 (ARM_IRQ2_BASE + 4)
+#define INTERRUPT_AVE                  (ARM_IRQ2_BASE + 5)
+#define INTERRUPT_CAM0                 (ARM_IRQ2_BASE + 6)
+#define INTERRUPT_CAM1                 (ARM_IRQ2_BASE + 7)
+#define INTERRUPT_HDMI0                (ARM_IRQ2_BASE + 8)
+#define INTERRUPT_HDMI1                (ARM_IRQ2_BASE + 9)
+#define INTERRUPT_PIXELVALVE1          (ARM_IRQ2_BASE + 10)
+#define INTERRUPT_I2CSPISLV            (ARM_IRQ2_BASE + 11)
+#define INTERRUPT_DSI1                 (ARM_IRQ2_BASE + 12)
+#define INTERRUPT_PWA0                 (ARM_IRQ2_BASE + 13)
+#define INTERRUPT_PWA1                 (ARM_IRQ2_BASE + 14)
+#define INTERRUPT_CPR                  (ARM_IRQ2_BASE + 15)
+#define INTERRUPT_SMI                  (ARM_IRQ2_BASE + 16)
+#define INTERRUPT_GPIO0                (ARM_IRQ2_BASE + 17)
+#define INTERRUPT_GPIO1                (ARM_IRQ2_BASE + 18)
+#define INTERRUPT_GPIO2                (ARM_IRQ2_BASE + 19)
+#define INTERRUPT_GPIO3                (ARM_IRQ2_BASE + 20)
+#define INTERRUPT_VC_I2C               (ARM_IRQ2_BASE + 21)
+#define INTERRUPT_VC_SPI               (ARM_IRQ2_BASE + 22)
+#define INTERRUPT_VC_I2SPCM            (ARM_IRQ2_BASE + 23)
+#define INTERRUPT_VC_SDIO              (ARM_IRQ2_BASE + 24)
+#define INTERRUPT_VC_UART              (ARM_IRQ2_BASE + 25)
+#define INTERRUPT_SLIMBUS              (ARM_IRQ2_BASE + 26)
+#define INTERRUPT_VEC                  (ARM_IRQ2_BASE + 27)
+#define INTERRUPT_CPG                  (ARM_IRQ2_BASE + 28)
+#define INTERRUPT_RNG                  (ARM_IRQ2_BASE + 29)
+#define INTERRUPT_VC_ARASANSDIO        (ARM_IRQ2_BASE + 30)
+#define INTERRUPT_AVSPMON              (ARM_IRQ2_BASE + 31)
+
+#define ARM_IRQ0_BASE                  64
+#define INTERRUPT_ARM_TIMER            (ARM_IRQ0_BASE + 0)
+#define INTERRUPT_ARM_MAILBOX          (ARM_IRQ0_BASE + 1)
+#define INTERRUPT_ARM_DOORBELL_0       (ARM_IRQ0_BASE + 2)
+#define INTERRUPT_ARM_DOORBELL_1       (ARM_IRQ0_BASE + 3)
+#define INTERRUPT_VPU0_HALTED          (ARM_IRQ0_BASE + 4)
+#define INTERRUPT_VPU1_HALTED          (ARM_IRQ0_BASE + 5)
+#define INTERRUPT_ILLEGAL_TYPE0        (ARM_IRQ0_BASE + 6)
+#define INTERRUPT_ILLEGAL_TYPE1        (ARM_IRQ0_BASE + 7)
+#define INTERRUPT_PENDING1             (ARM_IRQ0_BASE + 8)
+#define INTERRUPT_PENDING2             (ARM_IRQ0_BASE + 9)
+#define INTERRUPT_JPEG                 (ARM_IRQ0_BASE + 10)
+#define INTERRUPT_USB                  (ARM_IRQ0_BASE + 11)
+#define INTERRUPT_3D                   (ARM_IRQ0_BASE + 12)
+#define INTERRUPT_DMA2                 (ARM_IRQ0_BASE + 13)
+#define INTERRUPT_DMA3                 (ARM_IRQ0_BASE + 14)
+#define INTERRUPT_I2C                  (ARM_IRQ0_BASE + 15)
+#define INTERRUPT_SPI                  (ARM_IRQ0_BASE + 16)
+#define INTERRUPT_I2SPCM               (ARM_IRQ0_BASE + 17)
+#define INTERRUPT_SDIO                 (ARM_IRQ0_BASE + 18)
+#define INTERRUPT_UART                 (ARM_IRQ0_BASE + 19)
+#define INTERRUPT_ARASANSDIO           (ARM_IRQ0_BASE + 20)
+
+#define MAXIRQNUM                      (32 + 32 + 20)
+#define MAXFIQNUM                      (32 + 32 + 20)
+
+#define MAX_TIMER                       2
+#define MAX_PERIOD                      699050
+#define TICKS_PER_uSEC                  1
+
+/*
+ *  These are useconds NOT ticks.
+ *
+ */
+#define mSEC_1                          1000
+#define mSEC_5                          (mSEC_1 * 5)
+#define mSEC_10                         (mSEC_1 * 10)
+#define mSEC_25                         (mSEC_1 * 25)
+#define SEC_1                           (mSEC_1 * 1000)
+
+/*
+ * Watchdog
+ */
+#define PM_RSTC                        (PM_BASE+0x1c)
+#define PM_WDOG                        (PM_BASE+0x24)
+
+#define PM_WDOG_RESET                  0000000000
+#define PM_PASSWORD                    0x5a000000
+#define PM_WDOG_TIME_SET               0x000fffff
+#define PM_RSTC_WRCFG_CLR              0xffffffcf
+#define PM_RSTC_WRCFG_SET              0x00000030
+#define PM_RSTC_WRCFG_FULL_RESET       0x00000020
+#define PM_RSTC_RESET                  0x00000102
+
+/* Code copied from Linux arch/arm/mach-bcm2708/include/mach/arm_control.h. */
+
+/*  Mailbox flags. Valid for all owners */
+
+/* Mailbox status register (...0x98) */
+#define ARM_MS_FULL       0x80000000
+#define ARM_MS_EMPTY      0x40000000
+#define ARM_MS_LEVEL      0x400000FF /* Max. value depdnds on mailbox depth parameter */
+
+/* MAILBOX config/status register (...0x9C) */
+/* ANY write to this register clears the error bits! */
+#define ARM_MC_IHAVEDATAIRQEN    0x00000001 /* mailbox irq enable:  has data */
+#define ARM_MC_IHAVESPACEIRQEN   0x00000002 /* mailbox irq enable:  has space */
+#define ARM_MC_OPPISEMPTYIRQEN   0x00000004 /* mailbox irq enable: Opp. is empty */
+#define ARM_MC_MAIL_CLEAR        0x00000008 /* mailbox clear write 1, then  0 */
+#define ARM_MC_IHAVEDATAIRQPEND  0x00000010 /* mailbox irq pending:  has space */
+#define ARM_MC_IHAVESPACEIRQPEND 0x00000020 /* mailbox irq pending: Opp. is empty */
+#define ARM_MC_OPPISEMPTYIRQPEND 0x00000040 /* mailbox irq pending */
+/* Bit 7 is unused */
+#define ARM_MC_ERRNOOWN   0x00000100 /* error : none owner read from mailbox */
+#define ARM_MC_ERROVERFLW 0x00000200 /* error : write to fill mailbox */
+#define ARM_MC_ERRUNDRFLW 0x00000400 /* error : read from empty mailbox */
+
+/* Linux code ends here. */
+
+#define SZ_4K   4096
+
+typedef struct {
+    MemoryRegion iomem;
+    qemu_irq irq[MAXIRQNUM];
+    uint32_t irq_basic_pending;
+    uint32_t irq_pending_1;
+    uint32_t irq_pending_2;
+    uint32_t fiq_control;
+    uint32_t enable_irqs_1;
+    uint32_t enable_irqs_2;
+    uint32_t enable_basic_irqs;
+} BCM2708InterruptController;
+
+typedef struct {
+    MemoryRegion iomem;
+    QEMUTimer *timer;
+    qemu_irq irq;
+    uint64_t clock;     // initial value  of QEMU timer
+    int64_t expire;
+    uint32_t dt;
+    uint32_t cs;
+    uint32_t c[4];
+    bool active[4];
+} BCM2708SystemTimer;
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+    BCM2708InterruptController ic;      /* interrupt controller */
+    BCM2708SystemTimer st;              /* system timer */
+    pl011_state uart0;
+    //~ uint32_t level;
+    //~ uint32_t mask;
+    //~ int irq;
+} BCM2708State;
+
+typedef struct {
+    MemoryRegion ram;
+    MemoryRegion ram_alias;
+    BCM2708State *bcm2708;
+    qemu_irq *cpu_pic;
+} RaspberryPi;
+
+static RaspberryPi *rpi;
+
+static void bcm2708_update_irq(void)
+{
+    BCM2708InterruptController *ic = &rpi->bcm2708->ic;
+    bool pic_irq = (ic->irq_basic_pending & ic->enable_basic_irqs) ||
+                   (ic->irq_pending_1 & ic->enable_irqs_1) ||
+                   (ic->irq_pending_2 & ic->enable_irqs_2);
+    //~ logout("pic irq = %u\n", pic_irq);
+    qemu_set_irq(rpi->cpu_pic[ARM_PIC_CPU_IRQ], pic_irq);
+}
+
+static void bcm2708_set_irq(unsigned num, bool value)
+{
+    if (num == INTERRUPT_ARM_MAILBOX) {
+        logout("interrupt %u = %u\n", num, value);
+    }
+
+    switch (num) {
+    case INTERRUPT_TIMER0 ... INTERRUPT_VPUDMA:
+        if (value) {
+            rpi->bcm2708->ic.irq_pending_1 |=
+                (1 << (num - INTERRUPT_TIMER0));
+        } else {
+            rpi->bcm2708->ic.irq_pending_1 &=
+                ~(1 << (num - INTERRUPT_TIMER0));
+        }
+        if (rpi->bcm2708->ic.irq_pending_1) {
+            rpi->bcm2708->ic.irq_basic_pending |= (1 << 8);
+        } else {
+            rpi->bcm2708->ic.irq_basic_pending &= ~(1 << 8);
+        }
+        bcm2708_update_irq();
+        break;
+    case INTERRUPT_ARM_TIMER ... INTERRUPT_ARASANSDIO:
+        if (value) {
+            rpi->bcm2708->ic.irq_basic_pending |=
+                (1 << (num - INTERRUPT_ARM_TIMER));
+        } else {
+            rpi->bcm2708->ic.irq_basic_pending &=
+                ~(1 << (num - INTERRUPT_ARM_TIMER));
+        }
+        bcm2708_update_irq();
+        break;
+    default:
+        hw_error("unexpected interrupt %u\n", num);
+    }
+}
+
+static uint64_t bcm2708_timer_clock(BCM2708SystemTimer *st)
+{
+    return qemu_get_clock_us(vm_clock) - st->clock;
+}
+
+static void bcm2708_timer_update(BCM2708SystemTimer *st)
+{
+    uint64_t now = qemu_get_clock_us(vm_clock);
+    uint32_t clo = (uint32_t)(now - st->clock);
+    uint32_t dt_min = UINT32_MAX;
+    uint8_t i;
+    for (i = 0; i < 4; i++) {
+        uint32_t dt = st->c[i] - clo;
+        if (dt != 0 && dt < dt_min) {
+            dt_min = dt;
+        }
+    }
+    for (i = 0; i < 4; i++) {
+        uint32_t dt = st->c[i] - clo;
+        st->active[i] = (dt == dt_min);
+    }
+    st->dt = dt_min;
+    st->expire = now + dt_min;
+    //~ logout("wait %" PRIu32 " µs\n", dt_min);
+    qemu_mod_timer(st->timer, st->expire);
+}
+
+static void bcm2708_timer_irq(BCM2708SystemTimer *st)
+{
+    uint8_t i;
+    for (i = 0; i < 4; i++) {
+        if (st->cs & (1 << i)) {
+            bcm2708_set_irq(INTERRUPT_TIMER0 + i, true);
+        } else {
+            bcm2708_set_irq(INTERRUPT_TIMER0 + i, false);
+        }
+    }
+}
+
+static void bcm2708_timer_tick(void *opaque)
+{
+    BCM2708SystemTimer *st = opaque;
+    //~ uint64_t now = qemu_get_clock_us(vm_clock);
+    //~ uint32_t clo = (uint32_t)(now - st->clock);
+    uint8_t cs = st->cs;
+    uint8_t i;
+    //~ logout("%u µs expired\n", st->dt);
+    for (i = 0; i < 4; i++) {
+        if (st->active[i] && (cs ^ (1 << i))) {
+            st->cs |= (1 << i);
+            //~ logout("raise interrupt for C%u\n", i);
+            bcm2708_set_irq(INTERRUPT_TIMER0 + i, true);
+        } else {
+            //~ qemu_set_irq(s->parent_irq, false);
+        }
+    }
+    bcm2708_timer_update(st);
+}
+
+/* DMA. */
+
+static uint32_t bcm2708_dma_read(BCM2708State *s, unsigned offset)
+{
+    uint32_t value = 0;
+    switch (offset) {
+    default:
+        logout("offset=0x%02x, value=0x%08x (TODO)\n", offset, value);
+        return value;
+    }
+    logout("offset=0x%02x, value=0x%08x\n", offset, value);
+    return value;
+}
+
+static void bcm2708_dma_write(BCM2708State *s, unsigned offset, uint32_t value)
+{
+    //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x\n",
+    //~        offset, value);
+    switch (offset) {
+    default:
+        logout("offset=0x%02x, value=0x%08x (TODO)\n",
+               offset, value);
+    }
+}
+
+/* ARM Interrupt controller. */
+
+static uint64_t bcm2708_ic_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
+{
+    BCM2708InterruptController *ic = opaque;
+    uint32_t value = 0;
+    assert(size == 4);
+    switch (offset) {
+    case 0x00:  /* IRQ basic pending */
+        value = ic->irq_basic_pending;
+        //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x\n",
+               //~ offset, value);
+        break;
+    case 0x04: /* IRQ pending 1 */
+        value = ic->irq_pending_1;
+        //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x\n",
+               //~ offset, value);
+        break;
+    case 0x08: /* IRQ pending 2 */
+        value = ic->irq_pending_2;
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x\n",
+               offset, value);
+        break;
+    case 0x0c: /* FIQ control */
+    default:
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x0000 (TODO)\n",
+               offset);
+    }
+    return value;
+}
+
+static void bcm2708_ic_write(void *opaque, target_phys_addr_t offset, uint64_t value,
+                             unsigned size)
+{
+    BCM2708InterruptController *ic = opaque;
+
+    assert(size == 4);
+    switch (offset) {
+    case 0x00: /* IRQ basic pending */
+    case 0x04: /* IRQ pending 1 */
+    case 0x08: /* IRQ pending 2 */
+    case 0x0c: /* FIQ control */
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (TODO)\n", offset, value);
+        break;
+    case 0x10: /* Enable IRQs 1 */
+        ic->enable_irqs_1 |= value;
+        if (value != 8)
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (Enable IRQs 1)\n", offset, value);
+        break;
+    case 0x14: /* Enable IRQs 2 */
+        ic->enable_irqs_2 |= value;
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (Enable IRQs 2)\n", offset, value);
+        break;
+    case 0x18: /* Enable Basic IRQs */
+        ic->enable_basic_irqs |= value;
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (Enable Basic IRQs)\n", offset, value);
+        break;
+    case 0x1c: /* Disable IRQs 1 */
+        //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (disable)\n", offset, value);
+        ic->enable_irqs_1 &= ~value;
+        bcm2708_update_irq();
+        break;
+    case 0x20: /* Disable IRQs 2 */
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (Disable IRQs 2)\n", offset, value);
+        ic->enable_irqs_2 &= ~value;
+        bcm2708_update_irq();
+        break;
+    case 0x24: /* Disable Basic IRQs */
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (Disable Basic IRQs)\n", offset, value);
+        ic->enable_basic_irqs &= ~value;
+        bcm2708_update_irq();
+        break;
+    default:
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (TODO)\n", offset, value);
+    }
+}
+
+static uint64_t bcm2708_armctrl_read(void *opaque, target_phys_addr_t offset,
+                                     unsigned size)
+{
+    BCM2708State *s = opaque;
+    uint32_t value = 0;
+
+    assert(size == 4);
+
+    if (offset < 0x200) {
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x0000 (TODO)\n",
+               offset);
+    } else {
+        value = bcm2708_ic_read(&s->ic, offset - 0x0200, size);
+    }
+
+    return value;
+}
+
+static void bcm2708_armctrl_write(void *opaque, target_phys_addr_t offset,
+                                  uint64_t value, unsigned size)
+{
+    BCM2708State *s = opaque;
+
+    assert(size == 4);
+
+    if (offset < 0x0200) {
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (TODO)\n", offset, value);
+    } else {
+        bcm2708_ic_write(&s->ic, offset - 0x0200, value, size);
+    }
+}
+
+/* System timer. */
+
+static uint64_t bcm2708_st_read(void *opaque, target_phys_addr_t offset,
+                                unsigned size)
+{
+    BCM2708SystemTimer *st = opaque;
+    uint32_t value = 0;
+    assert(size == 4);
+    switch (offset) {
+    case 0x04: /* CLO */
+        value = (uint32_t)bcm2708_timer_clock(st);
+        break;
+    case 0x08: /* CHI */
+        value = (uint32_t)(bcm2708_timer_clock(st) >> 32);
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x\n", offset, value);
+        break;
+    case 0x0c ... 0x18: /* C0, C1, C2, C3 */
+        value = st->c[(offset - 0x0c) / 4];
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x\n", offset, value);
+        break;
+    default:
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08x (TODO)\n",
+               offset, value);
+        return value;
+    }
+    return value;
+}
+
+static void bcm2708_st_write(void *opaque, target_phys_addr_t offset,
+                             uint64_t value, unsigned size)
+{
+    BCM2708SystemTimer *st = opaque;
+    unsigned timer_index;
+
+    assert(size == 4);
+
+    switch (offset) {
+    case 0x00: /* CS */
+        //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (CS)\n",
+               //~ offset, value);
+        st->cs &= ~value;
+        bcm2708_timer_irq(st);
+        break;
+    case 0x04: /* CLO */
+    case 0x08: /* CHI */
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (ignored)\n",
+               offset, value);
+        break;
+    case 0x0c ... 0x18: /* C0, C1, C2, C3 */
+        timer_index = (offset - 0x0c) / 4;
+        st->c[timer_index] = value;
+        //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (C%u)\n",
+               //~ offset, value, timer_index);
+        bcm2708_timer_update(st);
+        break;
+    default:
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (TODO)\n", offset, value);
+    }
+}
+
+/* UART 0. */
+
+static uint32_t bcm2708_uart0_read(BCM2708State *s, unsigned offset)
+{
+    uint32_t value = 0;
+    switch (offset) {
+    default:
+        logout("offset=0x%02x, value=0x%08x (TODO) %s\n", offset, value,
+               qemu_sprint_backtrace(bt_buffer, sizeof(bt_buffer)));
+        return value;
+    }
+    //~ logout("offset=0x%02x, value=0x%08x\n", offset, value);
+    return value;
+}
+
+static bool mailbox_empty;
+static unsigned mailbox_value;
+//~ static uint8_t mailbox[] = { 1 };
+//~ static uint8_t mailbox_index;
+#define MAILBOX_SIZE (sizeof(mailbox) / sizeof(mailbox[0]))
+
+static uint32_t bcm2708_0_sbm_read(BCM2708State *s, unsigned offset)
+{
+    uint32_t value = 0;
+    switch (offset) {
+    case 0x80:          // ARM_0_MAIL0_RD
+        if (!mailbox_empty) {
+            value = mailbox_value;
+            bcm2708_set_irq(INTERRUPT_ARM_MAILBOX, false);
+            mailbox_empty = true;
+        }
+        logout("offset=0x%02x, value=0x%08x (ARM_0_MAIL0_RD)\n", offset, value);
+        break;
+    case 0x98:          // ARM_0_MAIL0_STA Status read
+        if (mailbox_empty) {
+            value |= ARM_MS_EMPTY;
+        }
+        // TODO: Missing emulation of ARM_MS_FULL for mailbox writes.
+        logout("offset=0x%02x, value=0x%08x (ARM_0_MAIL0_STA)\n", offset, value);
+        break;
+    case 0x9c:          // ARM_0_MAIL0_CNF Config
+    case 0xa0:          // ARM_0_MAIL1_WRT
+    default:
+        logout("offset=0x%02x, value=0x%08x (TODO) %s\n", offset, value,
+               qemu_sprint_backtrace(bt_buffer, sizeof(bt_buffer)));
+        return value;
+    }
+    //~ logout("offset=0x%02x, value=0x%08x\n", offset, value);
+    return value;
+}
+
+//~ Mailbox Peek  Read  Write  Status  Sender  Config
+//~    0    0x10  0x00  0x20   0x18    0x14    0x1C
+//~    1    0x20
+
+static void bcm2708_0_sbm_write(BCM2708State *s, unsigned offset,
+                                uint32_t value)
+{
+    switch (offset) {
+    case 0x9c:          // Config
+        if (value == ARM_MC_IHAVEDATAIRQEN) {
+            logout("offset=0x%02x, value=0x%08x (ARM_0_MAIL0_CNF)\n", offset, value);
+            //~ bcm2708_set_irq(INTERRUPT_ARM_MAILBOX, true);
+        } else {
+            logout("offset=0x%02x, value=0x%08x (ARM_0_MAIL0_CNF, TODO)\n", offset, value);
+        }
+        /* TODO: Clear error bits. */
+        break;
+    case 0xa0:          // ARM_0_MAIL1_WRT
+        logout("offset=0x%02x, value=0x%08x (ARM_0_MAIL1_WRT)\n", offset, value);
+        mailbox_empty = false;
+        bcm2708_set_irq(INTERRUPT_ARM_MAILBOX, true);
+        break;
+    default:
+        logout("offset=0x%02x, value=0x%08x (TODO)\n", offset, value);
+    }
+}
+
+#define IO(offset) (offset + BCM2708_PERI_BASE)
+
+static uint64_t bcm2708_read(void *opaque, target_phys_addr_t offset,
+                             unsigned size)
+{
+    BCM2708State *s = opaque;
+    uint32_t value = 0;
+
+    assert(size == 4);
+
+    switch (IO(offset)) {
+    case DMA_BASE ... DMA_BASE + SZ_4K - 1:
+        value = bcm2708_dma_read(s, IO(offset) - DMA_BASE);
+        break;
+    case UART0_BASE ... UART0_BASE + 0xffc:
+        value = bcm2708_uart0_read(s, IO(offset) - UART0_BASE);
+        break;
+    case ARMCTRL_0_SBM_BASE ... ARMCTRL_0_SBM_BASE + 0xa0:
+        value = bcm2708_0_sbm_read(s, IO(offset) - ARMCTRL_0_SBM_BASE);
+        break;
+    default:
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x0000 (TODO)\n", offset);
+    }
+    return value;
+}
+
+static void bcm2708_write(void *opaque, target_phys_addr_t offset,
+                          uint64_t value, unsigned size)
+{
+    BCM2708State *s = opaque;
+
+    assert(size == 4);
+
+    switch (IO(offset)) {
+    case DMA_BASE ... DMA_BASE + SZ_4K - 1:
+        bcm2708_dma_write(s, IO(offset) - DMA_BASE, value);
+        break;
+    case ARMCTRL_0_SBM_BASE ... ARMCTRL_0_SBM_BASE + 0xa0:
+        bcm2708_0_sbm_write(s, IO(offset) - ARMCTRL_0_SBM_BASE, value);
+        break;
+    default:
+        logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (TODO)\n", offset, value);
+    }
+    //~ bcm2708_update(s);
+}
+
+static const MemoryRegionOps bcm2708_armctrl_ops = {
+    .read = bcm2708_armctrl_read,
+    .write = bcm2708_armctrl_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps bcm2708_st_ops = {
+    .read = bcm2708_st_read,
+    .write = bcm2708_st_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps bcm2708_ops = {
+    .read = bcm2708_read,
+    .write = bcm2708_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/* -------------------------------------------------------------------------- */
+
+//~ static BCM2708State *bcm2708;
+
+static int bcm2708_pl011_arm_init(SysBusDevice *dev, pl011_state *s)
+{
+    //~ sysbus_init_irq(dev, &s->irq);
+    s->id = pl011_id_arm;
+    s->chr = qemu_char_get_next_serial();
+
+    s->read_trigger = 1;
+    s->ifl = 0x12;
+    s->cr = 0x300;
+    s->flags = 0x90;
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive,
+                              pl011_event, s);
+    }
+    vmstate_register(&dev->qdev, -1, &vmstate_pl011, s);
+    return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int bcm2708_init(SysBusDevice *dev)
+{
+    BCM2708State *s = FROM_SYSBUS(BCM2708State, dev);
+    int i;
+
+    logout("\n");
+
+    rpi->bcm2708 = s;
+
+    //~ qdev_init_gpio_in(&dev->qdev, bcm2708_set_irq, 32);
+    for (i = 0; i < 2; i++) {   // TODO
+        sysbus_init_irq(dev, &s->ic.irq[i]);
+    }
+    //~ s->irq = 31;
+
+    /* BCM2708. */
+    memory_region_init_io(&s->iomem, &bcm2708_ops, s, "bcm2708",
+                          USB_BASE + 0x1000 - BCM2708_PERI_BASE);
+    sysbus_init_mmio(dev, &s->iomem);
+
+    /* Interrupt controller. */
+    memory_region_init_io(&s->ic.iomem, &bcm2708_armctrl_ops, s, "bcm2708.ic",
+                          0x0400);
+    memory_region_add_subregion(&s->iomem,
+                                ARMCTRL_BASE - BCM2708_PERI_BASE,
+                                &s->ic.iomem);
+
+    /* System timer. */
+    memory_region_init_io(&s->st.iomem, &bcm2708_st_ops, &s->st, "bcm2708.st",
+                          0x1000);
+    memory_region_add_subregion(&s->iomem,
+                                ST_BASE - BCM2708_PERI_BASE,
+                                &s->st.iomem);
+    s->st.timer = qemu_new_timer_us(vm_clock, bcm2708_timer_tick, &s->st);
+    s->st.clock = s->st.expire = qemu_get_clock_us(vm_clock);
+    sysbus_init_irq(dev, &s->st.irq);
+    bcm2708_timer_update(&s->st);
+
+    /* UART0. */
+    //~ sysbus_create_simple("bcm2708.pl011", UART0_BASE, s->parent[12]);
+    memory_region_init_io(&s->uart0.iomem, &pl011_ops, &s->uart0, "bcm2708.uart0",
+                          0x1000);
+    memory_region_add_subregion(&s->iomem,
+                                UART0_BASE - BCM2708_PERI_BASE,
+                                &s->uart0.iomem);
+    bcm2708_pl011_arm_init(dev, &s->uart0);
+
+    /* Timer 0 and 1. */
+    DeviceState *devState = qdev_create(NULL, "bcm2708.sp804");
+    //~ qdev_prop_set_uint32(dev, "freq0", 150000000);
+    //~ qdev_prop_set_uint32(dev, "freq1", 150000000);
+    qdev_init_nofail(devState);
+    SysBusDevice *busdev = sysbus_from_qdev(devState);
+    busdev->mmio[0].addr = ARMCTRL_TIMER0_1_BASE;       // TODO: check
+    memory_region_add_subregion(&s->iomem,
+                                ARMCTRL_TIMER0_1_BASE - BCM2708_PERI_BASE,
+                                busdev->mmio[0].memory);
+    sysbus_init_irq(busdev, &s->ic.irq[0]);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_bcm2708 = {
+    .name = "bcm2708",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        //~ VMSTATE_UINT32(level, BCM2708State),
+        //~ VMSTATE_UINT32(mask, BCM2708State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2708_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    logout("\n");
+    k->init = bcm2708_init;
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_bcm2708;
+    //~ dc->props = bcm2708_properties;
+    //~ dc->reset = bcm2708_reset;
+}
+
+static TypeInfo bcm2708_info = {
+    .name          = "bcm2708",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2708State),
+    .class_init    = bcm2708_class_init,
+};
+
+static void raspi_register_types(void)
+{
+    logout("\n");
+    type_register_static(&bcm2708_info);
+}
+
+type_init(raspi_register_types)
+
+
+
+/* Board init. */
+
+static struct arm_boot_info raspi_binfo;
+
+static void raspi_init(ram_addr_t ram_size,
+                     const char *boot_device,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    ARMCPU *cpu;
+    MemoryRegion *sysmem = get_system_memory();
+
+    logout("\n");
+
+    rpi = g_new(RaspberryPi, 1);
+
+    if (!cpu_model) {
+        cpu_model = "arm1176";
+    }
+    cpu = cpu_arm_init(cpu_model);
+    if (!cpu) {
+        logout("Unable to find CPU definition\n");
+        exit(1);
+    }
+
+    /* Ignore the RAM size argument and use always the standard size. */
+    ram_size = 256 * MiB;
+
+    memory_region_init_ram(&rpi->ram, "raspi.ram", ram_size);
+    vmstate_register_ram_global(&rpi->ram);
+    /* ??? RAM should repeat to fill physical memory space.  */
+    memory_region_add_subregion(sysmem, BCM2708_SDRAM_BASE, &rpi->ram);
+
+    memory_region_init_alias(&rpi->ram_alias, "ram.alias",
+                             &rpi->ram, 0, ram_size);
+    memory_region_add_subregion(sysmem, 0xc0000000, &rpi->ram_alias);
+
+    rpi->cpu_pic = arm_pic_init_cpu(cpu);
+
+    //~ DeviceState *sysctl =
+    sysbus_create_varargs("bcm2708", BCM2708_PERI_BASE,
+                          rpi->cpu_pic[ARM_PIC_CPU_IRQ],
+                          rpi->cpu_pic[ARM_PIC_CPU_FIQ],
+                          NULL);
+
+    //~ sysbus_connect_irq(sysbus_from_qdev(sysctl), 0, rpi->cpu_pic[ARM_PIC_CPU_IRQ]);
+
+    //~ sysctl = qdev_create(NULL, "realview_sysctl");
+    //~ qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
+    //~ qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
+    //~ qdev_init_nofail(sysctl);
+    //~ sysbus_mmio_map(sysbus_from_qdev(sysctl), 0, 0x10000000);
+
+    raspi_binfo.ram_size = ram_size;
+    raspi_binfo.kernel_filename = kernel_filename;
+    raspi_binfo.kernel_cmdline = kernel_cmdline;
+    raspi_binfo.initrd_filename = initrd_filename;
+    raspi_binfo.board_id = 0x183;
+    arm_load_kernel(cpu, &raspi_binfo);
+}
+
+static QEMUMachine raspi_machine = {
+    .name = "raspi",
+    .desc = "ARM Raspberry PI (ARM1176)",
+    .init = raspi_init,
+    .use_scsi = 1,
+    .no_parallel = true,
+    //~ .use_virtcon:1,
+    .no_floppy = true,
+    .no_cdrom = true,
+    //~ no_sdcard:1;
+    //~ .default_machine_opts = "ram=256"
+};
+
+static void raspi_machine_init(void)
+{
+    logout("\n");
+    qemu_register_machine(&raspi_machine);
+}
+
+machine_init(raspi_machine_init);
+
+#if 0
+
+pi@raspberrypi ~ $ cat /proc/interrupts
+           CPU0
+  3:     210938   ARMCTRL  BCM2708 Timer Tick
+ 52:          0   ARMCTRL  BCM2708 GPIO catchall handler
+ 65:          5   ARMCTRL  ARM Mailbox IRQ
+ 66:          1   ARMCTRL  VCHIQ doorbell
+ 75:   15792842   ARMCTRL  dwc_otg, dwc_otg_hcd:usb1
+ 77:       8921   ARMCTRL  bcm2708_sdhci (dma)
+ 83:         20   ARMCTRL  uart-pl011
+ 84:      11172   ARMCTRL  mmc0
+Err:          0
+
+pi@raspberrypi ~ $ cat /proc/iomem
+00000000-0bffffff : System RAM
+  00008000-003adfff : Kernel text
+  003cc000-0043c397 : Kernel data
+20000000-20000fff : bcm2708_vcio
+20003000-20003fff : bcm2708_systemtimer
+20007000-20007fff : bcm2708_dma.0
+  20007000-20007fff : bcm2708_dma
+20100000-201000ff : bcm2708_powerman.0
+20200000-20200fff : bcm2708_gpio
+20201000-20201fff : dev:f1
+  20201000-20201fff : uart-pl011
+20204000-202040ff : bcm2708_spi.0
+20205000-202050ff : bcm2708_i2c.0
+20300000-203000ff : bcm2708_sdhci.0
+  20300000-203000ff : mmc0
+20804000-208040ff : bcm2708_i2c.1
+20980000-2099ffff : bcm2708_usb
+  20980000-2099ffff : dwc_otg
+
+TODO:
+
+arch_hw_breakpoint_init - keine Debug-Architektur
+
+
+mailbox0 from GPU to ARM
+mailbox1 from ARM to GPU
+
+
+#endif
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index e3ecce2..3be238a 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -24,6 +24,11 @@
 #define TIMER_CTRL_PERIODIC     (1 << 6)
 #define TIMER_CTRL_ENABLE       (1 << 7)
 
+#if !defined(BCM2708)
+#define logout(fmt, ...) \
+    do { } while (0)
+#endif
+
 typedef struct {
     ptimer_state *timer;
     uint32_t control;
@@ -207,6 +212,8 @@ static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
 {
     sp804_state *s = (sp804_state *)opaque;
 
+    logout("offset=0x%02" TARGET_PRIxPHYS " (timer)\n", offset);
+
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
     }
@@ -235,6 +242,9 @@ static void sp804_write(void *opaque, target_phys_addr_t offset,
 {
     sp804_state *s = (sp804_state *)opaque;
 
+    logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%08" PRIx64 " (timer)\n",
+           offset, value);
+
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
         return;
@@ -277,12 +287,18 @@ static int sp804_init(SysBusDevice *dev)
     s->timer[1] = arm_timer_init(s->freq1);
     s->timer[0]->irq = qi[0];
     s->timer[1]->irq = qi[1];
+#if defined(BCM2708)
+    memory_region_init_io(&s->iomem, &sp804_ops, s, "bcm2708.sp804", 0x0400);
+#else
     memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
+#endif
     sysbus_init_mmio(dev, &s->iomem);
     vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
     return 0;
 }
 
+#if !defined(BCM2708)
+
 /* Integrator/CP timer module.  */
 
 typedef struct {
@@ -361,6 +377,8 @@ static TypeInfo icp_pit_info = {
     .class_init    = icp_pit_class_init,
 };
 
+#endif
+
 static Property sp804_properties[] = {
     DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
     DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
@@ -377,7 +395,11 @@ static void sp804_class_init(ObjectClass *klass, void *data)
 }
 
 static TypeInfo sp804_info = {
+#if defined(BCM2708)
+    .name          = "bcm2708.sp804",
+#else
     .name          = "sp804",
+#endif
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(sp804_state),
     .class_init    = sp804_class_init,
@@ -385,7 +407,9 @@ static TypeInfo sp804_info = {
 
 static void arm_timer_register_types(void)
 {
+#if !defined(BCM2708)
     type_register_static(&icp_pit_info);
+#endif
     type_register_static(&sp804_info);
 }
 
diff --git a/hw/boards.h b/hw/boards.h
index 59c01d0..8ef8a78 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -19,13 +19,13 @@ typedef struct QEMUMachine {
     QEMUMachineInitFunc *init;
     int use_scsi;
     int max_cpus;
-    unsigned int no_serial:1,
-        no_parallel:1,
-        use_virtcon:1,
-        no_floppy:1,
-        no_cdrom:1,
-        no_sdcard:1;
-    int is_default;
+    bool no_serial:1;
+    bool no_parallel:1;
+    bool use_virtcon:1;
+    bool no_floppy:1;
+    bool no_cdrom:1;
+    bool no_sdcard:1;
+    bool is_default:1;
     const char *default_machine_opts;
     GlobalProperty *compat_props;
     struct QEMUMachine *next;
diff --git a/hw/pl011.c b/hw/pl011.c
index 3245702..4ea2913 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -41,8 +41,18 @@ typedef struct {
 #define PL011_FLAG_TXFF 0x20
 #define PL011_FLAG_RXFE 0x10
 
+#if !defined(BCM2708)
+#define logout(fmt, ...) \
+    do { } while (0)
+#endif
+
+#if defined(BCM2708)
+static const unsigned char pl011_id_arm[8] =
+  { 0x11, 0x10, 0x24, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+#else
 static const unsigned char pl011_id_arm[8] =
   { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+#endif
 static const unsigned char pl011_id_luminary[8] =
   { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
 
@@ -61,8 +71,16 @@ static uint64_t pl011_read(void *opaque, target_phys_addr_t offset,
     uint32_t c;
 
     if (offset >= 0xfe0 && offset < 0x1000) {
+        logout("offset=0x%02" TARGET_PRIxPHYS ". value=0x%08x (UART0) %s\n",
+               offset, s->id[(offset - 0xfe0) >> 2],
+               qemu_sprint_backtrace(bt_buffer, sizeof(bt_buffer)));
+
         return s->id[(offset - 0xfe0) >> 2];
     }
+
+    //~ logout("offset=0x%02" TARGET_PRIxPHYS " (UART0) %s\n", offset,
+           //~ qemu_sprint_backtrace(bt_buffer, sizeof(bt_buffer)));
+
     switch (offset >> 2) {
     case 0: /* UARTDR */
         s->flags &= ~PL011_FLAG_RXFF;
@@ -78,9 +96,7 @@ static uint64_t pl011_read(void *opaque, target_phys_addr_t offset,
         if (s->read_count == s->read_trigger - 1)
             s->int_level &= ~ PL011_INT_RX;
         pl011_update(s);
-        if (s->chr) {
-            qemu_chr_accept_input(s->chr);
-        }
+        qemu_chr_accept_input(s->chr);
         return c;
     case 1: /* UARTCR */
         return 0;
@@ -132,6 +148,9 @@ static void pl011_write(void *opaque, target_phys_addr_t offset,
     pl011_state *s = (pl011_state *)opaque;
     unsigned char ch;
 
+    //~ logout("offset=0x%02" TARGET_PRIxPHYS ", value=0x%04" PRIx64 " (UART0) %s\n",
+           //~ offset, value, qemu_sprint_backtrace(bt_buffer, sizeof(bt_buffer)));
+
     switch (offset >> 2) {
     case 0: /* UARTDR */
         /* ??? Check if transmitter is enabled.  */
@@ -190,6 +209,8 @@ static int pl011_can_receive(void *opaque)
 {
     pl011_state *s = (pl011_state *)opaque;
 
+    logout("\n");
+
     if (s->lcr & 0x10)
         return s->read_count < 16;
     else
@@ -218,11 +239,13 @@ static void pl011_put_fifo(void *opaque, uint32_t value)
 
 static void pl011_receive(void *opaque, const uint8_t *buf, int size)
 {
+    logout("\n");
     pl011_put_fifo(opaque, *buf);
 }
 
 static void pl011_event(void *opaque, int event)
 {
+    logout("\n");
     if (event == CHR_EVENT_BREAK)
         pl011_put_fifo(opaque, 0x400);
 }
@@ -258,6 +281,10 @@ static const VMStateDescription vmstate_pl011 = {
     }
 };
 
+#if defined(BCM2708)
+
+#else /* BCM2708 */
+
 static int pl011_init(SysBusDevice *dev, const unsigned char *id)
 {
     pl011_state *s = FROM_SYSBUS(pl011_state, dev);
@@ -325,3 +352,5 @@ static void pl011_register_types(void)
 }
 
 type_init(pl011_register_types)
+
+#endif /* BCM2708 */
diff --git a/qemu-timer.h b/qemu-timer.h
index f8af595..379963c 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -73,12 +73,23 @@ static inline QEMUTimer *qemu_new_timer_ns(QEMUClock *clock, QEMUTimerCB *cb,
     return qemu_new_timer(clock, SCALE_NS, cb, opaque);
 }
 
+static inline QEMUTimer *qemu_new_timer_us(QEMUClock *clock, QEMUTimerCB *cb,
+                                           void *opaque)
+{
+    return qemu_new_timer(clock, SCALE_US, cb, opaque);
+}
+
 static inline QEMUTimer *qemu_new_timer_ms(QEMUClock *clock, QEMUTimerCB *cb,
                                            void *opaque)
 {
     return qemu_new_timer(clock, SCALE_MS, cb, opaque);
 }
 
+static inline int64_t qemu_get_clock_us(QEMUClock *clock)
+{
+    return qemu_get_clock_ns(clock) / SCALE_US;
+}
+
 static inline int64_t qemu_get_clock_ms(QEMUClock *clock)
 {
     return qemu_get_clock_ns(clock) / SCALE_MS;
