Index: Makefile.target
===================================================================
--- Makefile.target	(revision 6883)
+++ Makefile.target	(working copy)
@@ -656,13 +656,17 @@
 ifeq ($(TARGET_BASE_ARCH), arm)
 OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
 OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-OBJS+= versatile_pci.o ptimer.o
+OBJS+= versatile_pci.o ptimer.o dm9000.o
 OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o
 OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
 OBJS+= pl061.o
 OBJS+= arm-semi.o
 OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
+OBJS+= s3c2410x.o s3c24xx_clkcon.o s3c24xx_gpio.o s3c24xx_iic.o
+OBJS+= s3c24xx_irq.o s3c24xx_lcd.o s3c24xx_memc.o s3c24xx_nand.o
+OBJS+= s3c24xx_rtc.o s3c24xx_serial.o s3c24xx_timers.o
+OBJS+= simtecbast.o
 OBJS+= pflash_cfi01.o gumstix.o
 OBJS+= zaurus.o ide.o serial.o nand.o ecc.o spitz.o tosa.o tc6393xb.o
 OBJS+= omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
Index: vl.c
===================================================================
--- vl.c	(revision 6883)
+++ vl.c	(working copy)
@@ -195,6 +195,7 @@
    to store the VM snapshots */
 DriveInfo drives_table[MAX_DRIVES+1];
 int nb_drives;
+static int nb_eeproms = 0;
 static int vga_ram_size;
 enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 static DisplayState *display_state;
@@ -2146,6 +2147,7 @@
 #define PFLASH_ALIAS "if=pflash"
 #define MTD_ALIAS "if=mtd"
 #define SD_ALIAS "index=0,if=sd"
+#define EEPROM_ALIAS "index=%d,if=eeprom"
 
 static int drive_opt_get_free_idx(void)
 {
@@ -2362,6 +2364,9 @@
         } else if (!strcmp(buf, "virtio")) {
             type = IF_VIRTIO;
             max_devs = 0;
+        } else if (!strcmp(buf, "eeprom")) {
+            type = IF_EEPROM;
+            max_devs = 0;
         } else {
             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
             return -1;
@@ -2597,6 +2602,7 @@
     case IF_PFLASH:
     case IF_MTD:
     case IF_VIRTIO:
+    case IF_EEPROM:
         break;
     }
     if (!file[0])
@@ -4172,6 +4178,7 @@
     QEMU_OPTION_usbdevice,
     QEMU_OPTION_name,
     QEMU_OPTION_uuid,
+    QEMU_OPTION_eeprom,
 
     /* Display options: */
     QEMU_OPTION_nographic,
@@ -4283,6 +4290,7 @@
     { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
     { "name", HAS_ARG, QEMU_OPTION_name },
     { "uuid", HAS_ARG, QEMU_OPTION_uuid },
+    { "eeprom", HAS_ARG, QEMU_OPTION_eeprom },
 
     /* Display options: */
     { "nographic", 0, QEMU_OPTION_nographic },
@@ -5308,6 +5316,9 @@
             case QEMU_OPTION_runas:
                 run_as = optarg;
                 break;
+            case QEMU_OPTION_eeprom:
+                drive_add(optarg, EEPROM_ALIAS, nb_eeproms++);
+                break;
             }
         }
     }
Index: Makefile
===================================================================
--- Makefile	(revision 6883)
+++ Makefile	(working copy)
@@ -75,6 +75,7 @@
 
 OBJS+=irq.o
 OBJS+=i2c.o smbus.o smbus_eeprom.o max7310.o max111x.o wm8750.o
+OBJS+=ch7xxx.o stcpmu.o
 OBJS+=ssd0303.o ssd0323.o ads7846.o stellaris_input.o twl92230.o
 OBJS+=tmp105.o lm832x.o
 OBJS+=scsi-disk.o cdrom.o
Index: sysemu.h
===================================================================
--- sysemu.h	(revision 6883)
+++ sysemu.h	(working copy)
@@ -127,7 +127,7 @@
 #endif
 
 typedef enum {
-    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO
+    IF_IDE, IF_SCSI, IF_FLOPPY, IF_PFLASH, IF_MTD, IF_SD, IF_VIRTIO, IF_EEPROM
 } BlockInterfaceType;
 
 typedef enum {
Index: hw/s3c2410x.c
===================================================================
--- hw/s3c2410x.c	(revision 0)
+++ hw/s3c2410x.c	(revision 0)
@@ -0,0 +1,77 @@
+/* hw/s3c2410x.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+
+/* We use the PXA style OHCI mapping */
+#include "pxa.h"
+
+/* Initialise a Samsung S3C2410X and all its internal peripherals.
+ *
+ * This emulation was originally intended to be sufficient to get a
+ * Simtec Electronics BAST (EB2410ITX) system emulation up and going
+ * well enough that the Simtec Advanced BootLoader Environment (ABLE)
+ * would startup and in its turn, be able to start a Linux system.
+ *
+ * The emulation is thus faithful to functionality only where it was
+ * necessary for getting things going. In particular it is not a fully
+ * faithful IRQ emulator, it does not implement the memory controller
+ * fully since there's no real simulated SDRAM is it were.
+ *
+ * The emulation is thus quite fast, where a more faithful emulation
+ * may be slower.
+ *
+ * Over time, the following peripherals are planned for implementing:
+ *  NAND controller
+ *  USB device port.
+ */
+S3CState *
+s3c2410x_init(int ram_size)
+{
+    S3CState *s = (S3CState *)qemu_mallocz(sizeof(S3CState));
+    /* Prepare the ARM 920T */
+    s->cpu_env = cpu_init("arm920t");
+    /* S3C2410X memory is always at the same physical location */
+    S3C24XX_DBF("RAM\n");
+    cpu_register_physical_memory(CPU_S3C2410X_RAM, ram_size, IO_MEM_RAM);
+    /* We get a memc */
+    S3C24XX_DBF("memc\n");
+    s3c24xx_memc_init(s);
+    /* And some interrupts (coo) */
+    S3C24XX_DBF("interrupts\n");
+    s->irqs = s3c24xx_irq_init(s);
+    /* The clock control allows for idling the CPU */
+    s3c24xx_clkcon_init(s);
+    /* And some GPIO */
+    S3C24XX_DBF("gpio\n");
+    s3c24xx_gpio_init(s); 
+    /* RTC for time */
+    s3c24xx_rtc_init(s);
+    /* And some IIC */
+    s3c24xx_iic_init(s);
+    /* And some timers */
+    s3c24xx_timers_init(s);
+    /* Serial ports */
+    S3C24XX_DBF("serial\n");
+    s3c24xx_serial_init(s, 0);
+    s3c24xx_serial_init(s, 1);
+    s3c24xx_serial_init(s, 2);
+    /* S3C2410X SRAM */
+    cpu_register_physical_memory(CPU_S3C2410X_SRAM, 4096, ram_size | IO_MEM_RAM);
+    /* A two port OHCI controller on IRQ 26 */
+    usb_ohci_init_pxa(CPU_S3C2410X_OHCI, 2, -1, s->irqs[26]);
+    /* LCD controller */
+    s3c24xx_lcd_init(s);
+    /* A nand controller */
+    s->nand_chip = NULL;
+    s3c24xx_nand_init(s);
+    return s;
+}
+
Index: hw/s3c2410x.h
===================================================================
--- hw/s3c2410x.h	(revision 0)
+++ hw/s3c2410x.h	(revision 0)
@@ -0,0 +1,352 @@
+/* hw/s3c2410x.h
+ *
+ * Samsung s3c2410x cpu register definitions
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#ifndef S3C2410X_H
+#define S3C2410X_H 1
+
+#include "qemu-common.h"
+#include "sysemu.h"
+
+#include "console.h"
+#include "hw/irq.h"
+
+#include "s3c24xx.h"
+
+/* S3C2410X SoC IDs */
+
+#define CPU_S3C2410X_IDENT_S3C2410X 0x32410000
+#define CPU_S3C2410X_IDENT_S3C2410A 0x32410002
+
+/* all defines are prefixed with CPU_S3C2410X_ */
+
+#define CPU_S3C2410X_REG(x) (0x48000000 + (x))
+
+#define CPU_S3C2410X_CS0 (0x00000000)
+#define CPU_S3C2410X_CS1 (0x08000000)
+#define CPU_S3C2410X_CS2 (0x10000000)
+#define CPU_S3C2410X_CS3 (0x18000000)
+#define CPU_S3C2410X_CS4 (0x20000000)
+#define CPU_S3C2410X_CS5 (0x28000000)
+#define CPU_S3C2410X_RAM (0x30000000)
+#define CPU_S3C2410X_SRAM (0x40000000)
+#define CPU_S3C2410X_OHCI (0x49000000)
+
+/* Clock control */
+#define CPU_S3C2410X_CLKCON 0x4C000000
+/* Lock time RW */
+#define CPU_S3C2410X_REG_LOCKTIME 0
+/* MPLL Control RW */
+#define CPU_S3C2410X_REG_MPLLCON 1
+/* UPLL Control RW */
+#define CPU_S3C2410X_REG_UPLLCON 2
+/* Clock Generator Control RW */
+#define CPU_S3C2410X_REG_CLKCON 3
+/* Slow Clock Control RW */
+#define CPU_S3C2410X_REG_CLKSLOW 4
+/* Clock divider control RW */
+#define CPU_S3C2410X_REG_CLKDIVN 5
+/* CLKCON IDLE */
+#define CPU_S3C2410X_REG_CLKCON_IDLE (1<<2)
+
+/* bus width, and wait state control */
+#define CPU_S3C2410X_BWSCON         CPU_S3C2410X_REG(0x0000)
+
+/* bank zero config - note, pinstrapped from OM pins! */
+#define CPU_S3C2410X_BWSCON_DW0_16  (1<<1)
+#define CPU_S3C2410X_BWSCON_DW0_32  (2<<1)
+
+/* bank one configs */
+#define CPU_S3C2410X_BWSCON_DW1_8   (0<<4)
+#define CPU_S3C2410X_BWSCON_DW1_16  (1<<4)
+#define CPU_S3C2410X_BWSCON_DW1_32  (2<<4)
+#define CPU_S3C2410X_BWSCON_WS1     (1<<6)
+#define CPU_S3C2410X_BWSCON_ST1     (1<<7)
+
+/* bank 2 configurations */
+#define CPU_S3C2410X_BWSCON_DW2_8   (0<<8)
+#define CPU_S3C2410X_BWSCON_DW2_16  (1<<8)
+#define CPU_S3C2410X_BWSCON_DW2_32  (2<<8)
+#define CPU_S3C2410X_BWSCON_WS2     (1<<10)
+#define CPU_S3C2410X_BWSCON_ST2     (1<<11)
+
+/* bank 3 configurations */
+#define CPU_S3C2410X_BWSCON_DW3_8   (0<<12)
+#define CPU_S3C2410X_BWSCON_DW3_16  (1<<12)
+#define CPU_S3C2410X_BWSCON_DW3_32  (2<<12)
+#define CPU_S3C2410X_BWSCON_WS3     (1<<14)
+#define CPU_S3C2410X_BWSCON_ST3     (1<<15)
+
+/* bank 4 configurations */
+#define CPU_S3C2410X_BWSCON_DW4_8   (0<<16)
+#define CPU_S3C2410X_BWSCON_DW4_16  (1<<16)
+#define CPU_S3C2410X_BWSCON_DW4_32  (2<<16)
+#define CPU_S3C2410X_BWSCON_WS4     (1<<18)
+#define CPU_S3C2410X_BWSCON_ST4     (1<<19)
+
+/* bank 5 configurations */
+#define CPU_S3C2410X_BWSCON_DW5_8   (0<<20)
+#define CPU_S3C2410X_BWSCON_DW5_16  (1<<20)
+#define CPU_S3C2410X_BWSCON_DW5_32  (2<<20)
+#define CPU_S3C2410X_BWSCON_WS5     (1<<22)
+#define CPU_S3C2410X_BWSCON_ST5     (1<<23)
+
+/* bank 6 configurations */
+#define CPU_S3C2410X_BWSCON_DW6_8   (0<<24)
+#define CPU_S3C2410X_BWSCON_DW6_16  (1<<24)
+#define CPU_S3C2410X_BWSCON_DW6_32  (2<<24)
+#define CPU_S3C2410X_BWSCON_WS6     (1<<26)
+#define CPU_S3C2410X_BWSCON_ST6     (1<<27)
+
+/* bank 7 configurations */
+#define CPU_S3C2410X_BWSCON_DW7_8   (0<<28)
+#define CPU_S3C2410X_BWSCON_DW7_16  (1<<28)
+#define CPU_S3C2410X_BWSCON_DW7_32  (2<<28)
+#define CPU_S3C2410X_BWSCON_WS7     (1<<30)
+#define CPU_S3C2410X_BWSCON_ST7     (1<<31)
+
+
+/* memory set (rom, ram) */
+#define CPU_S3C2410X_BANKCON0       CPU_S3C2410X_REG(0x0004)
+#define CPU_S3C2410X_BANKCON1       CPU_S3C2410X_REG(0x0008)
+#define CPU_S3C2410X_BANKCON2       CPU_S3C2410X_REG(0x000C)
+#define CPU_S3C2410X_BANKCON3       CPU_S3C2410X_REG(0x0010)
+#define CPU_S3C2410X_BANKCON4       CPU_S3C2410X_REG(0x0014)
+#define CPU_S3C2410X_BANKCON5       CPU_S3C2410X_REG(0x0018)
+#define CPU_S3C2410X_BANKCON6       CPU_S3C2410X_REG(0x001C)
+#define CPU_S3C2410X_BANKCON7       CPU_S3C2410X_REG(0x0020)
+
+/* bank configuration registers */
+
+#define CPU_S3C2410X_BANKCON_PMCnorm  (0x00)
+#define CPU_S3C2410X_BANKCON_PMC4     (0x01)
+#define CPU_S3C2410X_BANKCON_PMC8     (0x02)
+#define CPU_S3C2410X_BANKCON_PMC16    (0x03)
+
+/* bank configurations for banks 0..7, note banks
+ * 6 and 7 have differnt configurations depending on
+ * the memory type bits! */
+
+#define CPU_S3C2410X_BANKCON_Tacp2    (0x0 << 2)
+#define CPU_S3C2410X_BANKCON_Tacp3    (0x1 << 2)
+#define CPU_S3C2410X_BANKCON_Tacp4    (0x2 << 2)
+#define CPU_S3C2410X_BANKCON_Tacp6    (0x3 << 2)
+
+#define CPU_S3C2410X_BANKCON_Tcah0    (0x0 << 4)
+#define CPU_S3C2410X_BANKCON_Tcah1    (0x1 << 4)
+#define CPU_S3C2410X_BANKCON_Tcah2    (0x2 << 4)
+#define CPU_S3C2410X_BANKCON_Tcah4    (0x3 << 4)
+
+#define CPU_S3C2410X_BANKCON_Tcoh0    (0x0 << 6)
+#define CPU_S3C2410X_BANKCON_Tcoh1    (0x1 << 6)
+#define CPU_S3C2410X_BANKCON_Tcoh2    (0x2 << 6)
+#define CPU_S3C2410X_BANKCON_Tcoh4    (0x3 << 6)
+
+#define CPU_S3C2410X_BANKCON_Tacc1     (0x0 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc2     (0x1 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc3     (0x2 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc4     (0x3 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc6     (0x4 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc8     (0x5 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc10    (0x6 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc14    (0x7 << 8)
+
+#define CPU_S3C2410X_BANKCON_Tcos0     (0x0 << 11)
+#define CPU_S3C2410X_BANKCON_Tcos1     (0x1 << 11)
+#define CPU_S3C2410X_BANKCON_Tcos2     (0x2 << 11)
+#define CPU_S3C2410X_BANKCON_Tcos4     (0x3 << 11)
+
+#define CPU_S3C2410X_BANKCON_Tacs0     (0x0 << 13)
+#define CPU_S3C2410X_BANKCON_Tacs1     (0x1 << 13)
+#define CPU_S3C2410X_BANKCON_Tacs2     (0x2 << 13)
+#define CPU_S3C2410X_BANKCON_Tacs4     (0x3 << 13)
+
+#define CPU_S3C2410X_BANKCON_SRAM      (0x0 << 15)
+#define CPU_S3C2410X_BANKCON_SDRAM     (0x3 << 15)
+
+/* next bits only for SDRAM in 6,7 */
+#define CPU_S3C2410X_BANKCON_Trdc2     (0x00 << 2)
+#define CPU_S3C2410X_BANKCON_Trdc3     (0x01 << 2)
+#define CPU_S3C2410X_BANKCON_Trdc4     (0x02 << 2)
+
+/* control column address select */
+#define CPU_S3C2410X_BANKCON_SCANb8    (0x00 << 0)
+#define CPU_S3C2410X_BANKCON_SCANb9    (0x01 << 0)
+#define CPU_S3C2410X_BANKCON_SCANb10   (0x02 << 0)
+
+#define CPU_S3C2410X_REFRESH        CPU_S3C2410X_REG(0x0024)
+#define CPU_S3C2410X_BANKSIZE       CPU_S3C2410X_REG(0x0028)
+#define CPU_S3C2410X_MRSRB6         CPU_S3C2410X_REG(0x002C)
+#define CPU_S3C2410X_MRSRB7         CPU_S3C2410X_REG(0x0030)
+
+/* mode select register(s) */
+
+#define  CPU_S3C2410X_MRSRB_CL1     (0x00 << 4)
+#define  CPU_S3C2410X_MRSRB_CL2     (0x02 << 4)
+#define  CPU_S3C2410X_MRSRB_CL3     (0x03 << 4)
+
+/* bank size register */
+#define CPU_S3C2410X_BANKSIZE_128M  (0x2 << 0)
+#define CPU_S3C2410X_BANKSIZE_64M   (0x1 << 0)
+#define CPU_S3C2410X_BANKSIZE_32M   (0x0 << 0)
+#define CPU_S3C2410X_BANKSIZE_16M   (0x7 << 0)
+#define CPU_S3C2410X_BANKSIZE_8M    (0x6 << 0)
+#define CPU_S3C2410X_BANKSIZE_4M    (0x5 << 0)
+#define CPU_S3C2410X_BANKSIZE_2M    (0x4 << 0)
+
+/* interrupt controller */
+
+#define CPU_S3C2410X_SRCPND         CPU_S3C2410X_REG(0x02000000)
+#define CPU_S3C2410X_INTMOD         CPU_S3C2410X_REG(0x02000004)
+#define CPU_S3C2410X_INTMSK         CPU_S3C2410X_REG(0x02000008)
+#define CPU_S3C2410X_PRIORITY       CPU_S3C2410X_REG(0x0200000C)
+#define CPU_S3C2410X_INTPND         CPU_S3C2410X_REG(0x02000010)
+#define CPU_S3C2410X_INTOFFSET      CPU_S3C2410X_REG(0x02000014)
+#define CPU_S3C2410X_SUBSRCPND      CPU_S3C2410X_REG(0x02000018)
+#define CPU_S3C2410X_INTSUBMSK      CPU_S3C2410X_REG(0x0200001C)
+
+/* serial ports */
+
+#define CPU_S3C2410X_SERIAL_BASE(port) (0x50000000 + (port * 0x4000))
+/* Line control         RW WORD */
+#define CPU_S3C2410X_SERIAL_ULCON 0x00
+/* General control      RW WORD */
+#define CPU_S3C2410X_SERIAL_UCON  0x04
+/* Fifo control         RW WORD */
+#define CPU_S3C2410X_SERIAL_UFCON 0x08
+/* Modem control        RW WORD */
+#define CPU_S3C2410X_SERIAL_UMCON 0x0C
+/* TX/RX Status         RO WORD */
+#define CPU_S3C2410X_SERIAL_UTRSTAT 0x10
+/* Receive Error Status RO WORD */
+#define CPU_S3C2410X_SERIAL_UERSTAT 0x14
+/* FiFo Status          RO WORD */
+#define CPU_S3C2410X_SERIAL_UFSTAT 0x18
+/* Modem Status         RO WORD */
+#define CPU_S3C2410X_SERIAL_UMSTAT 0x1C
+/* TX buffer            WR BYTE */
+#define CPU_S3C2410X_SERIAL_UTXH 0x20
+/* RX buffer            RO BYTE */
+#define CPU_S3C2410X_SERIAL_URXH 0x24
+/* BAUD Divisor         RW WORD */
+#define CPU_S3C2410X_SERIAL_UBRDIV 0x28
+
+/* LCD */
+#define CPU_S3C2410X_LCD_BASE	0x4D000000
+
+/* IIC */
+#define CPU_S3C2410X_IIC_BASE	0x54000000
+
+/* Watchdog */
+#define CPU_S3C2410X_WDOG_BASE	0x53000000
+
+/* NAND */
+#define CPU_S3C2410X_NAND_BASE	0x4E000000
+
+/* GPIO */
+#define CPU_S3C2410X_GPIO_BASE	0x56000000
+
+/* Interrupt controller */
+#define CPU_S3C2410X_IRQ_BASE 0x4A000000
+/* IRQ request status              RW WORD */
+#define CPU_S3C2410X_IRQ_SRCPND 0
+/* Interrupt mode control          WR WORD */
+#define CPU_S3C2410X_IRQ_INTMOD 1
+/* Interrupt mask control          RW WORD */
+#define CPU_S3C2410X_IRQ_INTMSK 2
+/* IRQ priority control            WR WORD */
+#define CPU_S3C2410X_IRQ_PRIORITY 3
+/* Interrupt request status        RW WORD */
+#define CPU_S3C2410X_IRQ_INTPND 4
+/* Interrupt request source offset RO WORD */
+#define CPU_S3C2410X_IRQ_OFFSET 5
+/* Sub-source pending              RW WORD */
+#define CPU_S3C2410X_IRQ_SUBSRCPND 6
+/* Interrupt sub-mask              RW WORD */
+#define CPU_S3C2410X_IRQ_INTSUBMSK 7
+
+/* Timers */
+
+#define CPU_S3C2410X_TIMERS_BASE 0x51000000
+/* Timer configuration 0 */
+#define CPU_S3C2410X_TIMERS_TCFG0 0
+/* Timer configuration 1 */
+#define CPU_S3C2410X_TIMERS_TCFG1 1
+/* Timer control */
+#define CPU_S3C2410X_TIMERS_TCON 2
+/* Timer count buffer 0 */
+#define CPU_S3C2410X_TIMERS_TCNTB0 3
+/* Timer compare buffer 0 */
+#define CPU_S3C2410X_TIMERS_TCMPB0 4
+/* Timer count observation 0 */
+#define CPU_S3C2410X_TIMERS_TCNTO0 5
+/* Timer count buffer 1 */
+#define CPU_S3C2410X_TIMERS_TCNTB1 6
+/* Timer compare buffer 1 */
+#define CPU_S3C2410X_TIMERS_TCMPB1 7
+/* Timer count observation 1 */
+#define CPU_S3C2410X_TIMERS_TCNTO1 8
+/* Timer count buffer 2 */
+#define CPU_S3C2410X_TIMERS_TCNTB2 9
+/* Timer compare buffer 2 */
+#define CPU_S3C2410X_TIMERS_TCMPB2 10
+/* Timer count observation 2 */
+#define CPU_S3C2410X_TIMERS_TCNTO2 11
+/* Timer count buffer 3 */
+#define CPU_S3C2410X_TIMERS_TCNTB3 12
+/* Timer compare buffer 3 */
+#define CPU_S3C2410X_TIMERS_TCMPB3 13
+/* Timer count observation 3 */
+#define CPU_S3C2410X_TIMERS_TCNTO3 14
+/* Timer count buffer 4 */
+#define CPU_S3C2410X_TIMERS_TCNTB4 15
+/* Timer count observation 4 */
+#define CPU_S3C2410X_TIMERS_TCNTO4 16
+
+/* Real time clock */
+#define CPU_S3C2410X_RTC_BASE 0x57000040
+/* RTC Control RW Byte */
+#define CPU_S3C3410X_REG_RTCCON 0
+/* Tick time count RW Byte */
+#define CPU_S3C2410X_REG_TICNT 1
+/* RTC Alarm Control RW Byte */
+#define CPU_S3C2410X_REG_RTCALM 4
+/* Alarm second */
+#define CPU_S3C2410X_REG_ALMSEC 5
+/* Alarm minute */
+#define CPU_S3C2410X_REG_ALMMIN 6
+/* Alarm hour */
+#define CPU_S3C2410X_REG_ALMHOUR 7
+/* Alarm day */
+#define CPU_S3C2410X_REG_ALMDATE 8
+/* Alarm month */
+#define CPU_S3C2410X_REG_ALMMON 9
+/* Alarm year */
+#define CPU_S3C2410X_REG_ALMYEAR 10
+/* RTC Round Reset */
+#define CPU_S3C2410X_REG_RTCRST 11
+/* BCD Second */
+#define CPU_S3C2410X_REG_BCDSEC 12
+/* BCD Minute */
+#define CPU_S3C2410X_REG_BCDMIN 13
+/* BCD Hour */
+#define CPU_S3C2410X_REG_BCDHOUR 14
+/* BCD Day */
+#define CPU_S3C2410X_REG_BCDDATE 15
+/* BCD Day of week */
+#define CPU_S3C2410X_REG_BCDDAY 16
+/* BCD Month */
+#define CPU_S3C2410X_REG_BCDMON 17
+/* BCD Year */
+#define CPU_S3C2410X_REG_BCDYEAR 18
+
+/* External */
+S3CState *s3c2410x_init(int ram_size);
+
+#endif /* S3C2410X_H */
Index: hw/s3c24xx_timers.c
===================================================================
--- hw/s3c24xx_timers.c	(revision 0)
+++ hw/s3c24xx_timers.c	(revision 0)
@@ -0,0 +1,118 @@
+/* hw/s3c24xx_timers.c
+ *
+ * Samsung S3C24XX emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+#include "qemu-timer.h"
+
+/*
+  
+  NOTE: This is assumptions based on Simtec's boards which all supply
+  12MHz to TCLK1 to allow consistent timing input. Perhaps the S3CState will
+  need something to help manage this at a later time.
+  
+QEMU_TIMER_BASE is ticks per second for the qemu clocks
+TCLK1 (assumed input for timer4) is 12 MHz
+Thus, period in ticks of timer4 is:
+
+(timer4_period * QEMU_TIMER_BASE) / 12000000
+
+ */
+  
+#define MEGA 1000000
+#define HERTZ 1
+  
+#define TCLK1 (12 * MEGA * HERTZ)
+  
+static void
+s3c24xx_schedule_timer4(S3CState *soc)
+{
+  soc->timers_reg[CPU_S3C2410X_TIMERS_TCNTB4] = soc->timer4_reload_value;
+  soc->timer4_last_ticked = qemu_get_clock(vm_clock);
+  qemu_mod_timer(soc->timer4, soc->timer4_last_ticked + ((soc->timer4_reload_value*ticks_per_sec)/TCLK1));
+}
+
+static void
+s3c24xx_timer4_tick(void *opaque)
+{
+  S3CState *soc = (S3CState *)opaque;
+  S3C24XX_DBF("Timer4 goes TICK!\n");
+  qemu_set_irq(soc->irqs[14], 1);
+  if (soc->timers_reg[CPU_S3C2410X_TIMERS_TCON] && (1<<22)) {
+    s3c24xx_schedule_timer4(soc);
+  }
+}
+
+static void
+s3c24xx_timers_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x1f;
+  S3C24XX_DBF("Write TIMERS[%02x] = %08x\n",addr<<2, value);
+  soc->timers_reg[addr] = value;
+  if( addr == CPU_S3C2410X_TIMERS_TCON ) {
+    /* If Timer4's manual update is set, copy in the reload value */
+    if( value & (1 << 21) ) 
+      soc->timer4_reload_value = soc->timers_reg[CPU_S3C2410X_TIMERS_TCNTB4];
+    /* If Timer4's manual update is unset, and the timer is running, start it */
+    if( !(value & (1 << 21)) && value & (1 << 20)) {
+      s3c24xx_schedule_timer4(soc);
+    }
+  }
+}
+
+static uint32_t
+s3c24xx_timers_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x1f;
+  S3C24XX_DBF("Read TIMERS[%02x]\n",addr<<2);
+  if( addr == CPU_S3C2410X_TIMERS_TCNTO4 ) {
+    return soc->timer4_reload_value - (((qemu_get_clock(vm_clock)-soc->timer4_last_ticked)*TCLK1)/ticks_per_sec);
+  }
+  return soc->timers_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c24xx_timers_read[] = {
+  &s3c24xx_timers_read_f,
+  &s3c24xx_timers_read_f,
+  &s3c24xx_timers_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_timers_write[] = {
+  &s3c24xx_timers_write_f,
+  &s3c24xx_timers_write_f,
+  &s3c24xx_timers_write_f,
+};
+
+void
+s3c24xx_timers_init(S3CState *soc)
+{
+  /* Samsung S3C2410X TIMERS registration.
+   *
+   * Specifically the PWM timer4.
+   */
+  int tag = cpu_register_io_memory(0, s3c24xx_timers_read, s3c24xx_timers_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_TIMERS_BASE, 17*4, tag);
+  soc->timer4 = qemu_new_timer(vm_clock, s3c24xx_timer4_tick, soc);
+}
+
+/*
+  
+Need to set up a timer against the vm_clock for 12MHz. (Virtual TCLK1)
+
+Then we only provide timer4 anyway, and it will always be configured to use TCLK1
+
+We need to take on board the count/compare values, and when the timer is reloaded, we set
+a qemu_timer_mod to call us back at the appropriate VM tick.
+
+At that point we probably raise an interrupt.
+
+*/
Index: hw/stcpmu.c
===================================================================
--- hw/stcpmu.c	(revision 0)
+++ hw/stcpmu.c	(revision 0)
@@ -0,0 +1,114 @@
+/* Chrontel 7xxx (7006 in particular) stub implementation.
+ *
+ * Copyright 2008 Daniel Silverstone <dsilvers@simtec.co.uk> and
+ * Vincent Sanders <vince@simtec.co.uk>
+ *
+ */
+
+#include "qemu-common.h"
+#include "i2c.h"
+#include <stdio.h>
+#include "stcpmu.h"
+
+//#define DBF(X...) fprintf(stderr, "QEMU: stcpmu: " X)
+#define DBF(X...)
+
+unsigned char stcpmu_ident[] = "SBPM";
+unsigned char stcpmu_uniqueid[] = "\0\0QEMU";
+
+
+typedef struct stcpmu_state_s {
+  i2c_slave i2c;
+  int reg;
+  int rdidx;
+  int wridx;
+} stcpmu_state_t;
+
+static int
+stcpmu_rx(i2c_slave *i2c)
+{
+    stcpmu_state_t *s = (stcpmu_state_t *)i2c;
+    int ret = 0;
+    
+    DBF("Read from reg %d byte %d\n", s->reg, s->rdidx);
+    
+    switch (s->reg) {
+
+    case IICREG_IDENT:        
+        if (s->rdidx >= 4)
+            ret = 0;
+        else
+            ret = stcpmu_ident[s->rdidx];
+        s->rdidx++;        
+        break;
+
+    case IICREG_VER:
+        ret = STCPMU_VCURR;
+        break;
+        
+    case IICREG_IRQEN:
+        ret = 0x02;
+        break;
+        
+    case IICREG_UNQID:
+        if (s->rdidx >= 6)
+            ret = 0;
+        else
+            ret = stcpmu_uniqueid[s->rdidx];
+        s->rdidx++;                
+        break;
+
+    case IICREG_GPIO_PRESENT:
+            ret = 0;
+        s->rdidx++;                
+    }
+
+    DBF("Result 0x%02x\n", ret);
+    
+    return ret;
+}
+
+static int
+stcpmu_tx(i2c_slave *i2c, uint8_t data)
+{
+  DBF("Write : %d\n", data);
+  stcpmu_state_t *s = (stcpmu_state_t *)i2c;
+  if (s->wridx == 0) {
+    s->reg = data;
+    s->wridx++;
+    return 0;
+  }
+  
+  return 0;
+}
+
+static void
+stcpmu_event(i2c_slave *i2c, enum i2c_event event)
+{
+  stcpmu_state_t *s = (stcpmu_state_t *)i2c;
+  DBF("EV? %d\n", event);
+  switch (event) {
+  case I2C_START_RECV:
+    s->rdidx = 0;
+    break;
+  case I2C_START_SEND:
+    s->wridx = 0;
+    break;
+  case I2C_FINISH:
+  case I2C_NACK:
+      break;
+  }
+}
+
+i2c_slave *
+stcpmu_init(i2c_bus *bus, int addr)
+{
+  stcpmu_state_t *s = (stcpmu_state_t *)
+    i2c_slave_init(bus, addr, sizeof(stcpmu_state_t));
+  
+  s->i2c.event = stcpmu_event;
+  s->i2c.recv = stcpmu_rx;
+  s->i2c.send = stcpmu_tx;
+  
+  return &s->i2c;
+}
Index: hw/stcpmu.h
===================================================================
--- hw/stcpmu.h	(revision 0)
+++ hw/stcpmu.h	(revision 0)
@@ -0,0 +1,129 @@
+/* pmuregs.h
+ *
+ * Register definitions for the Simtec PMU.
+ *
+ * Copyright 2006 Simtec Electronics.
+ */
+
+#ifndef PMUREGS_H
+#define PMUREGS_H
+
+/* Versions of the Simtec Power management interface. */
+/* Version 1.0 interfcae */
+#define STCPMU_V1_02		 2
+
+/* Version 1.2 interface never existed */
+
+/* Version 1.3 interface */
+#define STCPMU_V1_30		30
+#define STCPMU_V1_31		31
+#define STCPMU_V1_32		32
+#define STCPMU_V1_33		33
+#define STCPMU_V1_34		34 
+
+#define STCPMU_VCURR STCPMU_V1_34 /**< Current revision of the PMU interface. */
+
+/* IIC registers */
+
+/* Version 1.20 regs */
+#define IICREG_IDENT		0	/**< PMU ident (SBPM) */
+#define IICREG_VER		1	/**< PMU version information. */
+#define IICREG_DDCEN		2	/**< Enables/disables the DDC_EN pin */
+#define IICREG_PWR		3	/**< Soft power switch */
+#define IICREG_RST		4	/**< Press the reset button */
+#define IICREG_GWO		5	/**< Global Wake On ... */
+#define IICREG_WOL		6	/**< Wake On LAN */
+#define IICREG_WOR		7	/**< Wake On Ring */
+#define IICREG_SND		8	/**< Play note */
+#define IICREG_UNQID		9	/**< Unique ID */
+#define IICREG_SLEEP		10	/**< Enter Sleep mode */
+
+/* Version 1.30 regs */
+#define IICREG_IRQEN		5	/**< Non zero to enable irqs */
+
+#define IICREG_STATUS		11	/**< (0x0b) status of last operation */
+
+#define IICREG_GPIO_PRESENT	20	/**< (0x14) Pullup enables */
+#define IICREG_GPIO_PULLUP	21	/**< (0x15) Pullup enables */
+#define IICREG_GPIO_DDR		22	/**< (0x16) Direction, 1=out, 0=in */
+#define IICREG_GPIO_STATUS	23	/**< (0x17) GPIO current status (rd) */
+#define IICREG_GPIO_SET		23	/**< (0x17) GPIO output bit set */
+#define IICREG_GPIO_CLEAR	24	/**< (0x18) GPIO output bit clear */
+#define IICREG_GPIO_IRQSOURCE	25	/**< (0x19) Source IRQ mask */
+#define IICREG_GPIO_IRQEDGE	26	/**< (0x1a) IRQ Edge/Level select  */
+#define IICREG_GPIO_IRQPOLARITY	27	/**< (0x1b) IRQ polarity */
+#define IICREG_GPIO_IRQSTATUS	28	/**< (0x1c) IRQs pending, write clears*/
+#define IICREG_GPIO_IRQDELAY	29	/**< (0x1d) IRQ delay mask */
+#define IICREG_GPIO_DELAY	30	/**< (0x1e) delay time in deciseconds */
+#define IICREG_GPIO_IRQBOTHEDGE 31	/**< (0x1f) IRQs on either edge */
+#define IICREG_GPIO_IRQFIRST	32	/**< (0x20) First IRQ detected */
+#define IICREG_GPIO_IRQRAW	33	/**< (0x21) IRQ raw status */
+
+#define IICREG_ADC_INFO         39      /**< Information about the ADC. */
+#define IICREG_ADC_PRESENT	40	/**< ADC presence indicators. */
+#define IICREG_ADC_IRQSOURCE	41      /**< ADC IRQ source enables. */
+#define IICREG_ADC_IRQSTATUS	42	/**< ADC IRQ status. */
+#define IICREG_ADC_POLARITY	43	/**< ADC IRQ polarity. */
+#define IICREG_ADC_0		44	/**< ADC 0 value. */
+#define IICREG_ADC_1		45	/**< ADC 1 value. */
+#define IICREG_ADC_2		46	/**< ADC 2 value. */
+#define IICREG_ADC_3		47	/**< ADC 3 value. */
+#define IICREG_ADC_4		48	/**< ADC 4 value. */
+#define IICREG_ADC_5		49	/**< ADC 5 value. */
+#define IICREG_ADC_6		50	/**< ADC 6 value. */
+#define IICREG_ADC_7		51	/**< ADC 7 value. */
+#define IICREG_ADC_0_THRESHOLD	52	/**< ADC 0 threshold. */
+#define IICREG_ADC_1_THRESHOLD	53	/**< ADC 1 threshold. */
+#define IICREG_ADC_2_THRESHOLD	54	/**< ADC 2 threshold. */
+#define IICREG_ADC_3_THRESHOLD	55	/**< ADC 3 threshold. */
+#define IICREG_ADC_4_THRESHOLD	56	/**< ADC 4 threshold. */
+#define IICREG_ADC_5_THRESHOLD	57	/**< ADC 5 threshold. */
+#define IICREG_ADC_6_THRESHOLD	58	/**< ADC 6 threshold. */
+#define IICREG_ADC_7_THRESHOLD	59	/**< ADC 7 threshold. */
+
+/* Version 1.32 registers */
+
+#define IICREG_HWINFO		12	/**< (0x0C) Hardware specific information. */
+
+/* Version 1.33 registers */
+#define IICREG_IMPSPEC		13	/**< (0x0D) Implementation specific. */
+
+/* Version 1.34 registers */
+#define IICREG_WDG_POR		64	/**< (0x40) Power-On / Reset watchdog. */
+#define IICREG_WDG_BUSBEAT	65	/**< (0x41) Bus heartbeat watchdog. */
+
+/* DEBUG registers - only present in debug builds */
+#define IICREG_SCRATCH          128
+
+
+#define IICREG_EEBASE 0xC0
+
+/* eeprom area */
+#define EEPROT 0x08	/* number of write once protected bytes */
+#define EELNGH 0x40
+#define IICREG_EE0   (IICREG_EEBASE + EEPROT) /* EEPROM location 0 (allowing for uniqueID) */
+#define IICREG_EEMAX ((IICREG_EE0 + (EELNGH - EEPROT))-1)
+
+/* EEPROM config byte locations */
+#define EELOC_WOL (EEPROT + 0)
+#define EELOC_WOR (EEPROT + 1)
+
+/* ident bytes */
+#define IICIDENT_0	0x53	/* S */
+#define IICIDENT_1	0x42	/* B */
+#define IICIDENT_2	0x50	/* P */
+#define IICIDENT_3	0x4d	/* M */
+
+
+/* Guard value for potentially hazardous operations (reset, sleep and power off) */
+#define IIC_GUARD 0x55
+
+/* status codes - pmu status of last request */
+#define PMUSTATUS_OK		(0)
+#define PMUSTATUS_ERROR		(1)	/* general failed operation */
+#define PMUSTATUS_ACCESS	(2)	/* no writable register here */
+#define PMUSTATUS_REGISTER	(3)	/* no readable register here */
+#define PMUSTATUS_SHORT		(4)	/* not enough data for operation */
+#define PMUSTATUS_INVALID	(5)	/* guard invalid */
+
+#endif
Index: hw/s3c24xx_rtc.c
===================================================================
--- hw/s3c24xx_rtc.c	(revision 0)
+++ hw/s3c24xx_rtc.c	(revision 0)
@@ -0,0 +1,82 @@
+/* hw/s3c24xx_rtc.c
+ *
+ * Samsung S3C24XX RTC emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+
+static inline int to_bcd(int a)
+{
+  return ((a/10)<<4) | (a%10);
+}
+
+static void
+s3c24xx_rtc_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_) >> 2;
+  if (addr < 0 || addr > 18) addr = 18;
+  S3C24XX_DBF("Write RTC[%d] = %08x\n", addr, value);
+  soc->rtc_reg[addr] = value;
+}
+
+static uint32_t
+s3c24xx_rtc_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_) >> 2;
+  struct tm *tm;
+  time_t ti;
+  if (addr < 0 || addr > 18) addr = 18;
+  S3C24XX_DBF("Read RTC[%d]\n", addr);
+  if( addr >= CPU_S3C2410X_REG_BCDSEC &&
+      addr <= CPU_S3C2410X_REG_BCDYEAR ) {
+    time(&ti);
+    tm = gmtime(&ti);
+    switch(addr) {
+    case CPU_S3C2410X_REG_BCDSEC:
+      return to_bcd(tm->tm_sec);
+    case CPU_S3C2410X_REG_BCDMIN:
+      return to_bcd(tm->tm_min);
+    case CPU_S3C2410X_REG_BCDHOUR:
+      return to_bcd(tm->tm_hour);
+    case CPU_S3C2410X_REG_BCDDATE:
+      return to_bcd(tm->tm_mday);
+    case CPU_S3C2410X_REG_BCDDAY:
+      return to_bcd(tm->tm_wday+1);
+    case CPU_S3C2410X_REG_BCDMON:
+      return to_bcd(tm->tm_mon+1);
+    case CPU_S3C2410X_REG_BCDYEAR:
+      return to_bcd(tm->tm_year-100);
+    }
+  }
+  return soc->rtc_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c24xx_rtc_read[] = {
+  &s3c24xx_rtc_read_f,
+  &s3c24xx_rtc_read_f,
+  &s3c24xx_rtc_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_rtc_write[] = {
+  &s3c24xx_rtc_write_f,
+  &s3c24xx_rtc_write_f,
+  &s3c24xx_rtc_write_f,
+};
+
+
+void
+s3c24xx_rtc_init(S3CState *soc)
+{
+  int tag;
+  tag = cpu_register_io_memory(0, s3c24xx_rtc_read, s3c24xx_rtc_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_RTC_BASE, 19*4, tag);
+  for(tag=0; tag < 18; ++tag)
+    soc->rtc_reg[tag] = 0;
+}
Index: hw/ch7xxx.c
===================================================================
--- hw/ch7xxx.c	(revision 0)
+++ hw/ch7xxx.c	(revision 0)
@@ -0,0 +1,76 @@
+/* Chrontel 7xxx (7006 in particular) stub implementation.
+ *
+ * Copyright 2008 Daniel Silverstone <dsilvers@simtec.co.uk> and
+ * Vincent Sanders <vince@simtec.co.uk>
+ *
+ */
+
+#include "qemu-common.h"
+#include "i2c.h"
+#include <stdio.h>
+
+//#define DBF(X...) fprintf(stderr, "QEMU:ch7xxx:" X)
+#define DBF(X...)
+
+typedef struct ch7xxx_state_s {
+  i2c_slave i2c;
+  int reg;
+  int wridx;
+} ch7xxx_state_t;
+
+static int
+ch7xxx_rx(i2c_slave *i2c)
+{
+    ch7xxx_state_t *s = (ch7xxx_state_t *)i2c;
+    DBF("RX?\n");
+    
+    switch (s->reg) {
+    case 0x25:
+      return 0x2A; /* CH7006 ID */
+    }
+    
+    return 0x00;
+}
+
+static int
+ch7xxx_tx(i2c_slave *i2c, uint8_t data)
+{
+  DBF("TX: %d\n", data);
+  ch7xxx_state_t *s = (ch7xxx_state_t *)i2c;
+  if (s->wridx == 0) {
+    s->reg = data;
+    s->wridx++;
+    return 0;
+  }
+  
+  return 0;
+}
+
+static void
+ch7xxx_event(i2c_slave *i2c, enum i2c_event event)
+{
+  ch7xxx_state_t *s = (ch7xxx_state_t *)i2c;
+  DBF("EV? %d\n", event);
+  switch (event) {
+  case I2C_START_RECV:
+    break;
+  case I2C_START_SEND:
+    s->wridx = 0;
+  case I2C_FINISH:
+  case I2C_NACK:
+      break;
+  }
+}
+
+i2c_slave *
+ch7xxx_init(i2c_bus *bus, int addr)
+{
+  ch7xxx_state_t *s = (ch7xxx_state_t *)
+    i2c_slave_init(bus, addr, sizeof(ch7xxx_state_t));
+  
+  s->i2c.event = ch7xxx_event;
+  s->i2c.recv = ch7xxx_rx;
+  s->i2c.send = ch7xxx_tx;
+  
+  return &s->i2c;
+}
Index: hw/ide.c
===================================================================
--- hw/ide.c	(revision 6883)
+++ hw/ide.c	(working copy)
@@ -2605,6 +2605,7 @@
             ret = 0;
         else
             ret = s->select;
+        ret |= 0x80;
         break;
     default:
     case 7:
@@ -3849,6 +3850,87 @@
     cpu_register_physical_memory(membase2, 2 << shift, mem2);
 }
 
+#if defined(TARGET_ARM)
+#include "s3c2410x.h"
+
+/* MMIO interface to IDE on Simtec's BAST
+ *
+ * Copyright Daniel Silverstone and Vincent Sanders
+ *
+ * This section of this file is under the terms of
+ * the GNU General Public License Version 2
+ */
+
+/* Each BAST IDE region is 0x1000000 bytes long, 
+ * the second half is the "alternate" register set 
+ */
+
+static void stcb_ide_write_f (void *opaque,
+                            target_phys_addr_t addr, uint32_t val)
+{
+    int reg = (addr & 0x3ff) >> 5; /* 0x200 long, 0x20 stride */
+    int alt = (addr & 0x800000) != 0;
+    S3C24XX_DBF("IDE write to addr %08x (reg %d) of value %04x\n", (unsigned int)addr, reg, val);
+    if (alt) {
+        ide_cmd_write(opaque, 0, val);
+    }
+    if (reg == 0) {
+        /* Data register */
+        ide_data_writew(opaque, 0, val);
+    } else {
+        /* Everything else */
+        ide_ioport_write(opaque, reg, val);
+    }
+}
+
+static uint32_t stcb_ide_read_f (void *opaque,target_phys_addr_t addr)
+{
+    int reg = (addr & 0x3ff) >> 5; /* 0x200 long, 0x20 stride */
+    int alt = (addr & 0x800000) != 0;
+    S3C24XX_DBF("IDE read of addr %08x (reg %d)\n", (unsigned int)addr, reg);
+    if (alt) {
+        return ide_status_read(opaque, 0);
+    }
+    if (reg == 0) {
+        return ide_data_readw(opaque, 0);
+    } else {
+        return ide_ioport_read(opaque, reg);
+    }
+}
+
+
+static CPUWriteMemoryFunc *stcb_ide_write[] = {
+    stcb_ide_write_f,
+    stcb_ide_write_f,
+    stcb_ide_write_f,
+};
+
+static CPUReadMemoryFunc *stcb_ide_read[] = {
+    stcb_ide_read_f,
+    stcb_ide_read_f,
+    stcb_ide_read_f,
+};
+
+/* hd_table must contain 2 block drivers */
+/* BAST uses memory mapped registers, not I/O. Return the memory
+ * I/O tag to access the ide.
+ * The BAST description will register it into the map in the right place.
+ */
+int stcb_ide_init (BlockDriverState *hd0, BlockDriverState *hd1, qemu_irq irq)
+{
+    IDEState *ide_if;
+    int stcb_ide_memory;
+
+    ide_if = qemu_mallocz(sizeof(IDEState) * 2);
+    ide_init2(&ide_if[0], hd0, hd1, irq);
+    
+    stcb_ide_memory = cpu_register_io_memory(0, stcb_ide_read,
+                                             stcb_ide_write, &ide_if[0]);
+    return stcb_ide_memory;
+}
+
+#endif
+
 /***********************************************************/
 /* CF-ATA Microdrive */
 
Index: hw/dm9000.c
===================================================================
--- hw/dm9000.c	(revision 0)
+++ hw/dm9000.c	(revision 0)
@@ -0,0 +1,633 @@
+/* hw/dm9000.c
+ *
+ * DM9000 Ethernet interface
+ *
+ * Copyright 2006, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "hw.h"
+#include "qemu-common.h"
+#include "hw/irq.h"
+#include "net.h"
+
+/* Comment this out if you don't want register debug on stderr */
+/* #define DM9000_DEBUG */
+
+#ifdef DM9000_DEBUG
+#define DM9000_DBF(X...) do { fprintf(stderr, X); } while(0)
+#else
+#define DM9000_DBF(X...) do { if (0) fprintf(stderr, X); } while (0)
+#endif
+
+#define DM9000_REG_NCR 0x00
+#define DM9000_REG_NSR 0x01
+#define DM9000_REG_TCR 0x02
+#define DM9000_REG_TSR1 0x03
+#define DM9000_REG_TSR2 0x04
+#define DM9000_REG_RCR 0x05
+#define DM9000_REG_RSR 0x06
+#define DM9000_REG_ROCR 0x07
+#define DM9000_REG_BPTR 0x08
+#define DM9000_REG_FCTR 0x09
+#define DM9000_REG_FCR 0x0A
+#define DM9000_REG_EPCR 0x0B
+#define DM9000_REG_EPAR 0x0C
+#define DM9000_REG_EPDRL 0x0D
+#define DM9000_REG_EPDRH 0x0E
+#define DM9000_REG_WCR 0x0F
+#define DM9000_REG_PAR0 0x10
+#define DM9000_REG_PAR1 0x11
+#define DM9000_REG_PAR2 0x12
+#define DM9000_REG_PAR3 0x13
+#define DM9000_REG_PAR4 0x14
+#define DM9000_REG_PAR5 0x15
+#define DM9000_REG_MAR0 0x16
+#define DM9000_REG_MAR1 0x17
+#define DM9000_REG_MAR2 0x18
+#define DM9000_REG_MAR3 0x19
+#define DM9000_REG_MAR4 0x1A
+#define DM9000_REG_MAR5 0x1B
+#define DM9000_REG_MAR6 0x1C
+#define DM9000_REG_MAR7 0x1D
+#define DM9000_REG_GPCR 0x1E
+#define DM9000_REG_GPR 0x1F
+#define DM9000_REG_TRPAL 0x22
+#define DM9000_REG_TRPAH 0x23
+#define DM9000_REG_RWPAL 0x24
+#define DM9000_REG_RWPAH 0x25
+#define DM9000_REG_VIDL 0x28
+#define DM9000_REG_VIDH 0x29
+#define DM9000_REG_PIDL 0x2A
+#define DM9000_REG_PIDH 0x2B
+#define DM9000_REG_CHIPR 0x2C
+#define DM9000_REG_SMCR 0x2F
+#define DM9000_REG_MRCMDX 0xF0
+#define DM9000_REG_MRCMD 0xF2
+#define DM9000_REG_MRRL 0xF4
+#define DM9000_REG_MRRH 0xF5
+#define DM9000_REG_MWCMDX 0xF6
+#define DM9000_REG_MWCMD 0xF8
+#define DM9000_REG_MWRL 0xFA
+#define DM9000_REG_MWRH 0xFB
+#define DM9000_REG_TXPLL 0xFC
+#define DM9000_REG_TXPLH 0xFD
+#define DM9000_REG_ISR 0xFE
+#define DM9000_REG_IMR 0xFF
+
+#define DM9000_NCR_RESET 0x01
+#define DM9000_NSR_TX1END 0x04
+#define DM9000_NSR_TX2END 0x08
+#define DM9000_TCR_TXREQ 0x01
+
+#define DM9000_IMR_AUTOWRAP 0x80
+
+#define DM9000_MII_READ 0x0C
+#define DM9000_MII_WRITE 0x0A
+
+#define DM9000_MII_REG_BMCR 0x00
+#define DM9000_MII_REG_STATUS 0x01
+#define DM9000_MII_REG_PHYID1 0x02
+#define DM9000_MII_REG_PHYID2 0x03
+#define DM9000_MII_REG_ANAR 0x04
+#define DM9000_MII_REG_ANLPAR 0x05
+#define DM9000_MII_REG_ANER 0x06
+#define DM9000_MII_REG_DSCR 0x10
+#define DM9000_MII_REG_DSCSR 0x11
+#define DM9000_MII_REG_10BTCSR 0x12
+
+
+typedef struct {
+    target_phys_addr_t addr; /* address port */
+    target_phys_addr_t data; /* data port */
+    VLANClientState *vc;
+    qemu_irq irq;
+    uint8_t macaddr[6];
+    uint8_t multihash[8]; /* multicast hash table */
+    uint8_t address; /* The internal magial address */
+    uint8_t packet_buffer[16 * 1024];
+    uint16_t dm9k_mrr, dm9k_mwr; /* Read and write address registers */
+    uint16_t dm9k_txpl; /* TX packet length */
+    uint16_t dm9k_trpa, dm9k_rwpa; /* TX Read ptr address, RX write ptr address */
+    uint8_t dm9k_imr, dm9k_isr; /* Interrupt mask register and status register*/
+    uint8_t dm9k_ncr, dm9k_nsr; /* Network control register, network status register */
+    uint8_t dm9k_wcr; /* Wakeup control */
+    uint8_t dm9k_tcr; /* Transmission control register */
+    uint8_t packet_copy_buffer[3 * 1024]; /* packet copy buffer */
+    unsigned int packet_index:1; /* 0 == packet I, 1 == packet II */
+    
+    /* Internal MII PHY state */
+    uint8_t dm9k_epcr; /* EEPROM/PHY control register */
+    uint8_t dm9k_epar; /* EEPROM/PHY address register */
+    uint16_t dm9k_epdr; /* EEPROM/PHY data register */
+    /* MII Regs */
+    uint16_t dm9k_mii_bmcr;
+    uint16_t dm9k_mii_anar;
+    uint16_t dm9k_mii_dscr;
+} dm9000_state;
+
+static void dm9000_raise_irq(dm9000_state *state)
+{
+    int level = ((state->dm9k_isr & state->dm9k_imr) & 0x03) != 0;
+    DM9000_DBF("DM9000: Set IRQ level %d\n", level);
+    qemu_set_irq(state->irq, level);
+}
+
+static void dm9000_soft_reset_mii(dm9000_state *state)
+{
+    state->dm9k_mii_bmcr = 0x3100; /* 100Mbps, AUTONEG, FULL DUPLEX */
+    state->dm9k_mii_anar = 0x01E1;
+    state->dm9k_mii_dscr = 0x0410;
+}
+
+static void dm9000_soft_reset(dm9000_state *state)
+{
+    DM9000_DBF("DM9000: Soft Reset\n");
+    state->dm9k_mrr = state->dm9k_mwr = state->dm9k_txpl = state->dm9k_trpa = 0x0000;
+    state->dm9k_rwpa = 0x0C04;
+    state->dm9k_imr = 0;
+    state->dm9k_isr = 0; /* 16 bit mode, no interrupts asserted */
+    state->dm9k_tcr = 0;
+    state->packet_index = 0;
+    memset(state->packet_buffer, 0, 16*1024);
+    memset(state->packet_copy_buffer, 0, 3*1024);
+    /* These registers have some bits "unaffected by software reset" */
+    /* Clear the reset bits */
+    state->dm9k_ncr &= 0xA0;
+    state->dm9k_nsr &= 0xD0;
+    /* Claim full duplex */
+    state->dm9k_ncr |= 1<<3;
+    /* Set link status to 1 */
+    state->dm9k_nsr |= 1<<6;
+    /* dm9k_wcr is unaffected or reserved, never reset */
+    /* MII control regs */
+    state->dm9k_epcr = 0x00;
+    state->dm9k_epar = 0x40;
+    /* reset the MII */
+    dm9000_soft_reset_mii(state);
+    dm9000_raise_irq(state); /* Clear any potentially pending IRQ */
+}
+
+static void dm9000_hard_reset(dm9000_state *state)
+{
+    state->dm9k_ncr = 0x00;
+    state->dm9k_nsr = 0x00;
+    state->dm9k_wcr = 0x00;
+    dm9000_soft_reset(state);
+}
+
+static void dm9000_do_transmit(dm9000_state *state)
+{
+    uint16_t idx, cnt, tptr;
+    idx = state->dm9k_trpa;
+    cnt = state->dm9k_txpl;
+    tptr = 0;
+    if( cnt > 3*1024 ) cnt = 3*1024; /* HARD CAP AT 3KiB */
+    DM9000_DBF("TX_Packet: %d bytes from %04x\n", cnt, idx);
+    while(cnt--) {
+        state->packet_copy_buffer[tptr++] = state->packet_buffer[idx++];
+        if( idx == 0x0C00 ) idx = 0;
+    }
+    /* DM9KNOTE: Assumes 16bit wiring */
+    idx = (idx+1) & ~1; /* Round up to nearest 16bit boundary */
+    if( idx == 0x0C00 ) idx = 0;
+    state->dm9k_trpa = idx;
+    /* We have the copy buffer, now we do the transmit */
+    qemu_send_packet(state->vc, state->packet_copy_buffer, state->dm9k_txpl);
+    /* Clear the "please xmit" bit */
+    state->dm9k_tcr &= ~DM9000_TCR_TXREQ;
+    /* Set the TXEND bit */
+    state->dm9k_nsr |= 1<<(2+state->packet_index);
+    DM9000_DBF("TX: NSR=%02x PI=%d\n", state->dm9k_nsr, state->packet_index);
+    /* Claim a TX complete IRQ */
+    state->dm9k_isr |= 0x02; /* Packet transmitted latch */
+    /* And flip the next-packet bit */
+    state->packet_index = !state->packet_index;
+    dm9000_raise_irq(state);
+}
+
+static void dm9000_mii_read(dm9000_state *state)
+{
+    int mii_reg = (state->dm9k_epar) & 0x3f;
+    uint16_t ret = 0;
+    switch(mii_reg) {
+    case DM9000_MII_REG_BMCR:
+        ret = state->dm9k_mii_bmcr;
+        break;
+    case DM9000_MII_REG_STATUS:
+        ret = 0x782D; /* No 100/T4, Can 100/FD, Can 100/HD, Can 10/FD, Can 10/HD, 
+                       * No Preamble suppression, Autoneg complete, No remote fault, 
+                       * Can autoneg, link up, no jabber, extended capability */
+        break;
+    case DM9000_MII_REG_PHYID1:
+        ret = 0x0181;
+        break;
+    case DM9000_MII_REG_PHYID2:
+        ret = 0xB8C0;
+        break;
+    case DM9000_MII_REG_ANAR:
+        ret = state->dm9k_mii_anar;
+        break;
+    case DM9000_MII_REG_ANLPAR:
+        ret = 0x0400;
+        break;
+    case DM9000_MII_REG_ANER:
+        ret = 0x0001;
+        break;
+    case DM9000_MII_REG_DSCR:
+        ret = state->dm9k_mii_dscr;
+        break;
+    case DM9000_MII_REG_DSCSR:
+        ret = 0xF008;
+        break;
+    case DM9000_MII_REG_10BTCSR:
+        ret = 0x7800;
+    }
+    state->dm9k_epdr = ret;
+    DM9000_DBF("DM9000:MIIPHY: Read of MII reg %d gives %04x\n", mii_reg, state->dm9k_epdr);
+}
+
+static void dm9000_mii_write(dm9000_state *state)
+{
+    int mii_reg = (state->dm9k_epar) & 0x3f;
+    DM9000_DBF("DM9000:MIIPHY: Write of MII reg %d value %04x\n", mii_reg, state->dm9k_epdr);
+    switch(mii_reg) {
+    case DM9000_MII_REG_BMCR:
+        state->dm9k_mii_bmcr = (state->dm9k_epdr &~0x8000);
+        if( state->dm9k_epdr & 0x8000 ) dm9000_soft_reset_mii(state);
+        break;
+    case DM9000_MII_REG_ANAR:
+        state->dm9k_mii_anar = state->dm9k_epdr;
+        break;
+    case DM9000_MII_REG_DSCR:
+        state->dm9k_mii_dscr = state->dm9k_epdr & ~0x0008;
+        break;
+    }
+}
+
+static void dm9000_write(void *opaque, target_phys_addr_t address,
+                         uint32_t value)
+{
+    dm9000_state *state = (dm9000_state *)opaque;
+#ifdef DM9000_DEBUG
+    int suppress_debug = 0;
+#endif
+
+    if (address == state->addr) {
+        if( (value != DM9000_REG_MRCMD) &&
+            (value != DM9000_REG_MWCMD) )
+            DM9000_DBF("DM9000: Address set to 0x%02x\n", value);
+        state->address = value;
+        return;
+    }
+    
+    if (address != state->data) {
+        DM9000_DBF("DM9000: Write to location which is neither data nor address port: " TARGET_FMT_plx "\n", address);
+    }
+    
+    switch(state->address) {
+    case DM9000_REG_NCR:
+        state->dm9k_ncr = value & 0xDF;
+        if (state->dm9k_ncr & DM9000_NCR_RESET)
+            dm9000_soft_reset(state);
+        break;
+    case DM9000_REG_NSR:
+        state->dm9k_nsr &= ~(value & 0x2C);
+        break;
+    case DM9000_REG_TCR:
+        state->dm9k_tcr = value & 0xFF;
+        if( value & DM9000_TCR_TXREQ ) dm9000_do_transmit(state);
+        break;
+    case DM9000_REG_EPCR:
+        state->dm9k_epcr = value & 0xFF;
+        if( value & DM9000_MII_READ )
+            dm9000_mii_read(state);
+        else if( value & DM9000_MII_WRITE )
+            dm9000_mii_write(state);
+        break;
+    case DM9000_REG_EPAR:
+        state->dm9k_epar = value & 0xFF;
+        break;
+    case DM9000_REG_EPDRL:
+        state->dm9k_epdr &= 0xFF00;
+        state->dm9k_epdr |= value & 0xFF;
+        break;
+    case DM9000_REG_EPDRH:
+        state->dm9k_epdr &= 0xFF;
+        state->dm9k_epdr |= (value & 0xFF) << 8;
+        break;
+    case DM9000_REG_PAR0:
+    case DM9000_REG_PAR1:
+    case DM9000_REG_PAR2:
+    case DM9000_REG_PAR3:
+    case DM9000_REG_PAR4:
+    case DM9000_REG_PAR5:
+        state->macaddr[state->address - DM9000_REG_PAR0] = value & 0xFF;
+        break;
+    case DM9000_REG_MAR0:
+    case DM9000_REG_MAR1:
+    case DM9000_REG_MAR2:
+    case DM9000_REG_MAR3:
+    case DM9000_REG_MAR4:
+    case DM9000_REG_MAR5:
+    case DM9000_REG_MAR6:
+    case DM9000_REG_MAR7:
+        /* multicast hash setup */
+        state->multihash[state->address - DM9000_REG_MAR0] = value & 0xFF;
+        break;
+    case DM9000_REG_MRRL:
+        state->dm9k_mrr &= 0xFF00;
+        state->dm9k_mrr |= value & 0xFF;
+        break;
+    case DM9000_REG_MRRH:
+        state->dm9k_mrr &= 0xFF;
+        state->dm9k_mrr |= (value & 0xFF) << 8;
+        break;
+    case DM9000_REG_MWCMDX:
+    case DM9000_REG_MWCMD:
+        /* DM9KNOTE: This assumes a 16bit wide wiring */
+        state->packet_buffer[state->dm9k_mwr] = value & 0xFF;
+        state->packet_buffer[state->dm9k_mwr+1] = (value >> 8) & 0xFF;
+        if( state->address == DM9000_REG_MWCMD ) {
+            state->dm9k_mwr += 2;
+            if( state->dm9k_imr & DM9000_IMR_AUTOWRAP )
+                if( state->dm9k_mwr >= 0x0C00 )
+                    state->dm9k_mwr -= 0x0C00;
+        }
+#ifdef DM9000_DEBUG
+        suppress_debug = 1;
+#endif
+        break;
+    case DM9000_REG_MWRL:
+        state->dm9k_mwr &= 0xFF00;
+        state->dm9k_mwr |= value & 0xFF;
+        break;
+    case DM9000_REG_MWRH:
+        state->dm9k_mwr &= 0xFF;
+        state->dm9k_mwr |= (value & 0xFF) << 8;
+        break;
+    case DM9000_REG_TXPLL:
+        state->dm9k_txpl &= 0xFF00;
+        state->dm9k_txpl |= value & 0xFF;
+        break;
+    case DM9000_REG_TXPLH:
+        state->dm9k_txpl &= 0xFF;
+        state->dm9k_txpl |= (value & 0xFF) << 8;
+        break;
+    case DM9000_REG_ISR:
+        state->dm9k_isr &= ~(value & 0x0F);
+        dm9000_raise_irq(state);
+        break;
+    case DM9000_REG_IMR:
+        if( !(state->dm9k_imr & DM9000_IMR_AUTOWRAP) &&
+            (value & DM9000_IMR_AUTOWRAP) )
+            state->dm9k_mrr = 0x0C00 | (state->dm9k_mrr & 0xFF);
+        state->dm9k_imr = value & 0xFF;
+        dm9000_raise_irq(state);
+        break;
+    }
+#ifdef DM9000_DEBUG
+    if(!suppress_debug) DM9000_DBF("DM9000: Write value %04x\n", value);
+#endif
+}
+
+static uint32_t dm9000_read(void *opaque, target_phys_addr_t address)
+{
+    dm9000_state *state = (dm9000_state *)opaque;
+    uint32_t ret = 0;
+#ifdef DM9000_DEBUG
+    int suppress_debug = 0;
+#endif
+
+    if (address == state->addr)
+        return state->address;
+    
+    if (address != state->data) {
+        DM9000_DBF("DM9000: Read from location which is neither data nor address port: " TARGET_FMT_plx "\n", address);
+    }
+    
+    switch(state->address) {
+    case DM9000_REG_NCR:
+        ret = state->dm9k_ncr;
+        break;
+    case DM9000_REG_NSR:
+        ret = state->dm9k_nsr;
+        /* Note, TX1END and TX2END are *CLEAR ON READ* */
+        state->dm9k_nsr &= ~(DM9000_NSR_TX1END | DM9000_NSR_TX2END);
+        break;
+    case DM9000_REG_TCR:
+        ret = state->dm9k_tcr;
+        break;
+    case DM9000_REG_TSR1:
+    case DM9000_REG_TSR2:
+        ret = 0x00; /* No error, yay! */
+        break;
+    case DM9000_REG_EPCR:
+        ret = state->dm9k_epcr;
+        break;
+    case DM9000_REG_EPAR:
+        ret = state->dm9k_epar;
+        break;
+    case DM9000_REG_EPDRL:
+        ret = state->dm9k_epdr & 0xFF;
+        break;
+    case DM9000_REG_EPDRH:
+        ret = (state->dm9k_epdr >> 8) & 0xFF;
+        break;
+    case DM9000_REG_PAR0:
+    case DM9000_REG_PAR1:
+    case DM9000_REG_PAR2:
+    case DM9000_REG_PAR3:
+    case DM9000_REG_PAR4:
+    case DM9000_REG_PAR5:
+        ret = state->macaddr[state->address - DM9000_REG_PAR0];
+        break;
+    case DM9000_REG_MAR0:
+    case DM9000_REG_MAR1:
+    case DM9000_REG_MAR2:
+    case DM9000_REG_MAR3:
+    case DM9000_REG_MAR4:
+    case DM9000_REG_MAR5:
+    case DM9000_REG_MAR6:
+    case DM9000_REG_MAR7:
+        /* multicast hash  */
+        ret = state->multihash[state->address - DM9000_REG_MAR0];
+        break;
+    case DM9000_REG_TRPAL:
+        ret = state->dm9k_trpa & 0xFF;
+        break;
+    case DM9000_REG_TRPAH:
+        ret = state->dm9k_trpa >> 8;
+        break;
+    case DM9000_REG_RWPAL:
+        ret = state->dm9k_rwpa & 0xFF;
+        break;
+    case DM9000_REG_RWPAH:
+        ret = state->dm9k_rwpa >> 8;
+        break;
+    case DM9000_REG_VIDL:
+        ret = 0x46;
+        break;
+    case DM9000_REG_VIDH:
+        ret = 0x0A;
+        break;
+    case DM9000_REG_PIDL:
+        ret = 0x00;
+        break;
+    case DM9000_REG_PIDH:
+        ret = 0x90;
+        break;
+    case DM9000_REG_CHIPR:
+        ret = 0x00;
+        break;
+    case DM9000_REG_MRCMDX:
+    case DM9000_REG_MRCMD:
+        /* DM9KNOTE: This assumes a 16bit wide wiring */
+        ret = state->packet_buffer[state->dm9k_mrr];
+        ret |= state->packet_buffer[state->dm9k_mrr+1] << 8;
+        if( state->address == DM9000_REG_MRCMD ) {
+            state->dm9k_mrr += 2;
+            if( state->dm9k_mrr >= (16*1024) ) state->dm9k_mrr -= (16*1024);
+            if( state->dm9k_imr & DM9000_IMR_AUTOWRAP )
+                if( state->dm9k_mrr < 0x0C00 )
+                    state->dm9k_mrr += 0x0C00;
+        }
+#ifdef DM9000_DEBUG
+        if (state->address==DM9000_REG_MRCMD)
+            suppress_debug = 1;
+#endif
+        break;
+    case DM9000_REG_MRRL:
+        ret = state->dm9k_mrr & 0xFF;
+        break;
+    case DM9000_REG_MRRH:
+        ret = state->dm9k_mrr >> 8;
+        break;
+    case DM9000_REG_MWRL:
+        ret = state->dm9k_mwr & 0xFF;
+        break;
+    case DM9000_REG_MWRH:
+        ret = state->dm9k_mwr >> 8;
+        break;
+    case DM9000_REG_TXPLL:
+        ret = state->dm9k_txpl & 0xFF;
+        break;
+    case DM9000_REG_TXPLH:
+        ret = state->dm9k_txpl >> 8;
+        break;
+    case DM9000_REG_ISR:
+        ret = state->dm9k_isr;
+        break;
+    case DM9000_REG_IMR:
+        ret = state->dm9k_imr;
+        break;
+    default:
+        ret = 0;
+    }
+
+#ifdef DM9000_DEBUG
+    if(!suppress_debug) DM9000_DBF("DM9000: Read gives: %04x\n", ret);
+#endif
+    return ret;
+}
+
+
+
+static int dm9000_can_receive(void *opaque)
+{
+    dm9000_state *state = (dm9000_state *)opaque;
+    uint16_t rx_space;
+    if( state->dm9k_rwpa < state->dm9k_mrr )
+        rx_space = state->dm9k_mrr - state->dm9k_rwpa;
+    else
+        rx_space = (13*1024) - (state->dm9k_rwpa - state->dm9k_mrr);
+    DM9000_DBF("DM9000:RX_Packet: Asked about RX, rwpa=%d mrr=%d => space is %d bytes\n", 
+               state->dm9k_rwpa, state->dm9k_mrr, rx_space);
+    if (rx_space > 2048) return 1;
+    return 0;
+}
+
+static void dm9000_receive(void *opaque, const uint8_t *buf, int size)
+{
+    dm9000_state *state = (dm9000_state *)opaque;
+    uint16_t rxptr = state->dm9k_rwpa;
+    uint8_t magic_padding = 4;
+    if( size > 2048 ) return; /* La La La, I can't hear you */
+    /* Fill out the magical header structure */
+    DM9000_DBF("DM9000:RX_Packet: %d bytes into buffer at %04x\n", size, rxptr);
+    if( size < 64 ) magic_padding += (64 - size);
+    DM9000_DBF("DM9000:RX_Packet: Magical padding is %d bytes\n", magic_padding);
+    size += magic_padding; /* The magical CRC word */
+    state->packet_buffer[state->dm9k_rwpa-4] = 0x01; /* Packet read */
+    state->packet_buffer[state->dm9k_rwpa-3] = 0x00; /* Status OK */
+    state->packet_buffer[state->dm9k_rwpa-2] = size & 0xFF; /* Size LOW */
+    state->packet_buffer[state->dm9k_rwpa-1] = (size & 0xFF00)>>8; /* Size HIGH */
+    size += 4; /* The magical next header (which we zero for fun) */
+    while(size--) {
+        if( size > (magic_padding + 3) )
+            state->packet_buffer[rxptr++] = *buf++;
+        else
+            state->packet_buffer[rxptr++] = 0x00; /* Clear to the next header */
+        /* DM9KNOTE: Assumes 16 bit wired config */
+        if (size == 4) rxptr = (rxptr+1) & ~1; /* At end of packet, realign */
+        if( rxptr >= (16*1024) ) rxptr -= (16*1024);
+        if( rxptr < 0x0C00 ) rxptr += 0x0C00;
+    }
+    state->dm9k_rwpa = rxptr;
+    state->dm9k_isr |= 0x01; /* RX interrupt, yay */
+    dm9000_raise_irq(state);
+}
+
+
+static CPUReadMemoryFunc *dm9000_readfn[] = {
+    dm9000_read,
+    dm9000_read,
+    dm9000_read
+};
+
+static CPUWriteMemoryFunc *dm9000_writefn[] = {
+    dm9000_write,
+    dm9000_write,
+    dm9000_write
+};
+
+/* initialises a dm9000 ethernet controller
+ * The dm9k has a single 16bit wide address and data port through which all
+ *  operations are multiplexed, there is a single IRQ
+ */
+void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr,
+                 uint32_t addr_offset, uint32_t data_offset,
+                 qemu_irq irq)
+{
+    dm9000_state *state;
+    int iomemtype;
+
+    state = (dm9000_state *)qemu_mallocz(sizeof(dm9000_state));
+    iomemtype = cpu_register_io_memory(0, dm9000_readfn,
+                                       dm9000_writefn, state);
+    cpu_register_physical_memory(base_addr, MAX(addr_offset, data_offset) + 4, iomemtype);
+    state->addr = addr_offset;
+    state->data = data_offset;
+    state->irq = irq;
+    memcpy(state->macaddr, nd->macaddr, 6);
+
+    dm9000_hard_reset(state);
+
+    state->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, 
+                                     dm9000_receive, dm9000_can_receive, state);
+}
Index: hw/s3c24xx.h
===================================================================
--- hw/s3c24xx.h	(revision 0)
+++ hw/s3c24xx.h	(revision 0)
@@ -0,0 +1,88 @@
+/* hw/s3c24xx.h
+ *
+ * Samsung s3c24xx cpu state and functions.
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#ifndef S3C24XX_H
+#define S3C24XX_H 1
+
+#include "qemu-common.h"
+#include "sysemu.h"
+
+#include "console.h"
+#include "hw/irq.h"
+
+/* This structure type encapsulates the state of the
+ * S3C24XX SoC.
+ */
+typedef struct {
+  CPUState *cpu_env;
+  qemu_irq *irqs;
+  qemu_irq *eirqs;
+
+  /* Memory controller */
+  uint32_t memc_reg[13];
+
+  /* Interrupt controller */
+  uint32_t irq_main_level, irq_subsrc_level;
+  uint32_t irq_reg[8];
+
+  /* Clock controller */
+  uint32_t clkcon_reg[6];
+
+  /* GPIO block */
+  uint32_t gpio_reg[47];
+
+  /* Realtime clock */
+  uint8_t rtc_reg[19];
+
+  /* i2c */
+  struct s3c24xx_i2c_state_s *iic;
+    
+  /* Timers, (Specifically timer4) */
+  uint32_t timers_reg[17];
+  QEMUTimer *timer4;
+  uint32_t timer4_reload_value;
+  int64_t timer4_last_ticked;
+
+    /* LCD controller */
+  struct s3c24xx_lcd_state_s *lcd;
+
+  /* NAND controller, and chip attached */
+  uint32_t nand_reg[5];
+  struct nand_flash_s *nand_chip;
+} S3CState;
+
+/* Internal functions for s3c24xx implementation */
+void s3c24xx_memc_init(S3CState *soc);
+qemu_irq *s3c24xx_irq_init(S3CState *soc);
+void s3c24xx_gpio_init(S3CState *soc);
+void s3c24xx_clkcon_init(S3CState *soc);
+void s3c24xx_timers_init(S3CState *soc);
+void s3c24xx_iic_init(S3CState *soc);
+i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s);
+void s3c24xx_rtc_init(S3CState *soc);
+void s3c24xx_lcd_init(S3CState *soc);
+void s3c24xx_nand_init(S3CState *soc);
+void s3c24xx_serial_init(S3CState *soc, int port);
+
+/* How to attach a NAND device to the s3c2410x */
+void s3c24xx_nand_attach(S3CState *soc, struct nand_flash_s *nand_chip);
+
+#ifdef DEBUG_S3C24XX_INLINE
+#define S3C24XX_DBF_STREAM stdout
+#else
+#define S3C24XX_DBF_STREAM stderr
+#endif
+#if defined(DEBUG_S3C24XX)
+#define S3C24XX_DBF(X...) fprintf(S3C24XX_DBF_STREAM,"QEMU:S3C24XX:" X); fflush(S3C24XX_DBF_STREAM)
+#else
+#define S3C24XX_DBF(X...) if(0) (fprintf)(S3C24XX_DBF_STREAM, X)
+#endif
+
+#endif /* S3C24XX_H */
Index: hw/s3c24xx_irq.c
===================================================================
--- hw/s3c24xx_irq.c	(revision 0)
+++ hw/s3c24xx_irq.c	(revision 0)
@@ -0,0 +1,181 @@
+/* hw/s3c24xx_irq.c
+ *
+ * Samsung S3C24XX emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+
+static void
+__s3c24xx_percolate_interrupt(S3CState *soc)
+{
+  /* Take the status of the srcpnd register, percolate it through, raise to CPU if necessary */
+  uint32_t ints = (soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] & 
+                   ~soc->irq_reg[CPU_S3C2410X_IRQ_INTMSK]);
+  int fsb = ffs(ints);
+  
+  /* TODO: Priority encoder could go here */
+  if (ints & soc->irq_reg[CPU_S3C2410X_IRQ_INTMOD]) {
+    /* Detected a FIQ */
+    S3C24XX_DBF("IRQ: Setting FIQ on CPU\n");
+    cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_FIQ);
+    return;
+  } else {
+    /* No FIQ here today */
+    cpu_reset_interrupt(soc->cpu_env, CPU_INTERRUPT_FIQ);
+  }
+  /* No FIQ, do we have an IRQ */
+  if (fsb) {
+    if ((soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] == 0) ||
+        (soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] > 1<<(fsb-1))) {
+      /* Current INTPND is lower priority than fsb of ints (or empty) */
+      soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] = 1<<(fsb-1);
+      soc->irq_reg[CPU_S3C2410X_IRQ_OFFSET] = fsb-1;
+    }
+  } else {
+    /* No FSB, thus no IRQ, thus nothing to see yet */
+  }
+
+  if (soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] != 0) {
+    S3C24XX_DBF("IRQ: Setting IRQ on CPU\n");
+    cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_HARD);
+  } else {
+    cpu_reset_interrupt(soc->cpu_env, CPU_INTERRUPT_HARD);
+  }
+}
+
+static void
+s3c24xx_percolate_subsrc_interrupt(S3CState *soc)
+{
+  uint32_t ints;
+  
+  soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= soc->irq_main_level;
+  soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= soc->irq_subsrc_level;
+  
+  ints = (soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] &
+          ~soc->irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]);
+   
+  /* If UART0 has asserted, raise that */
+  S3C24XX_DBF("SUBSRCPND 0x%08x\n", soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND]);
+  S3C24XX_DBF("INTSUBMSK 0x%08x\n", soc->irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]);
+  S3C24XX_DBF(" => Pending Subsource interrupts: %08x\n", ints);
+  if( ints & 0x7 ) {
+    S3C24XX_DBF("IRQ: Percolating UART0 subsource\n");
+    soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<28);
+  }
+  /* Ditto UART1 */
+  if( ints & 0x7<<3 ) soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<23);
+  /* Ditto UART2 */
+  if( ints & 0x7<<6 ) soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<15);
+  /* And percolate it through */
+  __s3c24xx_percolate_interrupt(soc);
+}
+
+static void
+s3c24xx_irq_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 7;
+  S3C24XX_DBF("Write IRQ[%02x] = %08x\n",addr<<2, value);
+  if (addr == CPU_S3C2410X_IRQ_SRCPND ||
+      addr == CPU_S3C2410X_IRQ_INTPND ||
+      addr == CPU_S3C2410X_IRQ_SUBSRCPND) {
+    soc->irq_reg[addr] &= ~value;
+  } else {
+    soc->irq_reg[addr] = value;
+  }
+
+  /* Start at the subsrc irqs and percolate from there */
+  s3c24xx_percolate_subsrc_interrupt(soc);
+}
+
+static uint32_t
+s3c24xx_irq_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x7;
+  S3C24XX_DBF("Read IRQ[%02x] => 0x%08x\n",addr<<2, soc->irq_reg[addr]);
+  return soc->irq_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c24xx_irq_read[] = {
+  &s3c24xx_irq_read_f,
+  &s3c24xx_irq_read_f,
+  &s3c24xx_irq_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_irq_write[] = {
+  &s3c24xx_irq_write_f,
+  &s3c24xx_irq_write_f,
+  &s3c24xx_irq_write_f,
+};
+
+static void
+s3c24xx_irq_set_interrupt_level(S3CState *soc, int irq_num, int level, int set_level)
+{
+  S3C24XX_DBF("IRQ: Set level for %d to %d\n", irq_num, level);
+  if( level ) {
+    if (set_level) soc->irq_main_level |= 1<<irq_num;
+    soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= 1<<irq_num;
+  } else {
+    soc->irq_main_level &= ~(1<<irq_num);
+    soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] &= ~(1<<irq_num);
+  }
+  s3c24xx_percolate_subsrc_interrupt(soc);
+}
+
+static void
+s3c24xx_irq_set_subsrc_interrupt_level(S3CState *soc, int irq_num, int level, int set_level)
+{
+  S3C24XX_DBF("IRQ: Set subsrc level for %d to %d\n", irq_num, level);
+  if( level ) {
+    if (set_level) soc->irq_subsrc_level |= 1<<irq_num;
+    soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= 1<<irq_num;
+  } else {
+    soc->irq_subsrc_level &= ~(1<<irq_num);
+    soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] &= ~(1<<irq_num);
+  }
+  s3c24xx_percolate_subsrc_interrupt(soc);
+}
+
+static void
+s3c24xx_irq_handler(void *opaque, int _n, int level)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int irq_num = _n % 32;
+  int is_subsrc = (_n & 32)?1:0;
+  int is_level = (_n & 64)?1:0;
+  S3C24XX_DBF("Setting %sIRQ[%d] = %d%s\n", (is_subsrc?"SUB ":""), irq_num, level, (is_level?" (level)":""));
+  if (is_subsrc == 0)
+    s3c24xx_irq_set_interrupt_level(soc, irq_num, level, is_level);
+  else
+    s3c24xx_irq_set_subsrc_interrupt_level(soc, irq_num, level, is_level);
+}
+
+qemu_irq *
+s3c24xx_irq_init(S3CState *soc)
+{
+  /* Samsung S3C2410X IRQ registration. */
+  int tag = cpu_register_io_memory(0, s3c24xx_irq_read, s3c24xx_irq_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_IRQ_BASE, 8*4, tag);
+#define IR(X) soc->irq_reg[X]
+  IR(CPU_S3C2410X_IRQ_SRCPND) = 0x00;
+  IR(CPU_S3C2410X_IRQ_INTMOD) = 0x00;
+  IR(CPU_S3C2410X_IRQ_INTMSK) = 0xFFFFFFFF;
+  IR(CPU_S3C2410X_IRQ_PRIORITY) = 0x7F; /* Not that we use it */
+  IR(CPU_S3C2410X_IRQ_INTPND) = 0x00;
+  IR(CPU_S3C2410X_IRQ_OFFSET) = 0x00;
+  IR(CPU_S3C2410X_IRQ_SUBSRCPND) = 0x00;
+  IR(CPU_S3C2410X_IRQ_INTSUBMSK) = 0x7FF;
+#undef IR
+  /* Allocate the interrupts and return them. All 64 potential ones.
+   * We return them doubled up because the latter half are level where
+   * the former half are edge.
+   */
+  return qemu_allocate_irqs(s3c24xx_irq_handler, soc, 128);
+}
Index: hw/s3c24xx_clkcon.c
===================================================================
--- hw/s3c24xx_clkcon.c	(revision 0)
+++ hw/s3c24xx_clkcon.c	(revision 0)
@@ -0,0 +1,73 @@
+/* hw/s3c24xx_clkcon.c
+ *
+ * Samsung S3C24XX Clock control emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+
+static void
+s3c24xx_clkcon_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x1F) >> 2;
+  int idle_rising_edge = 0;
+  if (addr < 0 || addr > 5) addr = 5;
+
+  S3C24XX_DBF("Write CLKCON[%02x] = %08x\n", (unsigned int)addr_ & 0xFF, value);
+
+  if( addr == CPU_S3C2410X_REG_CLKCON ) {
+    if( !(soc->clkcon_reg[addr] & CPU_S3C2410X_REG_CLKCON_IDLE) &&
+        (value & CPU_S3C2410X_REG_CLKCON_IDLE) ) idle_rising_edge = 1;
+  }
+  soc->clkcon_reg[addr] = value;
+  if( idle_rising_edge ) {
+    S3C24XX_DBF("CLKCON: Idling CPU\n");
+    cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_HALT);
+  }
+}
+
+static uint32_t
+s3c24xx_clkcon_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x1F) >> 2;
+  if (addr < 0 || addr > 5) addr = 5;
+  S3C24XX_DBF("Read CLKCON[%d]\n", addr);
+  return soc->clkcon_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c24xx_clkcon_read[] = {
+  &s3c24xx_clkcon_read_f,
+  &s3c24xx_clkcon_read_f,
+  &s3c24xx_clkcon_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_clkcon_write[] = {
+  &s3c24xx_clkcon_write_f,
+  &s3c24xx_clkcon_write_f,
+  &s3c24xx_clkcon_write_f,
+};
+
+
+void
+s3c24xx_clkcon_init(S3CState *soc)
+{
+  int tag;
+
+  tag = cpu_register_io_memory(0, s3c24xx_clkcon_read, s3c24xx_clkcon_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_CLKCON, 6*4, tag);
+  
+#define CR(X) soc->clkcon_reg[X]
+  CR(0) = 0x00FFFFFF;
+  CR(1) = 0x0005C080;
+  CR(2) = 0x00028080;
+  CR(3) = 0x0007FFF0;
+  CR(4) = 0x00000004;
+  CR(5) = 0x00000000;
+#undef CR
+}
Index: hw/s3c24xx_nand.c
===================================================================
--- hw/s3c24xx_nand.c	(revision 0)
+++ hw/s3c24xx_nand.c	(revision 0)
@@ -0,0 +1,126 @@
+/* hw/s3c24xx_nand.c
+ *
+ * Samsung S3C24XX NAND emulation
+ *
+ * Copyright 2006, 2008 Ben Dooks, Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+#include "flash.h"
+
+#define NFCONF 0
+#define NFCMD 1
+#define NFADDR 2
+#define NFDATA 3
+#define NFSTAT 4
+#define NFECC 5
+
+#define NFCE ((soc->nand_reg[NFCONF] & 1<<11) != 0)
+
+static void
+s3c24xx_nand_write_f(void *opaque, target_phys_addr_t addr,
+		      uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int reg = (addr & 0x1f) >> 2;
+  S3C24XX_DBF("%s(%d,%d (0x%08x))\n", __func__, reg, value, value);
+  if ((reg != NFCONF) && ((soc->nand_reg[NFCONF] & 1<<15) == 0)) {
+    return; /* Ignore the write, the nand is not enabled */
+  }
+  switch (reg) {
+  case NFCONF:
+    soc->nand_reg[reg] = value;
+    if (soc->nand_chip != NULL)
+      nand_setpins(soc->nand_chip, 0, 0, NFCE, 1, 0);
+    S3C24XX_DBF("NFCE = %d\n", NFCE);
+    break;
+  case NFCMD:
+    soc->nand_reg[reg] = value;
+    if (soc->nand_chip != NULL) {
+      nand_setpins(soc->nand_chip, 1, 0, NFCE, 1, 0);
+      nand_setio(soc->nand_chip, value);
+    }
+    break;
+  case NFADDR:
+    soc->nand_reg[reg] = value;
+    if (soc->nand_chip != NULL) {
+      nand_setpins(soc->nand_chip, 0, 1, NFCE, 1, 0);
+      nand_setio(soc->nand_chip, value);
+    }
+    break;
+  case NFDATA:
+    soc->nand_reg[reg] = value;
+    if (soc->nand_chip != NULL) {
+      nand_setpins(soc->nand_chip, 0, 0, NFCE, 1, 0);
+      nand_setio(soc->nand_chip, value);
+    }
+    break;
+  default:
+    /* Do nothing because the other registers are read only */
+    break;
+  }
+}
+
+static uint32_t
+s3c24xx_nand_read_f(void *opaque, target_phys_addr_t addr)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int reg = (addr & 0x1f) >> 2;
+  uint32_t ret = soc->nand_reg[reg];
+  switch (reg) {
+  case NFDATA:
+    if (soc->nand_chip != NULL) {
+      nand_setpins(soc->nand_chip, 0, 0, NFCE, 1, 0);
+      ret = soc->nand_reg[reg] = nand_getio(soc->nand_chip);
+    } else {
+      ret = soc->nand_reg[ret] = 0;
+    }
+    break;
+  case NFSTAT:
+    if (soc->nand_chip != NULL) {
+      nand_getpins(soc->nand_chip, &ret);
+      soc->nand_reg[reg] = ret;
+    } else {
+      ret = soc->nand_reg[ret] = 0;
+    }
+  default:
+    /* The rest read-back what was written to them */
+    break;
+  }
+  S3C24XX_DBF("%s(%d) = %d (0x%08x))\n", __func__, reg, ret, ret);
+  return ret;
+}
+
+static CPUReadMemoryFunc *s3c24xx_nand_read[] = {
+  &s3c24xx_nand_read_f,
+  &s3c24xx_nand_read_f,
+  &s3c24xx_nand_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_nand_write[] = {
+  &s3c24xx_nand_write_f,
+  &s3c24xx_nand_write_f,
+  &s3c24xx_nand_write_f,
+};
+
+void
+s3c24xx_nand_init(S3CState *soc)
+{
+  int tag = cpu_register_io_memory(0, s3c24xx_nand_read, s3c24xx_nand_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_NAND_BASE, 0x40, tag);
+  memset(soc->nand_reg, 0, sizeof(uint32_t) * 5);
+}
+
+void
+s3c24xx_nand_attach(S3CState *soc, struct nand_flash_s *nand_chip)
+{
+  if (soc->nand_chip != NULL) {
+    /* Detach current nand device */
+    /* no cmd, no addr, not enabled, write protected, no 'gnd' */
+    nand_setpins(soc->nand_chip, 0, 0, 1, 0, 0); 
+  }
+  soc->nand_chip = nand_chip;
+}
Index: hw/s3c24xx_gpio.c
===================================================================
--- hw/s3c24xx_gpio.c	(revision 0)
+++ hw/s3c24xx_gpio.c	(revision 0)
@@ -0,0 +1,161 @@
+/* hw/s3c24xx_gpio.c
+ *
+ * Samsung S3C24XX GPIO emulation (mostly for E-INT)
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+#include "hw/irq.h"
+
+#define EINT_MASK (0xA4)
+#define EINT_PEND (0xA8)
+#define GPR(P) soc->gpio_reg[P>>2]
+
+static void
+s3c24xx_gpio_propogate_eint(S3CState *soc)
+{
+  uint32_t ints, i;
+  S3C24XX_DBF("EINT: Propogating to IRQ\n");
+  ints = GPR(EINT_PEND) & ~GPR(EINT_MASK);
+  /* EINT0 - EINT3 are INT0 - INT3 */
+  for(i=0; i < 4; ++i)
+    qemu_set_irq(soc->irqs[i], (ints&(1<<i))?1:0);
+  /* EINT4 - EINT7 are INT4 */
+  qemu_set_irq(soc->irqs[4], (ints&0xf0)?1:0);
+  /* EINT8 - EINT23 are INT5 */
+  qemu_set_irq(soc->irqs[5], (ints&0x00ffff00)?1:0);
+}
+
+static uint32_t
+gpio_con_to_mask(uint32_t con)
+{
+  uint32_t mask = 0x0;
+  int bit;
+
+  for (bit = 0; bit < 16; bit++) {
+    if (((con >> (bit*2)) & 0x3) == 0x01)
+      mask |= 1 << bit;
+  }
+
+  S3C24XX_DBF("Con %08x => mask %08x\n", con, mask);
+  return mask;
+}
+
+static void
+s3c24xx_gpio_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x3f;
+  if (addr < 0 || addr > 47) addr = 47;
+
+  if (addr == (EINT_MASK>>2)) value &= ~0xf; /* cannot mask EINT0-EINT3 */
+  S3C24XX_DBF("Write GPIO[%02x] = %08x\n",addr<<2, value);
+  if (addr == (EINT_PEND>>2))
+    soc->gpio_reg[addr] &= ~value;
+  else {
+    if (addr < (0x80/4) && (addr_ & 0xf) == 0x04) {
+      uint32_t mask = gpio_con_to_mask(soc->gpio_reg[addr-1]);
+
+      value &= mask;
+
+      soc->gpio_reg[addr] &= ~mask;
+      soc->gpio_reg[addr] |= value;
+    } else
+      soc->gpio_reg[addr] = value;
+  }
+
+  if ((addr == (EINT_MASK)>>2) || (addr == (EINT_PEND)>>2)) {
+    /* A write to the EINT regs leads us to determine the interrupts to propagate */
+    s3c24xx_gpio_propogate_eint(soc);
+  }
+}
+
+static uint32_t
+s3c24xx_gpio_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x3f;
+  /* TODO: Move this ident to something in the s3cstate struct */
+  if (addr_ == 0x560000b0) 
+    return CPU_S3C2410X_IDENT_S3C2410A;
+  if (addr < 0 || addr > 47) addr = 47;
+  /* If IIC pins are wired to GPE, and GPE is on input mode, pretend the IIC is pulled high */
+  if (addr == 0x44>>2) {
+    /* GPEDAT read. */
+    uint32_t ret = soc->gpio_reg[addr];
+    if ((soc->gpio_reg[15] & 3<<28) == 0) ret |= 1 << 14;
+    if ((soc->gpio_reg[15] & 3<<30) == 0) ret |= 1 << 15;
+    S3C24XX_DBF("GPIO read of GPE, returning 0x%08x\n", ret);
+    return ret;
+  }
+  S3C24XX_DBF("Read GPIO[%02x] => 0x%08x\n",addr<<2, soc->gpio_reg[addr]);
+  return soc->gpio_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c24xx_gpio_read[] = {
+  &s3c24xx_gpio_read_f,
+  &s3c24xx_gpio_read_f,
+  &s3c24xx_gpio_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_gpio_write[] = {
+  &s3c24xx_gpio_write_f,
+  &s3c24xx_gpio_write_f,
+  &s3c24xx_gpio_write_f,
+};
+
+static void
+s3c24xx_gpio_irq_handler(void *opaque, int n, int level)
+{
+  S3CState *soc = (S3CState *)opaque;
+  if (level)
+    GPR(EINT_PEND) |= (1<<n);
+  s3c24xx_gpio_propogate_eint(soc);
+}
+
+void
+s3c24xx_gpio_init(S3CState *soc)
+{
+  /* Samsung S3C24XX GPIO
+   *
+   * The only really magic thing we do currently is the ID register and IRQs
+   */
+  int tag = cpu_register_io_memory(0, s3c24xx_gpio_read, s3c24xx_gpio_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_GPIO_BASE, 47*4, tag);
+  GPR(0x00) = 0x7fffff;
+  GPR(0x10) = 0;
+  GPR(0x18) = 0;
+  GPR(0x20) = 0;
+  GPR(0x28) = 0;
+  GPR(0x30) = 0;
+  GPR(0x34) = 0xfefc;		/* This happens to be the default in the h1940 */
+  GPR(0x38) = 0xf000;
+  GPR(0x40) = 0;
+  GPR(0x48) = 0;
+  GPR(0x50) = 0;
+  GPR(0x58) = 0;
+  GPR(0x60) = 0;
+  GPR(0x68) = 0xf800;
+  GPR(0x70) = 0;
+  GPR(0x78) = 0;
+  GPR(0x80) = 0x10330;
+  GPR(0x84) = 0;
+  GPR(0x88) = 0;
+  GPR(0x8C) = 0;
+  GPR(0x90) = 0;
+  GPR(0x9C) = 0;
+  GPR(0xA0) = 0;
+  GPR(0xA4) = 0xfffff0;
+  GPR(0xA8) = 0;
+  GPR(0xB0) = CPU_S3C2410X_IDENT_S3C2410X;
+  GPR(0xB4) = 1;
+  GPR(0xB8) = 0;
+  GPR(0xBC) = 0;
+  /* EINTs 0-23 -- Only 24, not 48 because EINTs are not level?*/
+  soc->eirqs = qemu_allocate_irqs(s3c24xx_gpio_irq_handler, soc, 24);
+}
Index: hw/simtecbast.c
===================================================================
--- hw/simtecbast.c	(revision 0)
+++ hw/simtecbast.c	(revision 0)
@@ -0,0 +1,255 @@
+/* hw/simtecbast.c
+ *
+ * Simple system emulation for the Simtec Electronics BAST
+ *
+ * Copyright 2006, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#include "s3c2410x.h"
+#include "assert.h"
+#include "simtechw.h"
+#include "arm-misc.h"
+#include "boards.h"
+#include "net.h"
+#include "devices.h"
+#include "flash.h"
+#include "i2c.h"
+
+#define BIOS_FILENAME "s3c2410x-able.bin"
+
+typedef struct {
+    S3CState *soc;
+    unsigned char cpld_ctrl2;
+    struct nand_flash_s *nand[4];
+} STCBState;
+
+/* Bytes in a Kilobyte */
+#define KILO 1024
+/* Bytes in a megabyte */
+#define MEGA 1024 * KILO
+/* Bytes */
+#define BYTE 1
+/* Bits in a byte */
+#define BIT 8
+
+/* Useful defines */
+#define SIMTEC_BAST_NOR_BASE CPU_S3C2410X_CS0
+#define SIMTEC_BAST_NOR_SIZE 16 * MEGA / BIT
+#define SIMTEC_BAST_BOARD_ID 331
+
+#define BAST_IDE_PRI_SLOW    (CPU_S3C2410X_CS3 | 0x2000000)
+#define BAST_IDE_SEC_SLOW    (CPU_S3C2410X_CS3 | 0x3000000)
+#define BAST_IDE_PRI_FAST    (CPU_S3C2410X_CS5 | 0x2000000)
+#define BAST_IDE_SEC_FAST    (CPU_S3C2410X_CS5 | 0x3000000)
+
+#define BAST_IDE_PRI_SLOW_BYTE    (CPU_S3C2410X_CS2 | 0x2000000)
+#define BAST_IDE_SEC_SLOW_BYTE    (CPU_S3C2410X_CS2 | 0x3000000)
+#define BAST_IDE_PRI_FAST_BYTE    (CPU_S3C2410X_CS4 | 0x2000000)
+#define BAST_IDE_SEC_FAST_BYTE    (CPU_S3C2410X_CS4 | 0x3000000)
+
+#define SIMTECBAST_CS1_CPLD_BASE ((target_phys_addr_t)(CPU_S3C2410X_CS1 | (0xc << 23)))
+#define SIMTECBAST_CS5_CPLD_BASE ((target_phys_addr_t)(CPU_S3C2410X_CS5 | (0xc << 23)))
+#define SIMTECBAST_CPLD_SIZE (4<<23)
+
+static uint32_t cpld_read(void *opaque, target_phys_addr_t address)
+{
+    STCBState *stcb = (STCBState *)opaque;
+    int reg = (address >> 23) & 0xf;
+    if (reg == 0xc)
+        return stcb->cpld_ctrl2;
+    return 0;
+}
+
+static void cpld_write(void *opaque, target_phys_addr_t address,
+                       uint32_t value)
+{
+    STCBState *stcb = (STCBState *)opaque;
+    int reg = (address >> 23) & 0xf;
+    if (reg == 0xc) {
+        stcb->cpld_ctrl2 = value;
+        s3c24xx_nand_attach(stcb->soc, stcb->nand[stcb->cpld_ctrl2 & 3]);
+    }
+}
+
+static CPUReadMemoryFunc *cpld_readfn[] = {
+    cpld_read,
+    cpld_read,
+    cpld_read
+};
+
+static CPUWriteMemoryFunc *cpld_writefn[] = {
+    cpld_write,
+    cpld_write,
+    cpld_write
+};
+
+static void stcb_cpld_register(STCBState *stcb)
+{
+    int tag = cpu_register_io_memory(0, cpld_readfn, cpld_writefn, stcb);
+    cpu_register_physical_memory(SIMTECBAST_CS1_CPLD_BASE, SIMTECBAST_CPLD_SIZE, tag);
+    cpu_register_physical_memory(SIMTECBAST_CS5_CPLD_BASE, SIMTECBAST_CPLD_SIZE, tag);
+    stcb->cpld_ctrl2 = 0;
+}
+
+static void stcb_register_ide(S3CState *soc)
+{
+    int ide0_mem = -1;
+    int ide1_mem = -1;
+    int index;
+    BlockDriverState *hd0, *hd1;
+  
+    if (drive_get_max_bus(IF_IDE) >= 2) {
+        fprintf(stderr, "qemu: too many IDE busses\n");
+        exit(1);
+    }
+  
+    index = drive_get_index(IF_IDE, 0, 0);
+    if (index != -1)
+        hd0 = drives_table[index].bdrv;
+    else
+        hd0 = NULL;
+  
+    index = drive_get_index(IF_IDE, 0, 1);
+    if (index != -1)
+        hd1 = drives_table[index].bdrv;
+    else
+        hd1 = NULL;
+  
+    ide0_mem = stcb_ide_init(hd0, hd1, soc->eirqs[16]);
+  
+    index = drive_get_index(IF_IDE, 1, 0);
+    if (index != -1)
+        hd0 = drives_table[index].bdrv;
+    else
+        hd0 = NULL;
+  
+    index = drive_get_index(IF_IDE, 1, 1);
+    if (index != -1)
+        hd1 = drives_table[index].bdrv;
+    else
+        hd1 = NULL;
+  
+    ide1_mem = stcb_ide_init(hd0, hd1, soc->eirqs[17]);
+  
+    cpu_register_physical_memory(BAST_IDE_PRI_SLOW, 0x1000000, ide0_mem);
+    cpu_register_physical_memory(BAST_IDE_PRI_FAST, 0x1000000, ide0_mem);
+  
+    cpu_register_physical_memory(BAST_IDE_SEC_SLOW, 0x1000000, ide1_mem);
+    cpu_register_physical_memory(BAST_IDE_SEC_FAST, 0x1000000, ide1_mem);
+
+    cpu_register_physical_memory(BAST_IDE_PRI_SLOW_BYTE, 0x1000000, ide0_mem);
+    cpu_register_physical_memory(BAST_IDE_PRI_FAST_BYTE, 0x1000000, ide0_mem);
+  
+    cpu_register_physical_memory(BAST_IDE_SEC_SLOW_BYTE, 0x1000000, ide1_mem);
+    cpu_register_physical_memory(BAST_IDE_SEC_FAST_BYTE, 0x1000000, ide1_mem);
+}
+
+static void stcb_i2c_setup(STCBState *stcb)
+{
+    i2c_bus *bus = s3c24xx_i2c_bus(stcb->soc->iic);
+    uint8_t *eeprom_buf = qemu_mallocz(256);
+    smbus_eeprom_device_init(bus, 0x50, eeprom_buf);
+    ch7xxx_init(bus, 0x75);
+    stcpmu_init(bus, 0x6B);
+}
+
+static struct arm_boot_info simtecbast_binfo = {
+    .board_id = SIMTEC_BAST_BOARD_ID,
+    .ram_size = 0x10000000,
+};
+
+static void stcb_init(ram_addr_t _ram_size, 
+                      int vga_ram_size, 
+                      const char *boot_device,
+                      const char *kernel_filename, const char *kernel_cmdline,
+                      const char *initrd_filename, const char *cpu_model)
+{
+    STCBState *stcb;
+    int bios_offset;
+    char buf[1024]; /* URGH */
+    int ret, index;
+    NICInfo* nd;
+
+    if (_ram_size > (256 * MEGA * BYTE)) _ram_size = 256 * MEGA * BYTE;
+    ram_size = _ram_size;
+
+    bios_offset = ram_size;
+  
+    stcb = (STCBState *)(malloc(sizeof(STCBState)));
+  
+    stcb->soc = s3c2410x_init(ram_size);
+
+    simtecbast_binfo.ram_size = ram_size;
+    simtecbast_binfo.kernel_filename = kernel_filename;
+    simtecbast_binfo.kernel_cmdline = kernel_cmdline;
+    simtecbast_binfo.initrd_filename = initrd_filename;
+    simtecbast_binfo.nb_cpus = 1;
+
+    /* fprintf(stderr,"%p, %x\n", phys_ram_base, (unsigned int)phys_ram_size); */
+    if (kernel_filename == NULL) {
+        simtecbast_binfo.loader_start = bios_offset;
+        /* No kernel given so try and aquire a bootloader */
+
+        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+        ret = load_image(buf, phys_ram_base + bios_offset);
+        if (ret <= 0) {
+            perror("qemu");
+            fprintf(stderr, "qemu: warning, could not load BAST BIOS from %s\n", buf);
+            exit (1);
+        } else {
+            fprintf(stdout, "qemu: info, loaded BAST BIOS %d bytes from %s\n", ret, buf);
+        }
+    } else {
+        simtecbast_binfo.loader_start = CPU_S3C2410X_RAM;
+        
+        arm_load_kernel(stcb->soc->cpu_env, &simtecbast_binfo);
+
+        /* Construct the smallest bootloader(ish) in the world */
+        stl_raw(phys_ram_base + bios_offset, 0xE59FF000); /* ldr pc, [pc, #0] (loads from +8) */
+        stl_raw(phys_ram_base + bios_offset + 4, 0x00000000);
+        stl_raw(phys_ram_base + bios_offset + 8, CPU_S3C2410X_RAM);
+        stl_raw(phys_ram_base + bios_offset + 12, 0xE3A0F000);
+    }
+  
+    /* Register the NOR flash ROM */
+    cpu_register_physical_memory(SIMTEC_BAST_NOR_BASE, SIMTEC_BAST_NOR_SIZE,
+                                 bios_offset | IO_MEM_ROM);
+
+    stcb_register_ide(stcb->soc);
+
+    nd = &nd_table[0];
+    if (!nd->model)
+        nd->model = "dm9000";
+    if (strcmp(nd->model, "dm9000") == 0) {
+        dm9000_init(nd, 0x2D000000, 0x00, 0x40, stcb->soc->eirqs[10]);
+    }
+  
+    /* Initialise the BAST CPLD */
+    stcb_cpld_register(stcb);
+  
+    /* attach i2c devices */
+    stcb_i2c_setup(stcb);
+
+    /* Attach some NAND devices */
+    stcb->nand[0] = NULL;
+    stcb->nand[1] = NULL;
+    index = drive_get_index(IF_MTD, 0, 0);
+    if (index == -1)
+        stcb->nand[2] = NULL;
+    else
+        stcb->nand[2] = nand_init(0xEC, 0x79); /* 128MiB small-page */
+  
+    /* And we're good to go */
+}
+
+
+QEMUMachine simtecbast_machine = {
+  .name = "simtecbast",
+  .desc = "Simtec Electronics BAST (S3C2410X, ARM920T)",
+  .init = stcb_init,
+  .max_cpus = 1,
+  .ram_require = SIMTEC_BAST_NOR_SIZE, 
+};
Index: hw/s3c24xx_serial.c
===================================================================
--- hw/s3c24xx_serial.c	(revision 0)
+++ hw/s3c24xx_serial.c	(revision 0)
@@ -0,0 +1,219 @@
+/* hw/s3c24xx_serial.c
+ *
+ * Samsung S3C24XX Serial block
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+
+typedef struct {
+    uint32_t ulcon, ucon, ufcon, umcon, ubrdiv;
+    unsigned char rx_byte;
+    /* Byte is available to be read */
+    unsigned int rx_available : 1;
+    CharDriverState *chr;
+    int port;
+    qemu_irq tx_irq;
+    qemu_irq rx_irq;
+    qemu_irq tx_level;
+    qemu_irq rx_level;
+} s3c24xx_serial_dev;
+
+static void 
+s3c24xx_serial_write_f(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    s3c24xx_serial_dev *s = opaque;
+    int reg = addr & 0x3f;
+    if (reg != CPU_S3C2410X_SERIAL_UTXH)
+        S3C24XX_DBF("Serial[%d] Write of 0x%08x to 0x%08x (reg %d)\n", s->port, value, (unsigned int)addr, reg);
+    switch(reg) {
+    case CPU_S3C2410X_SERIAL_ULCON:
+        s->ulcon = value;
+        break;
+    case CPU_S3C2410X_SERIAL_UCON:
+        s->ucon = value;
+        if( s->ucon & 1<<9 ) {
+            S3C24XX_DBF("Serial[%d] setting TX level interrupt due to ucon write\n", s->port);
+            qemu_set_irq(s->tx_level, 1);
+        } else {
+            S3C24XX_DBF("Serial[%d] clearing TX level interrupt due to ucon write\n", s->port);
+            qemu_set_irq(s->tx_level, 0);
+        }
+        if( !(s->ucon & 1<<8) ) {
+            S3C24XX_DBF("Serial[%d] clearing RX level interrupt (if any) due to ucon write\n", s->port);
+            qemu_set_irq(s->rx_level, 0);
+        }
+        break;
+    case CPU_S3C2410X_SERIAL_UFCON:
+        s->ufcon = (value & ~6);
+        break;
+    case CPU_S3C2410X_SERIAL_UMCON:
+        s->umcon = value;
+        break;
+    case CPU_S3C2410X_SERIAL_UTRSTAT:
+        break;
+    case CPU_S3C2410X_SERIAL_UERSTAT:
+        break;
+    case CPU_S3C2410X_SERIAL_UFSTAT:
+        break;
+    case CPU_S3C2410X_SERIAL_UMSTAT:
+        break;
+    case CPU_S3C2410X_SERIAL_UTXH: {
+        unsigned char ch = value & 0xff;
+        if (s->chr && ((s->ucon & 1<<5)==0))
+            qemu_chr_write(s->chr, &ch, 1);
+        else {
+            s->rx_byte = ch;
+            s->rx_available = 1;
+            if( s->ucon & 1<<8 ) {
+                S3C24XX_DBF("Serial[%d] Setting RX level interrupt due to loopback write\n", s->port);
+                qemu_set_irq(s->rx_level, 1);
+            } else {
+                S3C24XX_DBF("Serial[%d] Pulsing RX interrupt due to loopback write\n", s->port);
+                qemu_set_irq(s->rx_irq, 1);
+            }
+        }
+        if( s->ucon & 1<<9 ) {
+            S3C24XX_DBF("Serial[%d] Setting TX level interrupt due to byte write\n", s->port);
+            qemu_set_irq(s->tx_level, 1);
+        } else {
+            S3C24XX_DBF("Serial[%d] Pulsing TX interrupt due to byte write\n", s->port);
+            qemu_set_irq(s->tx_irq, 1);
+        }
+        break;
+    }
+    case CPU_S3C2410X_SERIAL_URXH:
+        break;
+    case CPU_S3C2410X_SERIAL_UBRDIV:
+        s->ubrdiv = value;
+        break;
+    default:
+        break;
+    };
+}
+
+static uint32_t
+s3c24xx_serial_read_f(void *opaque, target_phys_addr_t addr)
+{
+    s3c24xx_serial_dev *s = opaque;
+    int reg = addr & 0x3f;
+    if (reg != CPU_S3C2410X_SERIAL_URXH && 
+        reg != CPU_S3C2410X_SERIAL_UFCON &&
+        reg != CPU_S3C2410X_SERIAL_UFSTAT)
+        S3C24XX_DBF("Serial[%d] Read of 0x%08x (reg %d)\n", s->port, (unsigned int)addr, reg);
+    switch(reg) {
+    case CPU_S3C2410X_SERIAL_ULCON:
+        return s->ulcon;
+    case CPU_S3C2410X_SERIAL_UCON:
+        return s->ucon;
+    case CPU_S3C2410X_SERIAL_UFCON:
+        return s->ufcon & ~0x8; /* bit 3 is reserved, must be zero */
+    case CPU_S3C2410X_SERIAL_UMCON:
+        return s->umcon & 0x11; /* Rest are reserved, must be zero */
+    case CPU_S3C2410X_SERIAL_UTRSTAT:
+        return 6 | s->rx_available; /* TX always clear, RX when available */
+    case CPU_S3C2410X_SERIAL_UERSTAT:
+        return 0; /* Later, break detect comes in here */
+    case CPU_S3C2410X_SERIAL_UFSTAT:
+        return s->rx_available; /* TXFIFO, always empty, RXFIFO 0 or 1 bytes */
+    case CPU_S3C2410X_SERIAL_UMSTAT:
+        return 0;
+    case CPU_S3C2410X_SERIAL_UTXH:
+        return 0;
+    case CPU_S3C2410X_SERIAL_URXH:
+        s->rx_available = 0;
+        if( s->ucon & 1<<8 ) {
+            S3C24XX_DBF("Serial[%d] clearing RX level interrupt due to byte read\n", s->port);
+            qemu_set_irq(s->rx_level, 0);
+        }
+        return s->rx_byte;
+    case CPU_S3C2410X_SERIAL_UBRDIV:
+        return s->ubrdiv;
+    default:
+        return 0;
+    };
+}
+
+static CPUReadMemoryFunc *s3c24xx_serial_read[] = {
+    &s3c24xx_serial_read_f,
+    &s3c24xx_serial_read_f,
+    &s3c24xx_serial_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_serial_write[] = {
+    &s3c24xx_serial_write_f,
+    &s3c24xx_serial_write_f,
+    &s3c24xx_serial_write_f,
+};
+
+
+static void s3c24xx_serial_event(void *opaque, int event)
+{
+    /* Disabled currently. */
+    /*
+      s3c24xx_serial_dev *s = opaque;
+      if (event == CHR_EVENT_BREAK)
+      serial_receive_break(s);
+    */
+}
+
+static int 
+s3c24xx_serial_can_receive(void *opaque)
+{
+    s3c24xx_serial_dev *s = opaque;
+    /* If there's no byte to be read, we can receive a new one */
+    return !s->rx_available;
+}
+
+static void 
+s3c24xx_serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+    s3c24xx_serial_dev *s = opaque;
+    s->rx_byte = buf[0];
+    s->rx_available = 1;
+    if( s->ucon & 1<<8 ) {
+        S3C24XX_DBF("Serial[%d] setting RX level interrupt due to incoming char %02x\n", s->port, buf[0]);
+        qemu_set_irq(s->rx_level, 1);
+    } else {
+        S3C24XX_DBF("Serial[%d] pulse receive interrupt %d for %02x\n", s->port, 1<<(s->port*3), buf[0]);
+        qemu_set_irq(s->rx_irq, 1); /* Is there something we can do here to ensure it's just a pulse ? */
+    }
+}
+
+void
+s3c24xx_serial_init(S3CState *soc, int port)
+{
+    /* Initialise a serial port at the given port address */
+    s3c24xx_serial_dev *s;
+    int serial_io_magic;
+  
+    s = qemu_mallocz(sizeof(s3c24xx_serial_dev));
+    if (!s) return;
+    s->chr = serial_hds[port];
+    s->ulcon = 0;
+    s->ucon = 0;
+    s->ufcon = 0;
+    s->umcon = 0;
+    s->ubrdiv = 0;
+    s->port = port;
+    s->rx_available = 0;
+    s->tx_irq = soc->irqs[32 + (port * 3) + 1];
+    s->rx_irq = soc->irqs[32 + (port * 3)];
+    s->tx_level = soc->irqs[64 + 32 + (port * 3) + 1];
+    s->rx_level = soc->irqs[64 + 32 + (port * 3)];
+    /* Prepare our MMIO tag */
+    serial_io_magic = cpu_register_io_memory(0, s3c24xx_serial_read, s3c24xx_serial_write, s);
+    /* Register the region with the tag */
+    cpu_register_physical_memory(CPU_S3C2410X_SERIAL_BASE(port), 44, serial_io_magic);
+    if (s->chr) {
+        /* Add ourselves to the character device's IO handlers, if the port is
+         * present
+         */
+        qemu_chr_add_handlers(s->chr, s3c24xx_serial_can_receive,
+                              s3c24xx_serial_receive, s3c24xx_serial_event, s);
+    }
+}
Index: hw/i2c.h
===================================================================
--- hw/i2c.h	(revision 6883)
+++ hw/i2c.h	(working copy)
@@ -87,4 +87,10 @@
 struct i2c_slave *lm8323_init(i2c_bus *bus, qemu_irq nirq);
 void lm832x_key_event(struct i2c_slave *i2c, int key, int state);
 
+/* ch7xxx.c */
+i2c_slave *ch7xxx_init(i2c_bus *bus, int addr);
+
+/* stcpmu.c */
+i2c_slave *stcpmu_init(i2c_bus *bus, int addr);
+
 #endif
Index: hw/s3c24xx_lcd.c
===================================================================
--- hw/s3c24xx_lcd.c	(revision 0)
+++ hw/s3c24xx_lcd.c	(revision 0)
@@ -0,0 +1,587 @@
+/*
+ * Samsung S3C24xx series LCD controller.
+ *
+ * Copyright (c) 2007 OpenMoko, Inc.
+ * Author: Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This code is licenced under the GNU GPL v2.
+ */
+
+#include "s3c2410x.h"
+#include "hw.h"
+#include "console.h"
+
+typedef void (*s3c24xx_drawfn_t)(uint32_t *, uint8_t *, const uint8_t *, int, int);
+
+struct s3c24xx_lcd_state_s {
+    target_phys_addr_t base;
+    void *irq;
+    DisplayState *ds;
+    s3c24xx_drawfn_t *line_fn;
+
+    uint32_t con[5];
+    uint32_t saddr[3];
+    uint32_t r;
+    uint32_t g;
+    uint16_t b;
+    uint32_t dithmode;
+    uint32_t tpal;
+    uint8_t intpnd;
+    uint8_t srcpnd;
+    uint8_t intmsk;
+    uint8_t lpcsel;
+
+    uint16_t raw_pal[0x100];
+
+    int width;
+    int height;
+    int bpp;
+    int enable;
+    int msb;
+    int frm565;
+    void *fb;
+    uint32_t palette[0x100];
+    int invalidate;
+    int invalidatep;
+    int src_width;
+    int dest_width;
+    s3c24xx_drawfn_t fn;
+};
+
+static void s3c24xx_lcd_update(struct s3c24xx_lcd_state_s *s)
+{
+    s->intpnd |= s->srcpnd & ~s->intmsk;
+    qemu_set_irq(s->irq, !!s->intpnd);
+}
+
+void s3c24xx_lcd_reset(struct s3c24xx_lcd_state_s *s)
+{
+    s->enable = 0;
+    s->invalidate = 1;
+    s->invalidatep = 1;
+    s->width = -1;
+    s->height = -1;
+
+    s->con[0] = 0x00000000;
+    s->con[1] = 0x00000000;
+    s->con[2] = 0x00000000;
+    s->con[3] = 0x00000000;
+    s->con[4] = 0x00000000;
+    s->saddr[0] = 0x00000000;
+    s->saddr[1] = 0x00000000;
+    s->saddr[2] = 0x00000000;
+    s->r = 0x00000000;
+    s->g = 0x00000000;
+    s->b = 0x0000;
+    s->dithmode = 0x00000;
+    s->tpal = 0x00000000;
+    s->intpnd = 0;
+    s->srcpnd = 0;
+    s->intmsk = 3;
+    s->lpcsel = 4;
+    s3c24xx_lcd_update(s);
+}
+
+#define S3C24XX_LCDCON1	0x00	/* LCD Control register 1 */
+#define S3C24XX_LCDCON2	0x04	/* LCD Control register 2 */
+#define S3C24XX_LCDCON3	0x08	/* LCD Control register 3 */
+#define S3C24XX_LCDCON4	0x0c	/* LCD Control register 4 */
+#define S3C24XX_LCDCON5	0x10	/* LCD Control register 5 */
+#define S3C24XX_LCDSADDR1 0x14	/* Framebuffer Start Address 1 register */
+#define S3C24XX_LCDSADDR2 0x18	/* Framebuffer Start Address 2 register */
+#define S3C24XX_LCDSADDR3 0x1c	/* Framebuffer Start Address 3 register */
+#define S3C24XX_REDLUT 0x20	/* Red Lookup Table register */
+#define S3C24XX_GREENLUT 0x24	/* Green Lookup Table register */
+#define S3C24XX_BLUELUT	0x28	/* Blue Lookup Table register */
+#define S3C24XX_DITHMODE 0x4c	/* Dithering Mode register */
+#define S3C24XX_TPAL 0x50	/* Temporary Palette register */
+#define S3C24XX_LCDINTPND 0x54	/* LCD Interrupt Pending register */
+#define S3C24XX_LCDSRCPND 0x58	/* LCD Interrupt Source Pending register */
+#define S3C24XX_LCDINTMSK 0x5c	/* LCD Interrupt Mask register */
+#define S3C24XX_LPCSEL 0x60	/* LPC3600 Control register */
+
+#define S3C24XX_PALETTE	0x400	/* Palette IO start offset */
+#define S3C24XX_PALETTEEND 0x7fc	/* Palette IO end offset */
+
+static uint32_t s3c24xx_lcd_read(void *opaque, target_phys_addr_t addr)
+{
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+
+    switch (addr) {
+    case S3C24XX_LCDCON1:
+        return s->con[0];		/* XXX Return random LINECNT? */
+    case S3C24XX_LCDCON2:
+        return s->con[1];
+    case S3C24XX_LCDCON3:
+        return s->con[2];
+    case S3C24XX_LCDCON4:
+        return s->con[3];
+    case S3C24XX_LCDCON5:
+        return s->con[4];		/* XXX Return random STATUS? */
+    case S3C24XX_LCDSADDR1:
+        return s->saddr[0];
+    case S3C24XX_LCDSADDR2:
+        return s->saddr[1];
+    case S3C24XX_LCDSADDR3:
+        return s->saddr[2];
+    case S3C24XX_REDLUT:
+        return s->r;
+    case S3C24XX_GREENLUT:
+        return s->g;
+    case S3C24XX_BLUELUT:
+        return s->b;
+    case S3C24XX_DITHMODE:
+        return s->dithmode;
+    case S3C24XX_TPAL:
+        return s->tpal;
+    case S3C24XX_LCDINTPND:
+        return s->intpnd;
+    case S3C24XX_LCDSRCPND:
+        return s->srcpnd;
+    case S3C24XX_LCDINTMSK:
+        return s->intmsk;
+    case S3C24XX_LPCSEL:
+        return s->lpcsel;
+    case S3C24XX_PALETTE ... S3C24XX_PALETTEEND:
+        /* XXX assuming 16bit access */
+        return s->raw_pal[(addr - S3C24XX_PALETTE) >> 2];
+    default:
+        printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void s3c24xx_lcd_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+
+    switch (addr) {
+    case S3C24XX_LCDCON1:
+        s->con[0] = value & 0x0003ffff;
+        s->enable = value & 1;
+        s->bpp = (value >> 1) & 0xf;
+        s->invalidate = 1;
+        s->invalidatep = 1;
+        break;
+    case S3C24XX_LCDCON2:
+        s->con[1] = value;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_LCDCON3:
+        s->con[2] = value;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_LCDCON4:
+        s->con[3] = value & 0xffff;
+        break;
+    case S3C24XX_LCDCON5:
+        s->con[4] = value & 0x1fff;
+        s->frm565 = (value >> 11) & 1;
+        s->msb = (value >> 12) & 1;
+        s->invalidatep = 1;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_LCDSADDR1:
+        s->saddr[0] = value;
+        s->fb = phys_ram_base +
+                (((s->saddr[0] << 1) & 0x7ffffffe) - CPU_S3C2410X_RAM);
+        s->invalidate = 1;
+        break;
+    case S3C24XX_LCDSADDR2:
+        s->saddr[1] = value;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_LCDSADDR3:
+        s->saddr[2] = value;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_REDLUT:
+        s->r = value;
+        s->invalidatep = 1;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_GREENLUT:
+        s->g = value;
+        s->invalidatep = 1;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_BLUELUT:
+        s->b = value;
+        s->invalidatep = 1;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_DITHMODE:
+        s->dithmode = value;
+        break;
+    case S3C24XX_TPAL:
+        s->tpal = value;
+        s->invalidatep = 1;
+        s->invalidate = 1;
+        break;
+    case S3C24XX_LCDINTPND:
+        s->intpnd = value & 3;
+        break;
+    case S3C24XX_LCDSRCPND:
+        s->srcpnd = value & 3;
+        break;
+    case S3C24XX_LCDINTMSK:
+        s->intmsk = value & 7;
+        s3c24xx_lcd_update(s);
+        break;
+    case S3C24XX_LPCSEL:
+        s->lpcsel = (value & 3) | 4;
+        if (value & 1)
+            printf("%s: attempt to enable LPC3600\n", __FUNCTION__);
+        break;
+    case S3C24XX_PALETTE ... S3C24XX_PALETTEEND:
+        /* XXX assuming 16bit access */
+        s->raw_pal[(addr - S3C24XX_PALETTE) >> 2] = value;
+        break;
+    default:
+        printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *s3c24xx_lcd_readfn[] = {
+    s3c24xx_lcd_read,
+    s3c24xx_lcd_read,
+    s3c24xx_lcd_read,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_lcd_writefn[] = {
+    s3c24xx_lcd_write,
+    s3c24xx_lcd_write,
+    s3c24xx_lcd_write,
+};
+
+static inline void s3c24xx_lcd_resize(struct s3c24xx_lcd_state_s *s)
+{
+    int new_width, new_height;
+    new_height = ((s->con[1] >> 14) & 0x3ff) + 1;
+    new_width = ((s->con[2] >> 8) & 0x7ff) + 1;
+    if (s->width != new_width || s->height != new_height) {
+        s->width = new_width;
+        s->height = new_height;
+        qemu_console_resize(s->ds, s->width, s->height);
+        s->invalidate = 1;
+    }
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
+{
+    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
+{
+    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
+{
+    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
+{
+    return (r << 16) | (g << 8) | b;
+}
+
+static inline
+uint32_t s3c24xx_rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
+{
+    return (r << 16) | (g << 8) | b;
+}
+
+static inline uint32_t s3c24xx_rgb(struct s3c24xx_lcd_state_s *s,
+                unsigned int r, unsigned int g, unsigned b)
+{
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 8:
+        return s3c24xx_rgb_to_pixel32(r << 2, g << 2, b << 2);
+    case 15:
+        return s3c24xx_rgb_to_pixel15(r << 2, g << 2, b << 2);
+    case 16:
+        return s3c24xx_rgb_to_pixel16(r << 2, g << 2, b << 2);
+    case 24:
+        return s3c24xx_rgb_to_pixel24(r << 2, g << 2, b << 2);
+    case 32:
+        return s3c24xx_rgb_to_pixel32(r << 2, g << 2, b << 2);
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+}
+
+static void s3c24xx_lcd_palette_load(struct s3c24xx_lcd_state_s *s)
+{
+    int i, n;
+    switch (s->bpp) {
+    case 0:
+    case 8:
+        n = 2;
+        s->src_width = s->width >> 3;
+        s->fn = s->line_fn[0];
+        break;
+    case 1:
+    case 9:
+        n = 4;
+        s->src_width = s->width >> 2;
+        s->fn = s->line_fn[1];
+        break;
+    case 2:
+    case 10:
+        n = 16;
+        s->src_width = s->width >> 1;
+        s->fn = s->line_fn[2];
+        break;
+    case 3:
+    case 11:
+        n = 256;
+        s->src_width = s->width >> 0;
+        s->fn = s->line_fn[3];
+        break;
+    case 6:
+        s->src_width = (s->width * 3) >> 1;
+        s->fn = s->line_fn[4];
+        return;
+    case 12:
+        s->src_width = s->width << 1;
+        if (s->frm565)
+            s->fn = s->line_fn[5];
+        else
+            s->fn = s->line_fn[6];
+        return;
+    case 13:
+        s->src_width = s->width << 2;
+        s->fn = s->line_fn[7];
+        return;
+    default:
+        return;
+    }
+    if (s->bpp & 8) {
+        for (i = 0; i < n; i ++)
+            if (s->frm565)
+                s->palette[i] = s3c24xx_rgb(s,
+                        (s->raw_pal[i] >> 10) & 0x3e,
+                        (s->raw_pal[i] >> 5) & 0x3f,
+                        (s->raw_pal[i] << 1) & 0x3e);
+            else
+                s->palette[i] = s3c24xx_rgb(s,
+                        ((s->raw_pal[i] >> 10) & 0x3e) | (s->raw_pal[i] & 1),
+                        ((s->raw_pal[i] >> 6) & 0x3e) | (s->raw_pal[i] & 1),
+                        s->raw_pal[i] & 0x3f);
+    } else {
+        for (i = 0; i < n; i ++)
+            if (n < 256)
+                s->palette[i] = s3c24xx_rgb(s,
+                        ((s->r >> (i * 4)) & 0xf) << 2,
+                        ((s->g >> (i * 4)) & 0xf) << 2,
+                        ((s->b >> (i * 4)) & 0xf) << 2);
+            else
+                s->palette[i] = s3c24xx_rgb(s,
+                        ((s->r >> (((i >> 5) & 7) * 4)) & 0xf) << 2,
+                        ((s->g >> (((i >> 2) & 7) * 4)) & 0xf) << 2,
+                        ((s->b >> ((i & 3) * 4)) & 0xf) << 2);
+    }
+}
+
+static void s3c24xx_update_display(void *opaque)
+{
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+    int y, src_width, dest_width, dirty[2], miny, maxy;
+    ram_addr_t x, addr, new_addr, start, end;
+    uint8_t *src, *dest;
+    if (!s->enable || !s->dest_width)
+        return;
+
+    s3c24xx_lcd_resize(s);
+
+    if (s->invalidatep) {
+        s3c24xx_lcd_palette_load(s);
+        s->invalidatep = 0;
+    }
+
+    src = s->fb;
+    src_width = s->src_width;
+
+    dest = ds_get_data(s->ds);
+    dest_width = s->width * s->dest_width;
+
+    addr = (ram_addr_t) (s->fb - (void *) phys_ram_base);
+    start = addr + s->height * src_width;
+    end = addr;
+    dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
+    miny = s->height;
+    maxy = 0;
+    for (y = 0; y < s->height; y ++) {
+        new_addr = addr + src_width;
+        for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
+                        x += TARGET_PAGE_SIZE) {
+            dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
+            dirty[0] |= dirty[1];
+        }
+        if (dirty[0] || s->invalidate) {
+            s->fn(s->palette, dest, src, s->width, s->dest_width);
+            maxy = y;
+            end = new_addr;
+            if (y < miny) {
+                miny = y;
+                start = addr;
+            }
+        }
+        addr = new_addr;
+        dirty[0] = dirty[1];
+        src += src_width;
+        dest += dest_width;
+    }
+
+    s->invalidate = 0;
+    if (end > start)
+        cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+    s->srcpnd |= (1 << 1);			/* INT_FrSyn */
+    s3c24xx_lcd_update(s);
+    dpy_update(s->ds, 0, miny, s->width, maxy);
+}
+
+static void s3c24xx_invalidate_display(void *opaque)
+{
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+    s->invalidate = 1;
+}
+
+static void s3c24xx_screen_dump(void *opaque, const char *filename)
+{
+    /* TODO */
+}
+
+#define BITS 8
+#include "s3c24xx_template.h"
+#define BITS 15
+#include "s3c24xx_template.h"
+#define BITS 16
+#include "s3c24xx_template.h"
+#define BITS 24
+#include "s3c24xx_template.h"
+#define BITS 32
+#include "s3c24xx_template.h"
+
+static void s3c24xx_lcd_save(QEMUFile *f, void *opaque)
+{
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+    int i;
+    for (i = 0; i < 5; i ++)
+        qemu_put_be32s(f, &s->con[i]);
+    for (i = 0; i < 3; i ++)
+        qemu_put_be32s(f, &s->saddr[i]);
+    qemu_put_be32s(f, &s->r);
+    qemu_put_be32s(f, &s->g);
+    qemu_put_be16s(f, &s->b);
+    qemu_put_be32s(f, &s->dithmode);
+    qemu_put_be32s(f, &s->tpal);
+    qemu_put_8s(f, &s->intpnd);
+    qemu_put_8s(f, &s->srcpnd);
+    qemu_put_8s(f, &s->intmsk);
+    qemu_put_8s(f, &s->lpcsel);
+    for (i = 0; i < 0x100; i ++)
+        qemu_put_be16s(f, &s->raw_pal[i]);
+}
+
+static int s3c24xx_lcd_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *) opaque;
+    int i;
+    for (i = 0; i < 5; i ++)
+        qemu_get_be32s(f, &s->con[i]);
+    for (i = 0; i < 3; i ++)
+        qemu_get_be32s(f, &s->saddr[i]);
+    qemu_get_be32s(f, &s->r);
+    qemu_get_be32s(f, &s->g);
+    qemu_get_be16s(f, &s->b);
+    qemu_get_be32s(f, &s->dithmode);
+    qemu_get_be32s(f, &s->tpal);
+    qemu_get_8s(f, &s->intpnd);
+    qemu_get_8s(f, &s->srcpnd);
+    qemu_get_8s(f, &s->intmsk);
+    qemu_get_8s(f, &s->lpcsel);
+
+    s->invalidate = 1;
+    s->invalidatep = 1;
+    s->width = -1;
+    s->height = -1;
+    s->bpp = (s->con[0] >> 1) & 0xf;
+    s->enable = s->con[0] & 1;
+    s->msb = (s->con[4] >> 12) & 1;
+    s->frm565 = (s->con[4] >> 11) & 1;
+    s->fb = phys_ram_base + (((s->saddr[0] << 1) & 0x7ffffffe) - CPU_S3C2410X_RAM);
+
+    for (i = 0; i < 0x100; i ++)
+        qemu_get_be16s(f, &s->raw_pal[i]);
+
+    return 0;
+}
+
+struct s3c24xx_lcd_state_s *_s3c24xx_lcd_init(target_phys_addr_t base,
+                                              qemu_irq irq)
+{
+    int iomemtype;
+    struct s3c24xx_lcd_state_s *s = (struct s3c24xx_lcd_state_s *)
+            qemu_mallocz(sizeof(struct s3c24xx_lcd_state_s));
+
+    s->base = base;
+    s->irq = irq;
+
+    s3c24xx_lcd_reset(s);
+
+    s->ds = graphic_console_init(s3c24xx_update_display,
+                                      s3c24xx_invalidate_display, 
+                                      s3c24xx_screen_dump, NULL, s);
+
+    iomemtype = cpu_register_io_memory(0, s3c24xx_lcd_readfn,
+                    s3c24xx_lcd_writefn, s);
+    cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
+
+    register_savevm("s3c24xx_lcd", 0, 0, s3c24xx_lcd_save, s3c24xx_lcd_load, s);
+
+    switch (ds_get_bits_per_pixel(s->ds)) {
+    case 0:
+        s->dest_width = 0;
+        break;
+    case 8:
+        s->line_fn = s3c24xx_draw_fn_8;
+        s->dest_width = 1;
+        break;
+    case 15:
+        s->line_fn = s3c24xx_draw_fn_15;
+        s->dest_width = 2;
+        break;
+    case 16:
+        s->line_fn = s3c24xx_draw_fn_16;
+        s->dest_width = 2;
+        break;
+    case 24:
+        s->line_fn = s3c24xx_draw_fn_24;
+        s->dest_width = 3;
+        break;
+    case 32:
+        s->line_fn = s3c24xx_draw_fn_32;
+        s->dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+    return s;
+}
+
+
+void s3c24xx_lcd_init(S3CState *soc)
+{
+    soc->lcd = _s3c24xx_lcd_init(CPU_S3C2410X_LCD_BASE, soc->irqs[16]);    
+}
Index: hw/boards.h
===================================================================
--- hw/boards.h	(revision 6883)
+++ hw/boards.h	(working copy)
@@ -128,4 +128,7 @@
 /* tosa.c */
 extern QEMUMachine tosapda_machine;
 
+/* simtecbast.c */
+extern QEMUMachine simtecbast_machine;
+
 #endif
Index: hw/s3c24xx_memc.c
===================================================================
--- hw/s3c24xx_memc.c	(revision 0)
+++ hw/s3c24xx_memc.c	(revision 0)
@@ -0,0 +1,59 @@
+/* hw/s3c24xx_memc.c
+ *
+ * Samsung S3C24XX memc emulation (trivial register backing)
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+
+static void
+s3c24xx_memc_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x3f) >> 2;
+  if (addr < 0 || addr > 12) addr = 12;
+  S3C24XX_DBF("Write MEMC[%d] = %08x\n", addr, value);
+  soc->memc_reg[addr] = value;
+}
+
+static uint32_t
+s3c24xx_memc_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x3f) >> 2;
+  if (addr < 0 || addr > 12) addr = 12;
+  S3C24XX_DBF("Read MEMC[%d]\n", addr);
+  return soc->memc_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c24xx_memc_read[] = {
+  &s3c24xx_memc_read_f,
+  &s3c24xx_memc_read_f,
+  &s3c24xx_memc_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_memc_write[] = {
+  &s3c24xx_memc_write_f,
+  &s3c24xx_memc_write_f,
+  &s3c24xx_memc_write_f,
+};
+
+
+void
+s3c24xx_memc_init(S3CState *soc)
+{
+  /* Memory controller is all about SDRAM control, thus we just drop
+   * some RAM in there and assume life will be ok.
+   * It is 13 registers, each 4 bytes.
+   */
+  int tag;
+  tag = cpu_register_io_memory(0, s3c24xx_memc_read, s3c24xx_memc_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_BWSCON, 13*4, tag);
+  
+  for(tag = 0; tag < 13; tag++)
+    soc->memc_reg[tag] = 0;
+}
Index: hw/s3c24xx_template.h
===================================================================
--- hw/s3c24xx_template.h	(revision 0)
+++ hw/s3c24xx_template.h	(revision 0)
@@ -0,0 +1,262 @@
+/*
+ * Samsung S3C2410A LCD controller emulation.
+ *
+ * Copyright (c) 2007 OpenMoko, Inc.
+ * Author: Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Framebuffer format conversion routines.
+ */
+
+# define SKIP_PIXEL(to)		to += deststep
+#if BITS == 8
+# define COPY_PIXEL(to, from)	*to = from; SKIP_PIXEL(to)
+#elif BITS == 15 || BITS == 16
+# define COPY_PIXEL(to, from)	*(uint16_t *) to = from; SKIP_PIXEL(to)
+#elif BITS == 24 
+# define COPY_PIXEL(to, from)	\
+	*(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
+#elif BITS == 32
+# define COPY_PIXEL(to, from)	*(uint32_t *) to = from; SKIP_PIXEL(to)
+#else
+# error unknown bit depth
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP_WORDS	1
+#endif
+
+#define FN_2(x)		FN(x + 1) FN(x)
+#define FN_4(x)		FN_2(x + 2) FN_2(x)
+#define FN_8(x)		FN_4(x + 4) FN_4(x)
+
+static void glue(s3c24xx_draw_line1_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> (x)) & 1]);
+#ifdef SWAP_WORDS
+        FN_8(24)
+        FN_8(16)
+        FN_8(8)
+        FN_8(0)
+#else
+        FN_8(0)
+        FN_8(8)
+        FN_8(16)
+        FN_8(24)
+#endif
+#undef FN
+        width -= 32;
+        src += 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line2_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+        FN_4(12)
+        FN_4(8)
+        FN_4(4)
+        FN_4(0)
+#else
+        FN_4(0)
+        FN_4(4)
+        FN_4(8)
+        FN_4(12)
+#endif
+#undef FN
+        width -= 16;
+        src += 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line4_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+        FN_2(6)
+        FN_2(4)
+        FN_2(2)
+        FN_2(0)
+#else
+        FN_2(0)
+        FN_2(2)
+        FN_2(4)
+        FN_2(6)
+#endif
+#undef FN
+        width -= 8;
+        src += 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line8_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+        FN(24)
+        FN(16)
+        FN(8)
+        FN(0)
+#else
+        FN(0)
+        FN(8)
+        FN(16)
+        FN(24)
+#endif
+#undef FN
+        width -= 4;
+        src += 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line16a_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line16b_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x3f) << 2;
+        data >>= 5;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x3f) << 2;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line12_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+        src += 3;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        /* XXX should use (x & 0xf) << 4) | (x & 0xf) for natural
+         * colours.  Otherwise the image may be a bit darkened.  */
+        b = (data & 0xf00) >> 4;
+        g = (data & 0xf0) << 0;
+        r = (data & 0xf) << 4;
+        data >>= 12;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0xf00) >> 4;
+        g = (data & 0xf0) << 0;
+        r = (data & 0xf) << 4;
+        data >>= 12;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0xf00) >> 4;
+        g = (data & 0xf0) << 0;
+        r = (data & 0xf) << 4;
+        data >>= 12;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0xf00) >> 4;
+        g = (data & 0xf0) << 0;
+        r = (data & 0xf) << 4;
+        data >>= 12;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(s3c24xx_draw_line24_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        COPY_PIXEL(dest, glue(s3c24xx_rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static s3c24xx_drawfn_t glue(s3c24xx_draw_fn_, BITS)[] =
+{
+    glue(s3c24xx_draw_line1_, BITS),
+    glue(s3c24xx_draw_line2_, BITS),
+    glue(s3c24xx_draw_line4_, BITS),
+    glue(s3c24xx_draw_line8_, BITS),
+    glue(s3c24xx_draw_line12_, BITS),
+    glue(s3c24xx_draw_line16a_, BITS),
+    glue(s3c24xx_draw_line16b_, BITS),
+    glue(s3c24xx_draw_line24_, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
Index: hw/devices.h
===================================================================
--- hw/devices.h	(revision 6883)
+++ hw/devices.h	(working copy)
@@ -3,6 +3,13 @@
 
 /* Devices that have nowhere better to go.  */
 
+/* dm9000.c */
+#ifdef NEED_CPU_H
+/* This ifdef is present because target_phys_addr_t comes from cpu-defs.h */
+void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr, uint32_t addr_offset, 
+                 uint32_t data_offset, qemu_irq irq);
+#endif
+
 /* smc91c111.c */
 void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
 
Index: hw/simtechw.h
===================================================================
--- hw/simtechw.h	(revision 0)
+++ hw/simtechw.h	(revision 0)
@@ -0,0 +1,14 @@
+/** hw/simtechw.h
+ *
+ * Simtec board related hardware such as IDE.
+ *
+ * Copyright 2008 Daniel Silverstone <dsilvers@simtec.co.uk>
+ */
+
+#ifndef QEMU_HW_SIMTECHW_H
+#define QEMU_HW_SIMTECHW_H
+
+int stcb_ide_init (BlockDriverState *hd0, BlockDriverState *hd1, qemu_irq irq);
+
+
+#endif
Index: hw/s3c24xx_iic.c
===================================================================
--- hw/s3c24xx_iic.c	(revision 0)
+++ hw/s3c24xx_iic.c	(revision 0)
@@ -0,0 +1,290 @@
+/* hw/s3c24xx_iic.c
+ *
+ * Samsung S3C24XX emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone, Ben Dooks
+ *  and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "s3c2410x.h"
+#include "s3c24xx_iic.h"
+#include "i2c.h"
+#include "hw.h"
+
+
+/* IIC-bus serial interface */
+struct s3c24xx_i2c_state_s {
+    i2c_slave slave;
+    i2c_bus *bus;
+    target_phys_addr_t base;
+    qemu_irq irq;
+
+    uint8_t control;
+    uint8_t status;
+    uint8_t data;
+    uint8_t addy;
+    int busy;
+    int newstart;
+};
+
+static void s3c24xx_i2c_irq(struct s3c24xx_i2c_state_s *s)
+{
+    S3C24XX_DBF("IIC, setting IRQ pending\n");
+    s->control |= 1 << 4;
+    if (s->control & (1 << 5)) {
+      S3C24XX_DBF("IIC, raising irq\n");
+      qemu_irq_raise(s->irq);
+    }
+}
+
+static void s3c24xx_i2c_reset(struct s3c24xx_i2c_state_s *s)
+{
+    s->control = 0x00;
+    s->status = 0x00;
+    s->busy = 0;
+    s->newstart = 0;
+}
+
+static void s3c24xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) i2c;
+    if (!(s->status & (1 << 4)))
+        return;
+
+    switch (event) {
+    case I2C_START_RECV:
+    case I2C_START_SEND:
+        s->status |= 1 << 2;
+        s3c24xx_i2c_irq(s);
+        break;
+    case I2C_FINISH:
+        s->status &= ~6;
+        break;
+    case I2C_NACK:
+        s->status |= 1 << 0;
+        break;
+    default:
+        break;
+    }
+}
+
+static int s3c24xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) i2c;
+    if (!(s->status & (1 << 4)))
+        return 1;
+
+    if ((s->status >> 6) == 0)
+        s->data = data;						/* TODO */
+    s->status &= ~(1 << 0);
+    s3c24xx_i2c_irq(s);
+
+    return !(s->control & (1 << 7));
+}
+
+static int s3c24xx_i2c_rx(i2c_slave *i2c)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) i2c;
+    if (!(s->status & (1 << 4)))
+        return 1;
+
+    if ((s->status >> 6) == 1) {
+        s->status &= ~(1 << 0);
+        s3c24xx_i2c_irq(s);
+        return s->data;
+    }
+
+    return 0x00;
+}
+
+static void s3c_master_work(void *opaque)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+    int start = 0, stop = 0, ack = 1;
+    
+    S3C24XX_DBF("IIC, master, doing work?\n");
+    
+    if (s->control & (1 << 4))				/* Interrupt pending */
+        return;
+    if ((s->status & 0x90) != 0x90)			/* Master */
+        return;
+    
+    stop = ~s->status & (1 << 5);
+    if (s->newstart && s->status & (1 << 5)) {		/* START */
+        S3C24XX_DBF("IIC, START\n");
+        s->busy = 1;
+        start = 1;
+    }
+    s->newstart = 0;
+    
+    if (!s->busy) {
+      S3C24XX_DBF("IIC, master, not busy?\n");
+      return;
+    }
+
+    if (start) {
+        S3C24XX_DBF("IIC, master, starting transfer\n");
+        ack = !i2c_start_transfer(s->bus, s->data >> 1, (~s->status >> 6) & 1);
+    } else if (stop) {
+        S3C24XX_DBF("IIC, master, stopping\n");
+        i2c_end_transfer(s->bus);
+    } else if (s->status & (1 << 6)) { 
+        S3C24XX_DBF("IIC, master, sending\n");
+        ack = !i2c_send(s->bus, s->data);
+    } else {
+        S3C24XX_DBF("IIC, master, receiving\n");
+        s->data = i2c_recv(s->bus);
+
+        if (!(s->control & (1 << 7)))			/* ACK */
+            i2c_nack(s->bus);
+    }
+
+    if (!(s->status & (1 << 5))) {
+        s->busy = 0;
+        S3C24XX_DBF("IIC, master, not busy\n");
+        return;
+    }
+    s->status &= ~1;
+    s->status |= !ack;
+    if (!ack) {
+      S3C24XX_DBF("IIC, master not busy by ack\n");
+      s->busy = 0;
+    }
+    s3c24xx_i2c_irq(s);
+}
+
+static uint32_t s3c24xx_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+    
+    S3C24XX_DBF("IIC: doing read of %d\n", (unsigned int)addr);
+    
+    switch (addr & 0xFFFFFFFF) {
+    case S3C2410_IICCON:
+        return s->control;
+    case S3C2410_IICSTAT:
+        return s->status & ~(1 << 5);			/* Busy signal */
+    case S3C2410_IICADD:
+        return s->addy;
+    case S3C2410_IICDS:
+        return s->data;
+    default:
+        S3C24XX_DBF("%s: Bad register 0x%lx\n", __FUNCTION__, (long unsigned int)addr);
+        break;
+    }
+    return 0;
+}
+
+static void s3c24xx_i2c_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+    
+    S3C24XX_DBF("IIC, received write to %d of 0x%08x\n", (unsigned int)addr, value);
+    
+    switch (addr) {
+    case S3C2410_IICCON:
+        s->control = (s->control | 0xef) & value;
+        S3C24XX_DBF("IIC, IICCON is now 0x%08x\n", s->control);
+        if (s->busy || ((s->control & (1<<4)) == 0))
+            s3c_master_work(s);
+        break;
+
+    case S3C2410_IICSTAT:
+        s->status &= 0x0f;
+        s->status |= value & 0xf0;
+        if (s->status & (1 << 5))
+            s->newstart = 1;
+        s3c_master_work(s);
+        break;
+
+    case S3C2410_IICADD:
+        s->addy = value & 0x7f;
+        i2c_set_slave_address(&s->slave, s->addy);
+        break;
+
+    case S3C2410_IICDS:
+        s->data = value & 0xff;
+        s->busy = 1;
+        break;
+
+    default:
+        printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *s3c24xx_i2c_readfn[] = {
+    s3c24xx_i2c_read,
+    s3c24xx_i2c_read,
+    s3c24xx_i2c_read,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_i2c_writefn[] = {
+    s3c24xx_i2c_write,
+    s3c24xx_i2c_write,
+    s3c24xx_i2c_write,
+};
+
+static void s3c24xx_i2c_save(QEMUFile *f, void *opaque)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+    qemu_put_8s(f, &s->control);
+    qemu_put_8s(f, &s->status);
+    qemu_put_8s(f, &s->data);
+    qemu_put_8s(f, &s->addy);
+
+    qemu_put_be32(f, s->busy);
+    qemu_put_be32(f, s->newstart);
+
+    /* i2c_bus_save(f, s->bus); */
+    i2c_slave_save(f, &s->slave);
+}
+
+static int s3c24xx_i2c_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+    qemu_get_8s(f, &s->control);
+    qemu_get_8s(f, &s->status);
+    qemu_get_8s(f, &s->data);
+    qemu_get_8s(f, &s->addy);
+
+    s->busy = qemu_get_be32(f);
+    s->newstart = qemu_get_be32(f);
+
+    /* i2c_bus_load(f, s->bus); */
+    i2c_slave_load(f, &s->slave);
+    return 0;
+}
+
+void s3c24xx_iic_init(S3CState *soc)
+{
+    int iomemtype;
+    struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *)
+            qemu_mallocz(sizeof(struct s3c24xx_i2c_state_s));
+
+    s->base = CPU_S3C2410X_IIC_BASE;
+    s->irq = soc->irqs[27];
+    s->slave.event = s3c24xx_i2c_event;
+    s->slave.send = s3c24xx_i2c_tx;
+    s->slave.recv = s3c24xx_i2c_rx;
+    s->bus = i2c_init_bus();
+
+    s3c24xx_i2c_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, s3c24xx_i2c_readfn,
+                    s3c24xx_i2c_writefn, s);
+    cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
+
+    register_savevm("s3c24xx_i2c", 0, 0, s3c24xx_i2c_save, s3c24xx_i2c_load, s);
+
+    soc->iic = s;
+}
+
+i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s)
+{
+    return s->bus;
+}
+
Index: hw/s3c24xx_iic.h
===================================================================
--- hw/s3c24xx_iic.h	(revision 0)
+++ hw/s3c24xx_iic.h	(revision 0)
@@ -0,0 +1,56 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-iic.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ *		http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2410 I2C Controller
+*/
+
+#ifndef __ASM_ARCH_REGS_IIC_H
+#define __ASM_ARCH_REGS_IIC_H __FILE__
+
+/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */
+
+#define S3C2410_IICREG(x) (x)
+
+#define S3C2410_IICCON    S3C2410_IICREG(0x00)
+#define S3C2410_IICSTAT   S3C2410_IICREG(0x04)
+#define S3C2410_IICADD    S3C2410_IICREG(0x08)
+#define S3C2410_IICDS     S3C2410_IICREG(0x0C)
+#define S3C2440_IICLC	  S3C2410_IICREG(0x10)
+
+#define S3C2410_IICCON_ACKEN		(1<<7)
+#define S3C2410_IICCON_TXDIV_16		(0<<6)
+#define S3C2410_IICCON_TXDIV_512	(1<<6)
+#define S3C2410_IICCON_IRQEN		(1<<5)
+#define S3C2410_IICCON_IRQPEND		(1<<4)
+#define S3C2410_IICCON_SCALE(x)		((x)&15)
+#define S3C2410_IICCON_SCALEMASK	(0xf)
+
+#define S3C2410_IICSTAT_MASTER_RX	(2<<6)
+#define S3C2410_IICSTAT_MASTER_TX	(3<<6)
+#define S3C2410_IICSTAT_SLAVE_RX	(0<<6)
+#define S3C2410_IICSTAT_SLAVE_TX	(1<<6)
+#define S3C2410_IICSTAT_MODEMASK	(3<<6)
+
+#define S3C2410_IICSTAT_START		(1<<5)
+#define S3C2410_IICSTAT_BUSBUSY		(1<<5)
+#define S3C2410_IICSTAT_TXRXEN		(1<<4)
+#define S3C2410_IICSTAT_ARBITR		(1<<3)
+#define S3C2410_IICSTAT_ASSLAVE		(1<<2)
+#define S3C2410_IICSTAT_ADDR0		(1<<1)
+#define S3C2410_IICSTAT_LASTBIT		(1<<0)
+
+#define S3C2410_IICLC_SDA_DELAY0	(0 << 0)
+#define S3C2410_IICLC_SDA_DELAY5	(1 << 0)
+#define S3C2410_IICLC_SDA_DELAY10	(2 << 0)
+#define S3C2410_IICLC_SDA_DELAY15	(3 << 0)
+#define S3C2410_IICLC_SDA_DELAY_MASK	(3 << 0)
+
+#define S3C2410_IICLC_FILTER_ON		(1<<2)
+
+#endif /* __ASM_ARCH_REGS_IIC_H */
Index: target-arm/helper.c
===================================================================
--- target-arm/helper.c	(revision 6883)
+++ target-arm/helper.c	(working copy)
@@ -37,6 +37,8 @@
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM920T:
+       break;
     case ARM_CPUID_ARM926:
         set_feature(env, ARM_FEATURE_VFP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
@@ -279,6 +281,7 @@
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
+    { ARM_CPUID_ARM920T, "arm920t"},
     { ARM_CPUID_ARM1136, "arm1136"},
     { ARM_CPUID_ARM1136_R2, "arm1136-r2"},
     { ARM_CPUID_ARM11MPCORE, "arm11mpcore"},
Index: target-arm/machine.c
===================================================================
--- target-arm/machine.c	(revision 6883)
+++ target-arm/machine.c	(working copy)
@@ -7,6 +7,7 @@
     qemu_register_machine(&versatilepb_machine);
     qemu_register_machine(&versatileab_machine);
     qemu_register_machine(&realview_machine);
+    qemu_register_machine(&simtecbast_machine);
     qemu_register_machine(&akitapda_machine);
     qemu_register_machine(&spitzpda_machine);
     qemu_register_machine(&borzoipda_machine);
Index: target-arm/cpu.h
===================================================================
--- target-arm/cpu.h	(revision 6883)
+++ target-arm/cpu.h	(working copy)
@@ -370,6 +370,7 @@
 #define ARM_CPUID_ARM1026     0x4106a262
 #define ARM_CPUID_ARM926      0x41069265
 #define ARM_CPUID_ARM946      0x41059461
+#define ARM_CPUID_ARM920T     0x41129200
 #define ARM_CPUID_TI915T      0x54029152
 #define ARM_CPUID_TI925T      0x54029252
 #define ARM_CPUID_PXA250      0x69052100
Index: target-arm/translate.c
===================================================================
--- target-arm/translate.c	(revision 6883)
+++ target-arm/translate.c	(working copy)
@@ -5565,6 +5565,12 @@
             return 0;
         }
     }
+
+    gen_op_movl_T0_im(0);
+    gen_movl_reg_T0(s, rt);
+    return 0;
+
+
     fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
             op1, crn, crm, op2);
     return 1;
