r3627 - in trunk/src/host/qemu-neo1973: . hw linux-user linux-user/ppc target-arm target-i386 target-m68k target-mips target-ppc target-sparc

andrew at sita.openmoko.org andrew at sita.openmoko.org
Mon Dec 10 18:51:53 CET 2007


Author: andrew
Date: 2007-12-10 18:51:36 +0100 (Mon, 10 Dec 2007)
New Revision: 3627

Added:
   trunk/src/host/qemu-neo1973/hw/eccmemctl.c
Modified:
   trunk/src/host/qemu-neo1973/Makefile
   trunk/src/host/qemu-neo1973/Makefile.target
   trunk/src/host/qemu-neo1973/configure
   trunk/src/host/qemu-neo1973/cpu-defs.h
   trunk/src/host/qemu-neo1973/exec.c
   trunk/src/host/qemu-neo1973/hw/esp.c
   trunk/src/host/qemu-neo1973/hw/flash.h
   trunk/src/host/qemu-neo1973/hw/gumstix.c
   trunk/src/host/qemu-neo1973/hw/ide.c
   trunk/src/host/qemu-neo1973/hw/lsi53c895a.c
   trunk/src/host/qemu-neo1973/hw/mainstone.c
   trunk/src/host/qemu-neo1973/hw/mainstone.h
   trunk/src/host/qemu-neo1973/hw/mips_r4k.c
   trunk/src/host/qemu-neo1973/hw/omap.c
   trunk/src/host/qemu-neo1973/hw/omap.h
   trunk/src/host/qemu-neo1973/hw/pci.c
   trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c
   trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c
   trunk/src/host/qemu-neo1973/hw/piix_pci.c
   trunk/src/host/qemu-neo1973/hw/ppc405_boards.c
   trunk/src/host/qemu-neo1973/hw/scsi-disk.c
   trunk/src/host/qemu-neo1973/hw/scsi-disk.h
   trunk/src/host/qemu-neo1973/hw/sun4m.c
   trunk/src/host/qemu-neo1973/hw/sun4m.h
   trunk/src/host/qemu-neo1973/hw/usb-msd.c
   trunk/src/host/qemu-neo1973/linux-user/ppc/syscall.h
   trunk/src/host/qemu-neo1973/linux-user/ppc/target_signal.h
   trunk/src/host/qemu-neo1973/linux-user/socket.h
   trunk/src/host/qemu-neo1973/linux-user/syscall.c
   trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h
   trunk/src/host/qemu-neo1973/target-arm/helper.c
   trunk/src/host/qemu-neo1973/target-i386/exec.h
   trunk/src/host/qemu-neo1973/target-i386/helper.c
   trunk/src/host/qemu-neo1973/target-i386/helper2.c
   trunk/src/host/qemu-neo1973/target-i386/op.c
   trunk/src/host/qemu-neo1973/target-i386/translate.c
   trunk/src/host/qemu-neo1973/target-m68k/helper.c
   trunk/src/host/qemu-neo1973/target-mips/translate.c
   trunk/src/host/qemu-neo1973/target-ppc/cpu.h
   trunk/src/host/qemu-neo1973/target-ppc/helper.c
   trunk/src/host/qemu-neo1973/target-ppc/translate_init.c
   trunk/src/host/qemu-neo1973/target-sparc/translate.c
Log:
Weekly sync with cvs.savannah.nongnu.org.


Modified: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/Makefile	2007-12-10 17:51:36 UTC (rev 3627)
@@ -264,6 +264,7 @@
 	$(bindir)/qemu-system-arm \
 	$(bindir)/qemu-system-m68k \
 	$(bindir)/qemu-system-sh4 \
+	$(bindir)/qemu-system-sh4eb \
 	$(bindir)/qemu-i386 \
         $(bindir)/qemu-arm \
         $(bindir)/qemu-armeb \
@@ -279,6 +280,7 @@
         $(bindir)/qemu-alpha \
         $(bindir)/qemu-m68k \
         $(bindir)/qemu-sh4 \
+        $(bindir)/qemu-sh4eb \
         $(bindir)/qemu-img \
 	$(datadir)/bios.bin \
 	$(datadir)/vgabios.bin \

Modified: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/Makefile.target	2007-12-10 17:51:36 UTC (rev 3627)
@@ -490,7 +490,7 @@
 else
 VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
 VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
-VL_OBJS+= cs4231.o ptimer.o
+VL_OBJS+= cs4231.o ptimer.o eccmemctl.o
 endif
 endif
 ifeq ($(TARGET_BASE_ARCH), arm)

Modified: trunk/src/host/qemu-neo1973/configure
===================================================================
--- trunk/src/host/qemu-neo1973/configure	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/configure	2007-12-10 17:51:36 UTC (rev 3627)
@@ -526,11 +526,11 @@
 if test -z "$target_list" ; then
 # these targets are portable
     if [ "$softmmu" = "yes" ] ; then
-        target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu cris-softmmu"
+        target_list="i386-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc-softmmu ppcemb-softmmu ppc64-softmmu m68k-softmmu sh4-softmmu sh4eb-softmmu cris-softmmu"
     fi
 # the following are Linux specific
     if [ "$linux_user" = "yes" ] ; then
-        target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user ppc-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list"
+        target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user sparc64-linux-user sparc32plus-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user sh4-linux-user sh4eb-linux-user ppc-linux-user ppc64-linux-user ppc64abi32-linux-user x86_64-linux-user cris-linux-user $target_list"
     fi
 # the following are Darwin specific
     if [ "$darwin_user" = "yes" ] ; then

Modified: trunk/src/host/qemu-neo1973/cpu-defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-defs.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/cpu-defs.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -146,6 +146,8 @@
     void *next_cpu; /* next CPU sharing TB cache */                     \
     int cpu_index; /* CPU index (informative) */                        \
     /* user data */                                                     \
-    void *opaque;
+    void *opaque;                                                       \
+                                                                        \
+    const char *cpu_model_str;
 
 #endif

Modified: trunk/src/host/qemu-neo1973/exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/exec.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/exec.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -1317,9 +1317,7 @@
 
 CPUState *cpu_copy(CPUState *env)
 {
-#if 0
-    /* XXX: broken, must be handled by each CPU */
-    CPUState *new_env = cpu_init();
+    CPUState *new_env = cpu_init(env->cpu_model_str);
     /* preserve chaining and index */
     CPUState *next_cpu = new_env->next_cpu;
     int cpu_index = new_env->cpu_index;
@@ -1327,9 +1325,6 @@
     new_env->next_cpu = next_cpu;
     new_env->cpu_index = cpu_index;
     return new_env;
-#else
-    return NULL;
-#endif
 }
 
 #if !defined(CONFIG_USER_ONLY)

Added: trunk/src/host/qemu-neo1973/hw/eccmemctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/eccmemctl.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/eccmemctl.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -0,0 +1,266 @@
+/*
+ * QEMU Sparc Sun4m ECC memory controller emulation
+ *
+ * Copyright (c) 2007 Robert Reif
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "sun4m.h"
+#include "sysemu.h"
+
+//#define DEBUG_ECC
+
+#ifdef DEBUG_ECC
+#define DPRINTF(fmt, args...)                           \
+    do { printf("ECC: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+/* There are 3 versions of this chip used in SMP sun4m systems:
+ * MCC (version 0, implementation 0) SS-600MP
+ * EMC (version 0, implementation 1) SS-10
+ * SMC (version 0, implementation 2) SS-10SX and SS-20
+ */
+
+/* Register offsets */
+#define ECC_FCR_REG    0
+#define ECC_FSR_REG    8
+#define ECC_FAR0_REG   16
+#define ECC_FAR1_REG   20
+#define ECC_DIAG_REG   24
+
+/* ECC fault control register */
+#define ECC_FCR_EE     0x00000001      /* Enable ECC checking */
+#define ECC_FCR_EI     0x00000010      /* Enable Interrupts on correctable errors */
+#define ECC_FCR_VER    0x0f000000      /* Version */
+#define ECC_FCR_IMPL   0xf0000000      /* Implementation */
+
+/* ECC fault status register */
+#define ECC_FSR_CE     0x00000001      /* Correctable error */
+#define ECC_FSR_BS     0x00000002      /* C2 graphics bad slot access */
+#define ECC_FSR_TO     0x00000004      /* Timeout on write */
+#define ECC_FSR_UE     0x00000008      /* Uncorrectable error */
+#define ECC_FSR_DW     0x000000f0      /* Index of double word in block */
+#define ECC_FSR_SYND   0x0000ff00      /* Syndrome for correctable error */
+#define ECC_FSR_ME     0x00010000      /* Multiple errors */
+#define ECC_FSR_C2ERR  0x00020000      /* C2 graphics error */
+
+/* ECC fault address register 0 */
+#define ECC_FAR0_PADDR 0x0000000f      /* PA[32-35] */
+#define ECC_FAR0_TYPE  0x000000f0      /* Transaction type */
+#define ECC_FAR0_SIZE  0x00000700      /* Transaction size */
+#define ECC_FAR0_CACHE 0x00000800      /* Mapped cacheable */
+#define ECC_FAR0_LOCK  0x00001000      /* Error occurred in attomic cycle */
+#define ECC_FAR0_BMODE 0x00002000      /* Boot mode */
+#define ECC_FAR0_VADDR 0x003fc000      /* VA[12-19] (superset bits) */
+#define ECC_FAR0_S     0x08000000      /* Supervisor mode */
+#define ECC_FARO_MID   0xf0000000      /* Module ID */
+
+/* ECC diagnostic register */
+#define ECC_DIAG_CBX   0x00000001
+#define ECC_DIAG_CB0   0x00000002
+#define ECC_DIAG_CB1   0x00000004
+#define ECC_DIAG_CB2   0x00000008
+#define ECC_DIAG_CB4   0x00000010
+#define ECC_DIAG_CB8   0x00000020
+#define ECC_DIAG_CB16  0x00000040
+#define ECC_DIAG_CB32  0x00000080
+#define ECC_DIAG_DMODE 0x00000c00
+
+#define ECC_NREGS      8
+#define ECC_SIZE       (ECC_NREGS * sizeof(uint32_t))
+#define ECC_ADDR_MASK  (ECC_SIZE - 1)
+
+typedef struct ECCState {
+    uint32_t regs[ECC_NREGS];
+} ECCState;
+
+static void ecc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    printf("ECC: Unsupported write 0x" TARGET_FMT_plx " %02x\n",
+           addr, val & 0xff);
+}
+
+static uint32_t ecc_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    printf("ECC: Unsupported read 0x" TARGET_FMT_plx " 00\n", addr);
+    return 0;
+}
+
+static void ecc_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    printf("ECC: Unsupported write 0x" TARGET_FMT_plx " %04x\n",
+           addr, val & 0xffff);
+}
+
+static uint32_t ecc_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    printf("ECC: Unsupported read 0x" TARGET_FMT_plx " 0000\n", addr);
+    return 0;
+}
+
+static void ecc_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    ECCState *s = opaque;
+
+    switch (addr & ECC_ADDR_MASK) {
+    case ECC_FCR_REG:
+        s->regs[0] = (s->regs[0] & (ECC_FCR_VER | ECC_FCR_IMPL)) |
+                     (val & ~(ECC_FCR_VER | ECC_FCR_IMPL));
+        DPRINTF("Write fault control %08x\n", val);
+        break;
+    case 4:
+        s->regs[1] =  val;
+        DPRINTF("Write reg[1] %08x\n", val);
+        break;
+    case ECC_FSR_REG:
+        s->regs[2] =  val;
+        DPRINTF("Write fault status %08x\n", val);
+        break;
+    case 12:
+        s->regs[3] =  val;
+        DPRINTF("Write reg[3] %08x\n", val);
+        break;
+    case ECC_FAR0_REG:
+        s->regs[4] =  val;
+        DPRINTF("Write fault address 0 %08x\n", val);
+        break;
+    case ECC_FAR1_REG:
+        s->regs[5] =  val;
+        DPRINTF("Write fault address 1 %08x\n", val);
+        break;
+    case ECC_DIAG_REG:
+        s->regs[6] =  val;
+        DPRINTF("Write diag %08x\n", val);
+        break;
+    case 28:
+        s->regs[7] =  val;
+        DPRINTF("Write reg[7] %08x\n", val);
+        break;
+    }
+}
+
+static uint32_t ecc_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    ECCState *s = opaque;
+    uint32_t ret = 0;
+
+    switch (addr & ECC_ADDR_MASK) {
+    case ECC_FCR_REG:
+        ret = s->regs[0];
+        DPRINTF("Read enable %08x\n", ret);
+        break;
+    case 4:
+        ret = s->regs[1];
+        DPRINTF("Read register[1] %08x\n", ret);
+        break;
+    case ECC_FSR_REG:
+        ret = s->regs[2];
+        DPRINTF("Read fault status %08x\n", ret);
+        break;
+    case 12:
+        ret = s->regs[3];
+        DPRINTF("Read reg[3] %08x\n", ret);
+        break;
+    case ECC_FAR0_REG:
+        ret = s->regs[4];
+        DPRINTF("Read fault address 0 %08x\n", ret);
+        break;
+    case ECC_FAR1_REG:
+        ret = s->regs[5];
+        DPRINTF("Read fault address 1 %08x\n", ret);
+        break;
+    case ECC_DIAG_REG:
+        ret = s->regs[6];
+        DPRINTF("Read diag %08x\n", ret);
+        break;
+    case 28:
+        ret = s->regs[7];
+        DPRINTF("Read reg[7] %08x\n", ret);
+        break;
+    }
+    return ret;
+}
+
+static CPUReadMemoryFunc *ecc_mem_read[3] = {
+    ecc_mem_readb,
+    ecc_mem_readw,
+    ecc_mem_readl,
+};
+
+static CPUWriteMemoryFunc *ecc_mem_write[3] = {
+    ecc_mem_writeb,
+    ecc_mem_writew,
+    ecc_mem_writel,
+};
+
+static int ecc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    ECCState *s = opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    for (i = 0; i < ECC_NREGS; i++)
+        qemu_get_be32s(f, &s->regs[i]);
+
+    return 0;
+}
+
+static void ecc_save(QEMUFile *f, void *opaque)
+{
+    ECCState *s = opaque;
+    int i;
+
+    for (i = 0; i < ECC_NREGS; i++)
+        qemu_put_be32s(f, &s->regs[i]);
+}
+
+static void ecc_reset(void *opaque)
+{
+    ECCState *s = opaque;
+    int i;
+
+    s->regs[ECC_FCR_REG] &= (ECC_FCR_VER | ECC_FCR_IMPL);
+
+    for (i = 1; i < ECC_NREGS; i++)
+        s->regs[i] = 0;
+}
+
+void * ecc_init(target_phys_addr_t base, uint32_t version)
+{
+    int ecc_io_memory;
+    ECCState *s;
+
+    s = qemu_mallocz(sizeof(ECCState));
+    if (!s)
+        return NULL;
+
+    s->regs[0] = version;
+
+    ecc_io_memory = cpu_register_io_memory(0, ecc_mem_read, ecc_mem_write, s);
+    cpu_register_physical_memory(base, ECC_SIZE, ecc_io_memory);
+    register_savevm("ECC", base, 1, ecc_save, ecc_load, s);
+    qemu_register_reset(ecc_reset, s);
+    ecc_reset(s);
+    return s;
+}

Modified: trunk/src/host/qemu-neo1973/hw/esp.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/esp.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/esp.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -165,7 +165,7 @@
 
     if (s->current_dev) {
         /* Started a new command before the old one finished.  Cancel it.  */
-        scsi_cancel_io(s->current_dev, 0);
+        s->current_dev->cancel_io(s->current_dev, 0);
         s->async_len = 0;
     }
 
@@ -188,7 +188,7 @@
 
     DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
     lun = buf[0] & 7;
-    datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
+    datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
     s->ti_size = datalen;
     if (datalen != 0) {
         s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC;
@@ -196,10 +196,10 @@
         s->dma_counter = 0;
         if (datalen > 0) {
             s->rregs[ESP_RSTAT] |= STAT_DI;
-            scsi_read_data(s->current_dev, 0);
+            s->current_dev->read_data(s->current_dev, 0);
         } else {
             s->rregs[ESP_RSTAT] |= STAT_DO;
-            scsi_write_data(s->current_dev, 0);
+            s->current_dev->write_data(s->current_dev, 0);
         }
     }
     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
@@ -298,9 +298,9 @@
     if (s->async_len == 0) {
         if (to_device) {
             // ti_size is negative
-            scsi_write_data(s->current_dev, 0);
+            s->current_dev->write_data(s->current_dev, 0);
         } else {
-            scsi_read_data(s->current_dev, 0);
+            s->current_dev->read_data(s->current_dev, 0);
             /* If there is still data to be read from the device then
                complete the DMA operation immeriately.  Otherwise defer
                until the scsi layer has completed.  */
@@ -335,7 +335,7 @@
     } else {
         DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
         s->async_len = arg;
-        s->async_buf = scsi_get_buf(s->current_dev, 0);
+        s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
         if (s->dma_left) {
             esp_do_dma(s);
         } else if (s->dma_counter != 0 && s->ti_size <= 0) {
@@ -611,7 +611,7 @@
     }
     if (s->scsi_dev[id]) {
         DPRINTF("Destroying device %d\n", id);
-        scsi_disk_destroy(s->scsi_dev[id]);
+        s->scsi_dev[id]->destroy(s->scsi_dev[id]);
     }
     DPRINTF("Attaching block device %d\n", id);
     /* Command queueing is not implemented.  */

Modified: trunk/src/host/qemu-neo1973/hw/flash.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/flash.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/flash.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -1,12 +1,20 @@
 /* NOR flash devices */
 typedef struct pflash_t pflash_t;
 
-pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off,
-                           BlockDriverState *bs,
-                           uint32_t sector_len, int nb_blocs, int width,
-                           uint16_t id0, uint16_t id1,
-                           uint16_t id2, uint16_t id3);
+/* pflash_cfi01.c */
+pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs,
+                                uint32_t sector_len, int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3);
 
+/* pflash_cfi02.c */
+pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3);
+
 /* nand.c */
 struct nand_flash_s;
 struct nand_flash_s *nand_init(int manf_id, int chip_id);
@@ -37,4 +45,3 @@
 void ecc_reset(struct ecc_state_s *s);
 void ecc_put(QEMUFile *f, struct ecc_state_s *s);
 void ecc_get(QEMUFile *f, struct ecc_state_s *s);
-

Modified: trunk/src/host/qemu-neo1973/hw/gumstix.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gumstix.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/gumstix.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -67,7 +67,7 @@
         exit(1);
     }
 
-    if (!pflash_register(0x00000000, qemu_ram_alloc(connex_rom),
+    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(connex_rom),
             drives_table[index].bdrv, sector_len, connex_rom / sector_len,
             2, 0, 0, 0, 0)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -107,7 +107,7 @@
         exit(1);
     }
 
-    if (!pflash_register(0x00000000, qemu_ram_alloc(verdex_rom),
+    if (!pflash_cfi01_register(0x00000000, qemu_ram_alloc(verdex_rom),
             drives_table[index].bdrv, sector_len, verdex_rom / sector_len,
             2, 0, 0, 0, 0)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");

Modified: trunk/src/host/qemu-neo1973/hw/ide.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ide.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/ide.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -1361,7 +1361,7 @@
 
                     buf[8] = 0x2a;
                     buf[9] = 0x12;
-                    buf[10] = 0x08;
+                    buf[10] = 0x00;
                     buf[11] = 0x00;
 
                     buf[12] = 0x70;

Modified: trunk/src/host/qemu-neo1973/hw/lsi53c895a.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/lsi53c895a.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/lsi53c895a.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -187,6 +187,7 @@
     /* The tag is a combination of the device ID and the SCSI tag.  */
     uint32_t current_tag;
     uint32_t current_dma_len;
+    int command_complete;
     uint8_t *dma_buf;
     lsi_queue *queue;
     int queue_len;
@@ -465,7 +466,8 @@
     s->dbc -= count;
 
     if (s->dma_buf == NULL) {
-        s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag);
+        s->dma_buf = s->current_dev->get_buf(s->current_dev,
+                                             s->current_tag);
     }
 
     /* ??? Set SFBR to first data byte.  */
@@ -479,10 +481,10 @@
         s->dma_buf = NULL;
         if (out) {
             /* Write the data.  */
-            scsi_write_data(s->current_dev, s->current_tag);
+            s->current_dev->write_data(s->current_dev, s->current_tag);
         } else {
             /* Request any remaining data.  */
-            scsi_read_data(s->current_dev, s->current_tag);
+            s->current_dev->read_data(s->current_dev, s->current_tag);
         }
     } else {
         s->dma_buf += count;
@@ -596,6 +598,7 @@
     if (reason == SCSI_REASON_DONE) {
         DPRINTF("Command complete sense=%d\n", (int)arg);
         s->sense = arg;
+        s->command_complete = 2;
         if (s->waiting && s->dbc != 0) {
             /* Raise phase mismatch for short transfers.  */
             lsi_bad_phase(s, out, PHASE_ST);
@@ -612,6 +615,7 @@
     }
     DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
     s->current_dma_len = arg;
+    s->command_complete = 1;
     if (!s->waiting)
         return;
     if (s->waiting == 1 || s->dbc == 0) {
@@ -631,21 +635,30 @@
         s->dbc = 16;
     cpu_physical_memory_read(s->dnad, buf, s->dbc);
     s->sfbr = buf[0];
-    n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun);
+    s->command_complete = 0;
+    n = s->current_dev->send_command(s->current_dev, s->current_tag, buf,
+                                     s->current_lun);
     if (n > 0) {
         lsi_set_phase(s, PHASE_DI);
-        scsi_read_data(s->current_dev, s->current_tag);
+        s->current_dev->read_data(s->current_dev, s->current_tag);
     } else if (n < 0) {
         lsi_set_phase(s, PHASE_DO);
-        scsi_write_data(s->current_dev, s->current_tag);
+        s->current_dev->write_data(s->current_dev, s->current_tag);
     }
-    if (n && s->current_dma_len == 0) {
-        /* Command did not complete immediately so disconnect.  */
-        lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
-        lsi_add_msg_byte(s, 4); /* DISCONNECT */
-        lsi_set_phase(s, PHASE_MI);
-        s->msg_action = 1;
-        lsi_queue_command(s);
+
+    if (!s->command_complete) {
+        if (n) {
+            /* Command did not complete immediately so disconnect.  */
+            lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
+            lsi_add_msg_byte(s, 4); /* DISCONNECT */
+            /* wait data */
+            lsi_set_phase(s, PHASE_MI);
+            s->msg_action = 1;
+            lsi_queue_command(s);
+        } else {
+            /* wait command complete */
+            lsi_set_phase(s, PHASE_DI);
+        }
     }
 }
 
@@ -1822,7 +1835,7 @@
     }
     if (s->scsi_dev[id]) {
         DPRINTF("Destroying device %d\n", id);
-        scsi_disk_destroy(s->scsi_dev[id]);
+        s->scsi_dev[id]->destroy(s->scsi_dev[id]);
     }
     DPRINTF("Attaching block device %d\n", id);
     s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);

Modified: trunk/src/host/qemu-neo1973/hw/mainstone.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mainstone.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/mainstone.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -55,7 +55,8 @@
                 "'pflash' parameter\n");
         exit(1);
     }
-    if (!pflash_register(MST_FLASH_0, mainstone_ram + PXA2XX_INTERNAL_SIZE,
+    if (!pflash_cfi01_register(MST_FLASH_0,
+                         mainstone_ram + PXA2XX_INTERNAL_SIZE,
                          drives_table[index].bdrv,
                          256 * 1024, 128, 4, 0, 0, 0, 0)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -68,7 +69,8 @@
                 "'pflash' parameter\n");
         exit(1);
     }
-    if (!pflash_register(MST_FLASH_1, mainstone_ram + PXA2XX_INTERNAL_SIZE,
+    if (!pflash_cfi01_register(MST_FLASH_1,
+                         mainstone_ram + PXA2XX_INTERNAL_SIZE,
                          drives_table[index].bdrv,
                          256 * 1024, 128, 4, 0, 0, 0, 0)) {
         fprintf(stderr, "qemu: Error registering flash memory.\n");
@@ -76,6 +78,10 @@
     }
 
     mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]);
+
     smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]);
 
     arm_load_kernel(cpu->env, mainstone_ram, kernel_filename, kernel_cmdline,

Modified: trunk/src/host/qemu-neo1973/hw/mainstone.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mainstone.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/mainstone.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -17,7 +17,20 @@
 #define MST_FLASH_1		0x04000000
 
 /* IRQ definitions */
-#define ETHERNET_IRQ	3
+#define MMC_IRQ       0
+#define USIM_IRQ      1
+#define USBC_IRQ      2
+#define ETHERNET_IRQ  3
+#define AC97_IRQ      4
+#define PEN_IRQ       5
+#define MSINS_IRQ     6
+#define EXBRD_IRQ     7
+#define S0_CD_IRQ     9
+#define S0_STSCHG_IRQ 10
+#define S0_IRQ        11
+#define S1_CD_IRQ     13
+#define S1_STSCHG_IRQ 14
+#define S1_IRQ        15
 
 extern qemu_irq
 *mst_irq_init(struct pxa2xx_state_s *cpu, uint32_t base, int irq);

Modified: trunk/src/host/qemu-neo1973/hw/mips_r4k.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_r4k.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/mips_r4k.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -38,7 +38,7 @@
 
 static PITState *pit; /* PIT i8254 */
 
-/*i8254 PIT is attached to the IRQ0 at PIC i8259 */
+/* i8254 PIT is attached to the IRQ0 at PIC i8259 */
 
 static struct _loaderparams {
     int ram_size;
@@ -268,7 +268,6 @@
 		     hd[MAX_IDE_DEVS * i + 1]);
 
     i8042_init(i8259[1], i8259[12], 0x60);
-    ds1225y_init(0x9000, "nvram");
 }
 
 QEMUMachine mips_machine = {

Modified: trunk/src/host/qemu-neo1973/hw/omap.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/omap.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/omap.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -402,38 +402,53 @@
 }
 
 /* OMAP1 DMA module */
-typedef enum {
-    constant = 0,
-    post_incremented,
-    single_index,
-    double_index,
-} omap_dma_addressing_t;
-
 struct omap_dma_channel_s {
+    /* transfer data */
     int burst[2];
     int pack[2];
     enum omap_dma_port port[2];
     target_phys_addr_t addr[2];
     omap_dma_addressing_t mode[2];
+    uint16_t elements;
+    uint16_t frames;
+    int16_t frame_index[2];
+    int16_t element_index[2];
     int data_type;
+
+    /* transfer type */
+    int transparent_copy;
+    int constant_fill;
+    uint32_t color;
+
+    /* auto init and linked channel data */
     int end_prog;
     int repeat;
     int auto_init;
-    int priority;
-    int fs;
-    int sync;
-    int running;
+    int link_enabled;
+    int link_next_ch;
+
+    /* interruption data */
     int interrupts;
     int status;
-    int signalled;
-    int post_sync;
-    int transfer;
-    uint16_t elements;
-    uint16_t frames;
-    uint16_t frame_index;
-    uint16_t element_index;
+
+    /* state data */
+    int active;
+    int enable;
+    int sync;
+    int pending_request;
+    int waiting_end_prog;
     uint16_t cpc;
 
+    /* sync type */
+    int fs;
+    int bs;
+
+    /* compatibility */
+    int omap_3_1_compatible_disable;
+
+    qemu_irq irq;
+    struct omap_dma_channel_s *sibling;
+
     struct omap_dma_reg_set_s {
         target_phys_addr_t src, dest;
         int frame;
@@ -443,16 +458,22 @@
         int frames;
         int elements;
     } active_set;
+
+    /* unused parameters */
+    int priority;
+    int interleave_disabled;
+    int type;
 };
 
 struct omap_dma_s {
-    qemu_irq *ih;
     QEMUTimer *tm;
     struct omap_mpu_state_s *mpu;
     target_phys_addr_t base;
     omap_clk clk;
     int64_t delay;
     uint32_t drq;
+    enum omap_dma_model model;
+    int omap_3_1_mapping_disabled;
 
     uint16_t gcr;
     int run_count;
@@ -462,223 +483,302 @@
     struct omap_dma_lcd_channel_s lcd_ch;
 };
 
+/* Interrupts */
+#define TIMEOUT_INTR    (1 << 0)
+#define EVENT_DROP_INTR (1 << 1)
+#define HALF_FRAME_INTR (1 << 2)
+#define END_FRAME_INTR  (1 << 3)
+#define LAST_FRAME_INTR (1 << 4)
+#define END_BLOCK_INTR  (1 << 5)
+#define SYNC            (1 << 6)
+
 static void omap_dma_interrupts_update(struct omap_dma_s *s)
 {
-    /* First three interrupts are shared between two channels each.  */
-    qemu_set_irq(s->ih[OMAP_INT_DMA_CH0_6],
-                    (s->ch[0].status | s->ch[6].status) & 0x3f);
-    qemu_set_irq(s->ih[OMAP_INT_DMA_CH1_7],
-                    (s->ch[1].status | s->ch[7].status) & 0x3f);
-    qemu_set_irq(s->ih[OMAP_INT_DMA_CH2_8],
-                    (s->ch[2].status | s->ch[8].status) & 0x3f);
-    qemu_set_irq(s->ih[OMAP_INT_DMA_CH3],
-                    (s->ch[3].status) & 0x3f);
-    qemu_set_irq(s->ih[OMAP_INT_DMA_CH4],
-                    (s->ch[4].status) & 0x3f);
-    qemu_set_irq(s->ih[OMAP_INT_DMA_CH5],
-                    (s->ch[5].status) & 0x3f);
+    struct omap_dma_channel_s *ch = s->ch;
+    int i;
+
+    if (s->omap_3_1_mapping_disabled) {
+        for (i = 0; i < s->chans; i ++, ch ++)
+            if (ch->status)
+                qemu_irq_raise(ch->irq);
+    } else {
+        /* First three interrupts are shared between two channels each. */
+        for (i = 0; i < 6; i ++, ch ++) {
+            if (ch->status || (ch->sibling && ch->sibling->status))
+                qemu_irq_raise(ch->irq);
+        }
+    }
 }
 
-static void omap_dma_channel_load(struct omap_dma_s *s, int ch)
+static void omap_dma_channel_load(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
 {
-    struct omap_dma_reg_set_s *a = &s->ch[ch].active_set;
+    struct omap_dma_reg_set_s *a = &ch->active_set;
     int i;
+    int omap_3_1 = !ch->omap_3_1_compatible_disable;
 
     /*
      * TODO: verify address ranges and alignment
      * TODO: port endianness
      */
 
-    a->src = s->ch[ch].addr[0];
-    a->dest = s->ch[ch].addr[1];
-    a->frames = s->ch[ch].frames;
-    a->elements = s->ch[ch].elements;
+    a->src = ch->addr[0];
+    a->dest = ch->addr[1];
+    a->frames = ch->frames;
+    a->elements = ch->elements;
     a->frame = 0;
     a->element = 0;
 
-    if (unlikely(!s->ch[ch].elements || !s->ch[ch].frames)) {
+    if (unlikely(!ch->elements || !ch->frames)) {
         printf("%s: bad DMA request\n", __FUNCTION__);
         return;
     }
 
     for (i = 0; i < 2; i ++)
-        switch (s->ch[ch].mode[i]) {
+        switch (ch->mode[i]) {
         case constant:
             a->elem_delta[i] = 0;
             a->frame_delta[i] = 0;
             break;
         case post_incremented:
-            a->elem_delta[i] = s->ch[ch].data_type;
+            a->elem_delta[i] = ch->data_type;
             a->frame_delta[i] = 0;
             break;
         case single_index:
-            a->elem_delta[i] = s->ch[ch].data_type +
-                s->ch[ch].element_index - 1;
-            if (s->ch[ch].element_index > 0x7fff)
-                a->elem_delta[i] -= 0x10000;
+            a->elem_delta[i] = ch->data_type +
+                    ch->element_index[omap_3_1 ? 0 : i] - 1;
             a->frame_delta[i] = 0;
             break;
         case double_index:
-            a->elem_delta[i] = s->ch[ch].data_type +
-                s->ch[ch].element_index - 1;
-            if (s->ch[ch].element_index > 0x7fff)
-                a->elem_delta[i] -= 0x10000;
-            a->frame_delta[i] = s->ch[ch].frame_index -
-                s->ch[ch].element_index;
-            if (s->ch[ch].frame_index > 0x7fff)
-                a->frame_delta[i] -= 0x10000;
+            a->elem_delta[i] = ch->data_type +
+                    ch->element_index[omap_3_1 ? 0 : i] - 1;
+            a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] -
+                    ch->element_index[omap_3_1 ? 0 : i];
             break;
         default:
             break;
         }
 }
 
-static inline void omap_dma_request_run(struct omap_dma_s *s,
-                int channel, int request)
+static void omap_dma_activate_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
 {
-next_channel:
-    if (request > 0)
-        for (; channel < 9; channel ++)
-            if (s->ch[channel].sync == request && s->ch[channel].running)
-                break;
-    if (channel >= 9)
+    if (!ch->active) {
+        ch->active = 1;
+        if (ch->sync)
+            ch->status |= SYNC;
+        s->run_count ++;
+    }
+
+    if (s->delay && !qemu_timer_pending(s->tm))
+        qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
+}
+
+static void omap_dma_deactivate_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    /* Update cpc */
+    ch->cpc = ch->active_set.dest & 0xffff;
+
+    if (ch->pending_request && !ch->waiting_end_prog) {
+        /* Don't deactivate the channel */
+        ch->pending_request = 0;
         return;
+    }
 
-    if (s->ch[channel].transfer) {
-        if (request > 0) {
-            s->ch[channel ++].post_sync = request;
-            goto next_channel;
-        }
-        s->ch[channel].status |= 0x02;	/* Synchronisation drop */
-        omap_dma_interrupts_update(s);
+    /* Don't deactive the channel if it is synchronized and the DMA request is
+       active */
+    if (ch->sync && (s->drq & (1 << ch->sync)))
         return;
+
+    if (ch->active) {
+        ch->active = 0;
+        ch->status &= ~SYNC;
+        s->run_count --;
     }
 
-    if (!s->ch[channel].signalled)
-        s->run_count ++;
-    s->ch[channel].signalled = 1;
+    if (!s->run_count)
+        qemu_del_timer(s->tm);
+}
 
-    if (request > 0)
-        s->ch[channel].status |= 0x40;	/* External request */
+static void omap_dma_enable_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (!ch->enable) {
+        ch->enable = 1;
+        ch->waiting_end_prog = 0;
+        omap_dma_channel_load(s, ch);
+        if ((!ch->sync) || (s->drq & (1 << ch->sync)))
+            omap_dma_activate_channel(s, ch);
+    }
+}
 
-    if (s->delay && !qemu_timer_pending(s->tm))
-        qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
+static void omap_dma_disable_channel(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (ch->enable) {
+        ch->enable = 0;
+        /* Discard any pending request */
+        ch->pending_request = 0;
+        omap_dma_deactivate_channel(s, ch);
+    }
+}
 
-    if (request > 0) {
-        channel ++;
-        goto next_channel;
+static void omap_dma_channel_end_prog(struct omap_dma_s *s,
+                struct omap_dma_channel_s *ch)
+{
+    if (ch->waiting_end_prog) {
+        ch->waiting_end_prog = 0;
+        if (!ch->sync || ch->pending_request) {
+            ch->pending_request = 0;
+            omap_dma_activate_channel(s, ch);
+        }
     }
 }
 
-static inline void omap_dma_request_stop(struct omap_dma_s *s, int channel)
+static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s)
 {
-    if (s->ch[channel].signalled)
-        s->run_count --;
-    s->ch[channel].signalled = 0;
+    s->omap_3_1_mapping_disabled = 0;
+    s->chans = 9;
+}
 
-    if (!s->run_count)
-        qemu_del_timer(s->tm);
+static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s)
+{
+    s->omap_3_1_mapping_disabled = 1;
+    s->chans = 16;
 }
 
+static void omap_dma_process_request(struct omap_dma_s *s, int request)
+{
+    int channel;
+    int drop_event = 0;
+    struct omap_dma_channel_s *ch = s->ch;
+
+    for (channel = 0; channel < s->chans; channel ++, ch ++) {
+        if (ch->enable && ch->sync == request) {
+            if (!ch->active)
+                omap_dma_activate_channel(s, ch);
+            else if (!ch->pending_request)
+                ch->pending_request = 1;
+            else {
+                /* Request collision */
+                /* Second request received while processing other request */
+                ch->status |= EVENT_DROP_INTR;
+                drop_event = 1;
+            }
+        }
+    }
+
+    if (drop_event)
+        omap_dma_interrupts_update(s);
+}
+
 static void omap_dma_channel_run(struct omap_dma_s *s)
 {
-    int ch;
+    int n = s->chans;
     uint16_t status;
     uint8_t value[4];
     struct omap_dma_port_if_s *src_p, *dest_p;
     struct omap_dma_reg_set_s *a;
+    struct omap_dma_channel_s *ch;
 
-    for (ch = 0; ch < 9; ch ++) {
-        a = &s->ch[ch].active_set;
+    for (ch = s->ch; n; n --, ch ++) {
+        if (!ch->active)
+            continue;
 
-        src_p = &s->mpu->port[s->ch[ch].port[0]];
-        dest_p = &s->mpu->port[s->ch[ch].port[1]];
-        if (s->ch[ch].signalled && (!src_p->addr_valid(s->mpu, a->src) ||
-                    !dest_p->addr_valid(s->mpu, a->dest))) {
+        a = &ch->active_set;
+
+        src_p = &s->mpu->port[ch->port[0]];
+        dest_p = &s->mpu->port[ch->port[1]];
+        if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) ||
+                        (!dest_p->addr_valid(s->mpu, a->dest))) {
 #if 0
             /* Bus time-out */
-            if (s->ch[ch].interrupts & 0x01)
-                s->ch[ch].status |= 0x01;
-            omap_dma_request_stop(s, ch);
+            if (ch->interrupts & TIMEOUT_INTR)
+                ch->status |= TIMEOUT_INTR;
+            omap_dma_deactivate_channel(s, ch);
             continue;
 #endif
-            printf("%s: Bus time-out in DMA%i operation\n", __FUNCTION__, ch);
+            printf("%s: Bus time-out in DMA%i operation\n",
+                            __FUNCTION__, s->chans - n);
         }
 
-        status = s->ch[ch].status;
-        while (status == s->ch[ch].status && s->ch[ch].signalled) {
+        status = ch->status;
+        while (status == ch->status && ch->active) {
             /* Transfer a single element */
-            s->ch[ch].transfer = 1;
-            cpu_physical_memory_read(a->src, value, s->ch[ch].data_type);
-            cpu_physical_memory_write(a->dest, value, s->ch[ch].data_type);
-            s->ch[ch].transfer = 0;
+            /* FIXME: check the endianness */
+            if (!ch->constant_fill)
+                cpu_physical_memory_read(a->src, value, ch->data_type);
+            else
+                *(uint32_t *) value = ch->color;
 
+            if (!ch->transparent_copy ||
+                    *(uint32_t *) value != ch->color)
+                cpu_physical_memory_write(a->dest, value, ch->data_type);
+
             a->src += a->elem_delta[0];
             a->dest += a->elem_delta[1];
             a->element ++;
 
-            /* Check interrupt conditions */
+            /* If the channel is element synchronized, deactivate it */
+            if (ch->sync && !ch->fs && !ch->bs)
+                omap_dma_deactivate_channel(s, ch);
+
+            /* If it is the last frame, set the LAST_FRAME interrupt */
+            if (a->element == 1 && a->frame == a->frames - 1)
+                if (ch->interrupts & LAST_FRAME_INTR)
+                    ch->status |= LAST_FRAME_INTR;
+
+            /* If the half of the frame was reached, set the HALF_FRAME
+               interrupt */
+            if (a->element == (a->elements >> 1))
+                if (ch->interrupts & HALF_FRAME_INTR)
+                    ch->status |= HALF_FRAME_INTR;
+
             if (a->element == a->elements) {
+                /* End of Frame */
                 a->element = 0;
                 a->src += a->frame_delta[0];
                 a->dest += a->frame_delta[1];
                 a->frame ++;
 
-                if (a->frame == a->frames) {
-                    if (!s->ch[ch].repeat || !s->ch[ch].auto_init)
-                        s->ch[ch].running = 0;
+                /* If the channel is frame synchronized, deactivate it */
+                if (ch->sync && ch->fs)
+                    omap_dma_deactivate_channel(s, ch);
 
-                    if (s->ch[ch].auto_init &&
-                            (s->ch[ch].repeat ||
-                             s->ch[ch].end_prog))
-                        omap_dma_channel_load(s, ch);
+                /* If the channel is async, update cpc */
+                if (!ch->sync)
+                    ch->cpc = a->dest & 0xffff;
 
-                    if (s->ch[ch].interrupts & 0x20)
-                        s->ch[ch].status |= 0x20;
+                /* Set the END_FRAME interrupt */
+                if (ch->interrupts & END_FRAME_INTR)
+                    ch->status |= END_FRAME_INTR;
 
-                    if (!s->ch[ch].sync)
-                        omap_dma_request_stop(s, ch);
-                }
+                if (a->frame == a->frames) {
+                    /* End of Block */
+                    /* Disable the channel */
 
-                if (s->ch[ch].interrupts & 0x08)
-                    s->ch[ch].status |= 0x08;
+                    if (ch->omap_3_1_compatible_disable) {
+                        omap_dma_disable_channel(s, ch);
+                        if (ch->link_enabled)
+                            omap_dma_enable_channel(s,
+                                            &s->ch[ch->link_next_ch]);
+                    } else {
+                        if (!ch->auto_init)
+                            omap_dma_disable_channel(s, ch);
+                        else if (ch->repeat || ch->end_prog)
+                            omap_dma_channel_load(s, ch);
+                        else {
+                            ch->waiting_end_prog = 1;
+                            omap_dma_deactivate_channel(s, ch);
+                        }
+                    }
 
-                if (s->ch[ch].sync && s->ch[ch].fs &&
-                                !(s->drq & (1 << s->ch[ch].sync))) {
-                    s->ch[ch].status &= ~0x40;
-                    omap_dma_request_stop(s, ch);
+                    if (ch->interrupts & END_BLOCK_INTR)
+                        ch->status |= END_BLOCK_INTR;
                 }
             }
-
-            if (a->element == 1 && a->frame == a->frames - 1)
-                if (s->ch[ch].interrupts & 0x10)
-                    s->ch[ch].status |= 0x10;
-
-            if (a->element == (a->elements >> 1))
-                if (s->ch[ch].interrupts & 0x04)
-                    s->ch[ch].status |= 0x04;
-
-            if (s->ch[ch].sync && !s->ch[ch].fs &&
-                            !(s->drq & (1 << s->ch[ch].sync))) {
-                s->ch[ch].status &= ~0x40;
-                omap_dma_request_stop(s, ch);
-            }
-
-            /*
-             * Process requests made while the element was
-             * being transferred.
-             */
-            if (s->ch[ch].post_sync) {
-                omap_dma_request_run(s, 0, s->ch[ch].post_sync);
-                s->ch[ch].post_sync = 0;
-            }
-
-#if 0
-            break;
-#endif
         }
-
-        s->ch[ch].cpc = a->dest & 0x0000ffff;
     }
 
     omap_dma_interrupts_update(s);
@@ -686,77 +786,176 @@
         qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
 }
 
+static void omap_dma_reset(struct omap_dma_s *s)
+{
+    int i;
+
+    qemu_del_timer(s->tm);
+    s->gcr = 0x0004;
+    s->drq = 0x00000000;
+    s->run_count = 0;
+    s->lcd_ch.src = emiff;
+    s->lcd_ch.condition = 0;
+    s->lcd_ch.interrupts = 0;
+    s->lcd_ch.dual = 0;
+    omap_dma_enable_3_1_mapping(s);
+    for (i = 0; i < s->chans; i ++) {
+        memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst));
+        memset(&s->ch[i].port, 0, sizeof(s->ch[i].port));
+        memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode));
+        memset(&s->ch[i].elements, 0, sizeof(s->ch[i].elements));
+        memset(&s->ch[i].frames, 0, sizeof(s->ch[i].frames));
+        memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index));
+        memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index));
+        memset(&s->ch[i].data_type, 0, sizeof(s->ch[i].data_type));
+        memset(&s->ch[i].transparent_copy, 0,
+                        sizeof(s->ch[i].transparent_copy));
+        memset(&s->ch[i].constant_fill, 0, sizeof(s->ch[i].constant_fill));
+        memset(&s->ch[i].color, 0, sizeof(s->ch[i].color));
+        memset(&s->ch[i].end_prog, 0, sizeof(s->ch[i].end_prog));
+        memset(&s->ch[i].repeat, 0, sizeof(s->ch[i].repeat));
+        memset(&s->ch[i].auto_init, 0, sizeof(s->ch[i].auto_init));
+        memset(&s->ch[i].link_enabled, 0, sizeof(s->ch[i].link_enabled));
+        memset(&s->ch[i].link_next_ch, 0, sizeof(s->ch[i].link_next_ch));
+        s->ch[i].interrupts = 0x0003;
+        memset(&s->ch[i].status, 0, sizeof(s->ch[i].status));
+        memset(&s->ch[i].active, 0, sizeof(s->ch[i].active));
+        memset(&s->ch[i].enable, 0, sizeof(s->ch[i].enable));
+        memset(&s->ch[i].sync, 0, sizeof(s->ch[i].sync));
+        memset(&s->ch[i].pending_request, 0, sizeof(s->ch[i].pending_request));
+        memset(&s->ch[i].waiting_end_prog, 0,
+                        sizeof(s->ch[i].waiting_end_prog));
+        memset(&s->ch[i].cpc, 0, sizeof(s->ch[i].cpc));
+        memset(&s->ch[i].fs, 0, sizeof(s->ch[i].fs));
+        memset(&s->ch[i].bs, 0, sizeof(s->ch[i].bs));
+        memset(&s->ch[i].omap_3_1_compatible_disable, 0,
+                        sizeof(s->ch[i].omap_3_1_compatible_disable));
+        memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set));
+        memset(&s->ch[i].priority, 0, sizeof(s->ch[i].priority));
+        memset(&s->ch[i].interleave_disabled, 0,
+                        sizeof(s->ch[i].interleave_disabled));
+        memset(&s->ch[i].type, 0, sizeof(s->ch[i].type));
+    }
+}
+
 static int omap_dma_ch_reg_read(struct omap_dma_s *s,
-                int ch, int reg, uint16_t *value) {
+                struct omap_dma_channel_s *ch, int reg, uint16_t *value)
+{
     switch (reg) {
     case 0x00:	/* SYS_DMA_CSDP_CH0 */
-        *value = (s->ch[ch].burst[1] << 14) |
-                (s->ch[ch].pack[1] << 13) |
-                (s->ch[ch].port[1] << 9) |
-                (s->ch[ch].burst[0] << 7) |
-                (s->ch[ch].pack[0] << 6) |
-                (s->ch[ch].port[0] << 2) |
-                (s->ch[ch].data_type >> 1);
+        *value = (ch->burst[1] << 14) |
+                (ch->pack[1] << 13) |
+                (ch->port[1] << 9) |
+                (ch->burst[0] << 7) |
+                (ch->pack[0] << 6) |
+                (ch->port[0] << 2) |
+                (ch->data_type >> 1);
         break;
 
     case 0x02:	/* SYS_DMA_CCR_CH0 */
-        *value = (s->ch[ch].mode[1] << 14) |
-                (s->ch[ch].mode[0] << 12) |
-                (s->ch[ch].end_prog << 11) |
-                (s->ch[ch].repeat << 9) |
-                (s->ch[ch].auto_init << 8) |
-                (s->ch[ch].running << 7) |
-                (s->ch[ch].priority << 6) |
-                (s->ch[ch].fs << 5) | s->ch[ch].sync;
+        if (s->model == omap_dma_3_1)
+            *value = 0 << 10;			/* FIFO_FLUSH reads as 0 */
+        else
+            *value = ch->omap_3_1_compatible_disable << 10;
+        *value |= (ch->mode[1] << 14) |
+                (ch->mode[0] << 12) |
+                (ch->end_prog << 11) |
+                (ch->repeat << 9) |
+                (ch->auto_init << 8) |
+                (ch->enable << 7) |
+                (ch->priority << 6) |
+                (ch->fs << 5) | ch->sync;
         break;
 
     case 0x04:	/* SYS_DMA_CICR_CH0 */
-        *value = s->ch[ch].interrupts;
+        *value = ch->interrupts;
         break;
 
     case 0x06:	/* SYS_DMA_CSR_CH0 */
-        /* FIXME: shared CSR for channels sharing the interrupts */
-        *value = s->ch[ch].status;
-        s->ch[ch].status &= 0x40;
-        omap_dma_interrupts_update(s);
+        *value = ch->status;
+        ch->status &= SYNC;
+        if (!ch->omap_3_1_compatible_disable && ch->sibling) {
+            *value |= (ch->sibling->status & 0x3f) << 6;
+            ch->sibling->status &= SYNC;
+        }
+        qemu_irq_lower(ch->irq);
         break;
 
     case 0x08:	/* SYS_DMA_CSSA_L_CH0 */
-        *value = s->ch[ch].addr[0] & 0x0000ffff;
+        *value = ch->addr[0] & 0x0000ffff;
         break;
 
     case 0x0a:	/* SYS_DMA_CSSA_U_CH0 */
-        *value = s->ch[ch].addr[0] >> 16;
+        *value = ch->addr[0] >> 16;
         break;
 
     case 0x0c:	/* SYS_DMA_CDSA_L_CH0 */
-        *value = s->ch[ch].addr[1] & 0x0000ffff;
+        *value = ch->addr[1] & 0x0000ffff;
         break;
 
     case 0x0e:	/* SYS_DMA_CDSA_U_CH0 */
-        *value = s->ch[ch].addr[1] >> 16;
+        *value = ch->addr[1] >> 16;
         break;
 
     case 0x10:	/* SYS_DMA_CEN_CH0 */
-        *value = s->ch[ch].elements;
+        *value = ch->elements;
         break;
 
     case 0x12:	/* SYS_DMA_CFN_CH0 */
-        *value = s->ch[ch].frames;
+        *value = ch->frames;
         break;
 
     case 0x14:	/* SYS_DMA_CFI_CH0 */
-        *value = s->ch[ch].frame_index;
+        *value = ch->frame_index[0];
         break;
 
     case 0x16:	/* SYS_DMA_CEI_CH0 */
-        *value = s->ch[ch].element_index;
+        *value = ch->element_index[0];
         break;
 
-    case 0x18:	/* SYS_DMA_CPC_CH0 */
-        *value = s->ch[ch].cpc;
+    case 0x18:	/* SYS_DMA_CPC_CH0 or DMA_CSAC */
+        if (ch->omap_3_1_compatible_disable)
+            *value = ch->active_set.src & 0xffff;	/* CSAC */
+        else
+            *value = ch->cpc;
         break;
 
+    case 0x1a:	/* DMA_CDAC */
+        *value = ch->active_set.dest & 0xffff;	/* CDAC */
+        break;
+
+    case 0x1c:	/* DMA_CDEI */
+        *value = ch->element_index[1];
+        break;
+
+    case 0x1e:	/* DMA_CDFI */
+        *value = ch->frame_index[1];
+        break;
+
+    case 0x20:	/* DMA_COLOR_L */
+        *value = ch->color & 0xffff;
+        break;
+
+    case 0x22:	/* DMA_COLOR_U */
+        *value = ch->color >> 16;
+        break;
+
+    case 0x24:	/* DMA_CCR2 */
+        *value = (ch->bs << 2) |
+                (ch->transparent_copy << 1) |
+                ch->constant_fill;
+        break;
+
+    case 0x28:	/* DMA_CLNK_CTRL */
+        *value = (ch->link_enabled << 15) |
+                (ch->link_next_ch & 0xf);
+        break;
+
+    case 0x2a:	/* DMA_LCH_CTRL */
+        *value = (ch->interleave_disabled << 15) |
+                ch->type;
+        break;
+
     default:
         return 1;
     }
@@ -764,228 +963,690 @@
 }
 
 static int omap_dma_ch_reg_write(struct omap_dma_s *s,
-                int ch, int reg, uint16_t value) {
+                struct omap_dma_channel_s *ch, int reg, uint16_t value)
+{
     switch (reg) {
     case 0x00:	/* SYS_DMA_CSDP_CH0 */
-        s->ch[ch].burst[1] = (value & 0xc000) >> 14;
-        s->ch[ch].pack[1] = (value & 0x2000) >> 13;
-        s->ch[ch].port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
-        s->ch[ch].burst[0] = (value & 0x0180) >> 7;
-        s->ch[ch].pack[0] = (value & 0x0040) >> 6;
-        s->ch[ch].port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
-        s->ch[ch].data_type = (1 << (value & 3));
-        if (s->ch[ch].port[0] >= omap_dma_port_last)
+        ch->burst[1] = (value & 0xc000) >> 14;
+        ch->pack[1] = (value & 0x2000) >> 13;
+        ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
+        ch->burst[0] = (value & 0x0180) >> 7;
+        ch->pack[0] = (value & 0x0040) >> 6;
+        ch->port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
+        ch->data_type = (1 << (value & 3));
+        if (ch->port[0] >= omap_dma_port_last)
             printf("%s: invalid DMA port %i\n", __FUNCTION__,
-                            s->ch[ch].port[0]);
-        if (s->ch[ch].port[1] >= omap_dma_port_last)
+                            ch->port[0]);
+        if (ch->port[1] >= omap_dma_port_last)
             printf("%s: invalid DMA port %i\n", __FUNCTION__,
-                            s->ch[ch].port[1]);
+                            ch->port[1]);
         if ((value & 3) == 3)
-            printf("%s: bad data_type for DMA channel %i\n", __FUNCTION__, ch);
+            printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
         break;
 
     case 0x02:	/* SYS_DMA_CCR_CH0 */
-        s->ch[ch].mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
-        s->ch[ch].mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
-        s->ch[ch].end_prog = (value & 0x0800) >> 11;
-        s->ch[ch].repeat = (value & 0x0200) >> 9;
-        s->ch[ch].auto_init = (value & 0x0100) >> 8;
-        s->ch[ch].priority = (value & 0x0040) >> 6;
-        s->ch[ch].fs = (value & 0x0020) >> 5;
-        s->ch[ch].sync = value & 0x001f;
-        if (value & 0x0080) {
-            if (s->ch[ch].running) {
-                if (!s->ch[ch].signalled &&
-                                s->ch[ch].auto_init && s->ch[ch].end_prog)
-                    omap_dma_channel_load(s, ch);
-            } else {
-                s->ch[ch].running = 1;
-                omap_dma_channel_load(s, ch);
-            }
-            if (!s->ch[ch].sync || (s->drq & (1 << s->ch[ch].sync)))
-                omap_dma_request_run(s, ch, 0);
-        } else {
-            s->ch[ch].running = 0;
-            omap_dma_request_stop(s, ch);
-        }
+        ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        ch->end_prog = (value & 0x0800) >> 11;
+        if (s->model > omap_dma_3_1)
+            ch->omap_3_1_compatible_disable  = (value >> 10) & 0x1;
+        ch->repeat = (value & 0x0200) >> 9;
+        ch->auto_init = (value & 0x0100) >> 8;
+        ch->priority = (value & 0x0040) >> 6;
+        ch->fs = (value & 0x0020) >> 5;
+        ch->sync = value & 0x001f;
+
+        if (value & 0x0080)
+            omap_dma_enable_channel(s, ch);
+        else
+            omap_dma_disable_channel(s, ch);
+
+        if (ch->end_prog)
+            omap_dma_channel_end_prog(s, ch);
+
         break;
 
     case 0x04:	/* SYS_DMA_CICR_CH0 */
-        s->ch[ch].interrupts = value & 0x003f;
+        ch->interrupts = value;
         break;
 
     case 0x06:	/* SYS_DMA_CSR_CH0 */
-        return 1;
+        OMAP_RO_REG((target_phys_addr_t) reg);
+        break;
 
     case 0x08:	/* SYS_DMA_CSSA_L_CH0 */
-        s->ch[ch].addr[0] &= 0xffff0000;
-        s->ch[ch].addr[0] |= value;
+        ch->addr[0] &= 0xffff0000;
+        ch->addr[0] |= value;
         break;
 
     case 0x0a:	/* SYS_DMA_CSSA_U_CH0 */
-        s->ch[ch].addr[0] &= 0x0000ffff;
-        s->ch[ch].addr[0] |= (uint32_t) value << 16;
+        ch->addr[0] &= 0x0000ffff;
+        ch->addr[0] |= (uint32_t) value << 16;
         break;
 
     case 0x0c:	/* SYS_DMA_CDSA_L_CH0 */
-        s->ch[ch].addr[1] &= 0xffff0000;
-        s->ch[ch].addr[1] |= value;
+        ch->addr[1] &= 0xffff0000;
+        ch->addr[1] |= value;
         break;
 
     case 0x0e:	/* SYS_DMA_CDSA_U_CH0 */
-        s->ch[ch].addr[1] &= 0x0000ffff;
-        s->ch[ch].addr[1] |= (uint32_t) value << 16;
+        ch->addr[1] &= 0x0000ffff;
+        ch->addr[1] |= (uint32_t) value << 16;
         break;
 
     case 0x10:	/* SYS_DMA_CEN_CH0 */
-        s->ch[ch].elements = value & 0xffff;
+        ch->elements = value;
         break;
 
     case 0x12:	/* SYS_DMA_CFN_CH0 */
-        s->ch[ch].frames = value & 0xffff;
+        ch->frames = value;
         break;
 
     case 0x14:	/* SYS_DMA_CFI_CH0 */
-        s->ch[ch].frame_index = value & 0xffff;
+        ch->frame_index[0] = (int16_t) value;
         break;
 
     case 0x16:	/* SYS_DMA_CEI_CH0 */
-        s->ch[ch].element_index = value & 0xffff;
+        ch->element_index[0] = (int16_t) value;
         break;
 
-    case 0x18:	/* SYS_DMA_CPC_CH0 */
+    case 0x18:	/* SYS_DMA_CPC_CH0 or DMA_CSAC */
+        OMAP_RO_REG((target_phys_addr_t) reg);
+        break;
+
+    case 0x1c:	/* DMA_CDEI */
+        ch->element_index[1] = (int16_t) value;
+        break;
+
+    case 0x1e:	/* DMA_CDFI */
+        ch->frame_index[1] = (int16_t) value;
+        break;
+
+    case 0x20:	/* DMA_COLOR_L */
+        ch->color &= 0xffff0000;
+        ch->color |= value;
+        break;
+
+    case 0x22:	/* DMA_COLOR_U */
+        ch->color &= 0xffff;
+        ch->color |= value << 16;
+        break;
+
+    case 0x24:	/* DMA_CCR2 */
+        ch->bs  = (value >> 2) & 0x1;
+        ch->transparent_copy = (value >> 1) & 0x1;
+        ch->constant_fill = value & 0x1;
+        break;
+
+    case 0x28:	/* DMA_CLNK_CTRL */
+        ch->link_enabled = (value >> 15) & 0x1;
+        if (value & (1 << 14)) {			/* Stop_Lnk */
+            ch->link_enabled = 0;
+            omap_dma_disable_channel(s, ch);
+        }
+        ch->link_next_ch = value & 0x1f;
+        break;
+
+    case 0x2a:	/* DMA_LCH_CTRL */
+        ch->interleave_disabled = (value >> 15) & 0x1;
+        ch->type = value & 0xf;
+        break;
+
+    default:
         return 1;
+    }
+    return 0;
+}
 
+static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t value)
+{
+    switch (offset) {
+    case 0xbc0:	/* DMA_LCD_CSDP */
+        s->brust_f2 = (value >> 14) & 0x3;
+        s->pack_f2 = (value >> 13) & 0x1;
+        s->data_type_f2 = (1 << ((value >> 11) & 0x3));
+        s->brust_f1 = (value >> 7) & 0x3;
+        s->pack_f1 = (value >> 6) & 0x1;
+        s->data_type_f1 = (1 << ((value >> 0) & 0x3));
+        break;
+
+    case 0xbc2:	/* DMA_LCD_CCR */
+        s->mode_f2 = (value >> 14) & 0x3;
+        s->mode_f1 = (value >> 12) & 0x3;
+        s->end_prog = (value >> 11) & 0x1;
+        s->omap_3_1_compatible_disable = (value >> 10) & 0x1;
+        s->repeat = (value >> 9) & 0x1;
+        s->auto_init = (value >> 8) & 0x1;
+        s->running = (value >> 7) & 0x1;
+        s->priority = (value >> 6) & 0x1;
+        s->bs = (value >> 4) & 0x1;
+        break;
+
+    case 0xbc4:	/* DMA_LCD_CTRL */
+        s->dst = (value >> 8) & 0x1;
+        s->src = ((value >> 6) & 0x3) << 1;
+        s->condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->interrupts = (value >> 1) & 1;
+        s->dual = value & 1;
+        break;
+
+    case 0xbc8:	/* TOP_B1_L */
+        s->src_f1_top &= 0xffff0000;
+        s->src_f1_top |= 0x0000ffff & value;
+        break;
+
+    case 0xbca:	/* TOP_B1_U */
+        s->src_f1_top &= 0x0000ffff;
+        s->src_f1_top |= value << 16;
+        break;
+
+    case 0xbcc:	/* BOT_B1_L */
+        s->src_f1_bottom &= 0xffff0000;
+        s->src_f1_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0xbce:	/* BOT_B1_U */
+        s->src_f1_bottom &= 0x0000ffff;
+        s->src_f1_bottom |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd0:	/* TOP_B2_L */
+        s->src_f2_top &= 0xffff0000;
+        s->src_f2_top |= 0x0000ffff & value;
+        break;
+
+    case 0xbd2:	/* TOP_B2_U */
+        s->src_f2_top &= 0x0000ffff;
+        s->src_f2_top |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd4:	/* BOT_B2_L */
+        s->src_f2_bottom &= 0xffff0000;
+        s->src_f2_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0xbd6:	/* BOT_B2_U */
+        s->src_f2_bottom &= 0x0000ffff;
+        s->src_f2_bottom |= (uint32_t) value << 16;
+        break;
+
+    case 0xbd8:	/* DMA_LCD_SRC_EI_B1 */
+        s->element_index_f1 = value;
+        break;
+
+    case 0xbda:	/* DMA_LCD_SRC_FI_B1_L */
+        s->frame_index_f1 &= 0xffff0000;
+        s->frame_index_f1 |= 0x0000ffff & value;
+        break;
+
+    case 0xbf4:	/* DMA_LCD_SRC_FI_B1_U */
+        s->frame_index_f1 &= 0x0000ffff;
+        s->frame_index_f1 |= (uint32_t) value << 16;
+        break;
+
+    case 0xbdc:	/* DMA_LCD_SRC_EI_B2 */
+        s->element_index_f2 = value;
+        break;
+
+    case 0xbde:	/* DMA_LCD_SRC_FI_B2_L */
+        s->frame_index_f2 &= 0xffff0000;
+        s->frame_index_f2 |= 0x0000ffff & value;
+        break;
+
+    case 0xbf6:	/* DMA_LCD_SRC_FI_B2_U */
+        s->frame_index_f2 &= 0x0000ffff;
+        s->frame_index_f2 |= (uint32_t) value << 16;
+        break;
+
+    case 0xbe0:	/* DMA_LCD_SRC_EN_B1 */
+        s->elements_f1 = value;
+        break;
+
+    case 0xbe4:	/* DMA_LCD_SRC_FN_B1 */
+        s->frames_f1 = value;
+        break;
+
+    case 0xbe2:	/* DMA_LCD_SRC_EN_B2 */
+        s->elements_f2 = value;
+        break;
+
+    case 0xbe6:	/* DMA_LCD_SRC_FN_B2 */
+        s->frames_f2 = value;
+        break;
+
+    case 0xbea:	/* DMA_LCD_LCH_CTRL */
+        s->lch_type = value & 0xf;
+        break;
+
     default:
-        OMAP_BAD_REG((target_phys_addr_t) reg);
+        return 1;
     }
     return 0;
 }
 
-static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr)
+static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t *ret)
 {
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int i, reg, ch, offset = addr - s->base;
-    uint16_t ret;
+    switch (offset) {
+    case 0xbc0:	/* DMA_LCD_CSDP */
+        *ret = (s->brust_f2 << 14) |
+            (s->pack_f2 << 13) |
+            ((s->data_type_f2 >> 1) << 11) |
+            (s->brust_f1 << 7) |
+            (s->pack_f1 << 6) |
+            ((s->data_type_f1 >> 1) << 0);
+        break;
 
+    case 0xbc2:	/* DMA_LCD_CCR */
+        *ret = (s->mode_f2 << 14) |
+            (s->mode_f1 << 12) |
+            (s->end_prog << 11) |
+            (s->omap_3_1_compatible_disable << 10) |
+            (s->repeat << 9) |
+            (s->auto_init << 8) |
+            (s->running << 7) |
+            (s->priority << 6) |
+            (s->bs << 4);
+        break;
+
+    case 0xbc4:	/* DMA_LCD_CTRL */
+        qemu_irq_lower(s->irq);
+        *ret = (s->dst << 8) |
+            ((s->src & 0x6) << 5) |
+            (s->condition << 3) |
+            (s->interrupts << 1) |
+            s->dual;
+        break;
+
+    case 0xbc8:	/* TOP_B1_L */
+        *ret = s->src_f1_top & 0xffff;
+        break;
+
+    case 0xbca:	/* TOP_B1_U */
+        *ret = s->src_f1_top >> 16;
+        break;
+
+    case 0xbcc:	/* BOT_B1_L */
+        *ret = s->src_f1_bottom & 0xffff;
+        break;
+
+    case 0xbce:	/* BOT_B1_U */
+        *ret = s->src_f1_bottom >> 16;
+        break;
+
+    case 0xbd0:	/* TOP_B2_L */
+        *ret = s->src_f2_top & 0xffff;
+        break;
+
+    case 0xbd2:	/* TOP_B2_U */
+        *ret = s->src_f2_top >> 16;
+        break;
+
+    case 0xbd4:	/* BOT_B2_L */
+        *ret = s->src_f2_bottom & 0xffff;
+        break;
+
+    case 0xbd6:	/* BOT_B2_U */
+        *ret = s->src_f2_bottom >> 16;
+        break;
+
+    case 0xbd8:	/* DMA_LCD_SRC_EI_B1 */
+        *ret = s->element_index_f1;
+        break;
+
+    case 0xbda:	/* DMA_LCD_SRC_FI_B1_L */
+        *ret = s->frame_index_f1 & 0xffff;
+        break;
+
+    case 0xbf4:	/* DMA_LCD_SRC_FI_B1_U */
+        *ret = s->frame_index_f1 >> 16;
+        break;
+
+    case 0xbdc:	/* DMA_LCD_SRC_EI_B2 */
+        *ret = s->element_index_f2;
+        break;
+
+    case 0xbde:	/* DMA_LCD_SRC_FI_B2_L */
+        *ret = s->frame_index_f2 & 0xffff;
+        break;
+
+    case 0xbf6:	/* DMA_LCD_SRC_FI_B2_U */
+        *ret = s->frame_index_f2 >> 16;
+        break;
+
+    case 0xbe0:	/* DMA_LCD_SRC_EN_B1 */
+        *ret = s->elements_f1;
+        break;
+
+    case 0xbe4:	/* DMA_LCD_SRC_FN_B1 */
+        *ret = s->frames_f1;
+        break;
+
+    case 0xbe2:	/* DMA_LCD_SRC_EN_B2 */
+        *ret = s->elements_f2;
+        break;
+
+    case 0xbe6:	/* DMA_LCD_SRC_FN_B2 */
+        *ret = s->frames_f2;
+        break;
+
+    case 0xbea:	/* DMA_LCD_LCH_CTRL */
+        *ret = s->lch_type;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t value)
+{
     switch (offset) {
-    case 0x000 ... 0x2fe:
-        reg = offset & 0x3f;
-        ch = (offset >> 6) & 0x0f;
-        if (omap_dma_ch_reg_read(s, ch, reg, &ret))
-            break;
-        return ret;
-
     case 0x300:	/* SYS_DMA_LCD_CTRL */
-        i = s->lcd_ch.condition;
-        s->lcd_ch.condition = 0;
-        qemu_irq_lower(s->lcd_ch.irq);
-        return ((s->lcd_ch.src == imif) << 6) | (i << 3) |
-                (s->lcd_ch.interrupts << 1) | s->lcd_ch.dual;
+        s->src = (value & 0x40) ? imif : emiff;
+        s->condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->interrupts = (value >> 1) & 1;
+        s->dual = value & 1;
+        break;
 
     case 0x302:	/* SYS_DMA_LCD_TOP_F1_L */
-        return s->lcd_ch.src_f1_top & 0xffff;
+        s->src_f1_top &= 0xffff0000;
+        s->src_f1_top |= 0x0000ffff & value;
+        break;
 
     case 0x304:	/* SYS_DMA_LCD_TOP_F1_U */
-        return s->lcd_ch.src_f1_top >> 16;
+        s->src_f1_top &= 0x0000ffff;
+        s->src_f1_top |= value << 16;
+        break;
 
     case 0x306:	/* SYS_DMA_LCD_BOT_F1_L */
-        return s->lcd_ch.src_f1_bottom & 0xffff;
+        s->src_f1_bottom &= 0xffff0000;
+        s->src_f1_bottom |= 0x0000ffff & value;
+        break;
 
     case 0x308:	/* SYS_DMA_LCD_BOT_F1_U */
-        return s->lcd_ch.src_f1_bottom >> 16;
+        s->src_f1_bottom &= 0x0000ffff;
+        s->src_f1_bottom |= value << 16;
+        break;
 
     case 0x30a:	/* SYS_DMA_LCD_TOP_F2_L */
-        return s->lcd_ch.src_f2_top & 0xffff;
+        s->src_f2_top &= 0xffff0000;
+        s->src_f2_top |= 0x0000ffff & value;
+        break;
 
     case 0x30c:	/* SYS_DMA_LCD_TOP_F2_U */
-        return s->lcd_ch.src_f2_top >> 16;
+        s->src_f2_top &= 0x0000ffff;
+        s->src_f2_top |= value << 16;
+        break;
 
     case 0x30e:	/* SYS_DMA_LCD_BOT_F2_L */
-        return s->lcd_ch.src_f2_bottom & 0xffff;
+        s->src_f2_bottom &= 0xffff0000;
+        s->src_f2_bottom |= 0x0000ffff & value;
+        break;
 
     case 0x310:	/* SYS_DMA_LCD_BOT_F2_U */
-        return s->lcd_ch.src_f2_bottom >> 16;
+        s->src_f2_bottom &= 0x0000ffff;
+        s->src_f2_bottom |= value << 16;
+        break;
 
-    case 0x400:	/* SYS_DMA_GCR */
-        return s->gcr;
+    default:
+        return 1;
     }
-
-    OMAP_BAD_REG(addr);
     return 0;
 }
 
-static void omap_dma_write(void *opaque, target_phys_addr_t addr,
-                uint32_t value)
+static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset,
+                uint16_t *ret)
 {
-    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
-    int reg, ch, offset = addr - s->base;
+    int i;
 
     switch (offset) {
-    case 0x000 ... 0x2fe:
-        reg = offset & 0x3f;
-        ch = (offset >> 6) & 0x0f;
-        if (omap_dma_ch_reg_write(s, ch, reg, value))
-            OMAP_RO_REG(addr);
-        break;
-
     case 0x300:	/* SYS_DMA_LCD_CTRL */
-        s->lcd_ch.src = (value & 0x40) ? imif : emiff;
-        s->lcd_ch.condition = 0;
-        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
-        s->lcd_ch.interrupts = (value >> 1) & 1;
-        s->lcd_ch.dual = value & 1;
+        i = s->condition;
+        s->condition = 0;
+        qemu_irq_lower(s->irq);
+        *ret = ((s->src == imif) << 6) | (i << 3) |
+                (s->interrupts << 1) | s->dual;
         break;
 
     case 0x302:	/* SYS_DMA_LCD_TOP_F1_L */
-        s->lcd_ch.src_f1_top &= 0xffff0000;
-        s->lcd_ch.src_f1_top |= 0x0000ffff & value;
+        *ret = s->src_f1_top & 0xffff;
         break;
 
     case 0x304:	/* SYS_DMA_LCD_TOP_F1_U */
-        s->lcd_ch.src_f1_top &= 0x0000ffff;
-        s->lcd_ch.src_f1_top |= value << 16;
+        *ret = s->src_f1_top >> 16;
         break;
 
     case 0x306:	/* SYS_DMA_LCD_BOT_F1_L */
-        s->lcd_ch.src_f1_bottom &= 0xffff0000;
-        s->lcd_ch.src_f1_bottom |= 0x0000ffff & value;
+        *ret = s->src_f1_bottom & 0xffff;
         break;
 
     case 0x308:	/* SYS_DMA_LCD_BOT_F1_U */
-        s->lcd_ch.src_f1_bottom &= 0x0000ffff;
-        s->lcd_ch.src_f1_bottom |= value << 16;
+        *ret = s->src_f1_bottom >> 16;
         break;
 
     case 0x30a:	/* SYS_DMA_LCD_TOP_F2_L */
-        s->lcd_ch.src_f2_top &= 0xffff0000;
-        s->lcd_ch.src_f2_top |= 0x0000ffff & value;
+        *ret = s->src_f2_top & 0xffff;
         break;
 
     case 0x30c:	/* SYS_DMA_LCD_TOP_F2_U */
-        s->lcd_ch.src_f2_top &= 0x0000ffff;
-        s->lcd_ch.src_f2_top |= value << 16;
+        *ret = s->src_f2_top >> 16;
         break;
 
     case 0x30e:	/* SYS_DMA_LCD_BOT_F2_L */
-        s->lcd_ch.src_f2_bottom &= 0xffff0000;
-        s->lcd_ch.src_f2_bottom |= 0x0000ffff & value;
+        *ret = s->src_f2_bottom & 0xffff;
         break;
 
     case 0x310:	/* SYS_DMA_LCD_BOT_F2_U */
-        s->lcd_ch.src_f2_bottom &= 0x0000ffff;
-        s->lcd_ch.src_f2_bottom |= value << 16;
+        *ret = s->src_f2_bottom >> 16;
         break;
 
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value)
+{
+    switch (offset) {
     case 0x400:	/* SYS_DMA_GCR */
-        s->gcr = value & 0x000c;
+        s->gcr = value;
         break;
 
+    case 0x404:	/* DMA_GSCR */
+        if (value & 0x8)
+            omap_dma_disable_3_1_mapping(s);
+        else
+            omap_dma_enable_3_1_mapping(s);
+        break;
+
+    case 0x408:	/* DMA_GRST */
+        if (value & 0x1)
+            omap_dma_reset(s);
+        break;
+
     default:
-        OMAP_BAD_REG(addr);
+        return 1;
     }
+    return 0;
 }
 
+static int omap_dma_sys_read(struct omap_dma_s *s, int offset,
+                uint16_t *ret)
+{
+    switch (offset) {
+    case 0x400:	/* SYS_DMA_GCR */
+        *ret = s->gcr;
+        break;
+
+    case 0x404:	/* DMA_GSCR */
+        *ret = s->omap_3_1_mapping_disabled << 3;
+        break;
+
+    case 0x408:	/* DMA_GRST */
+        *ret = 0;
+        break;
+
+    case 0x442:	/* DMA_HW_ID */
+    case 0x444:	/* DMA_PCh2_ID */
+    case 0x446:	/* DMA_PCh0_ID */
+    case 0x448:	/* DMA_PCh1_ID */
+    case 0x44a:	/* DMA_PChG_ID */
+    case 0x44c:	/* DMA_PChD_ID */
+        *ret = 1;
+        break;
+
+    case 0x44e:	/* DMA_CAPS_0_U */
+        *ret = (1 << 3) | /* Constant Fill Capacity */
+            (1 << 2);     /* Transparent BLT Capacity */
+        break;
+
+    case 0x450:	/* DMA_CAPS_0_L */
+    case 0x452:	/* DMA_CAPS_1_U */
+        *ret = 0;
+        break;
+
+    case 0x454:	/* DMA_CAPS_1_L */
+        *ret = (1 << 1); /* 1-bit palletized capability */
+        break;
+
+    case 0x456:	/* DMA_CAPS_2 */
+        *ret = (1 << 8) | /* SSDIC */
+            (1 << 7) |    /* DDIAC */
+            (1 << 6) |    /* DSIAC */
+            (1 << 5) |    /* DPIAC */
+            (1 << 4) |    /* DCAC  */
+            (1 << 3) |    /* SDIAC */
+            (1 << 2) |    /* SSIAC */
+            (1 << 1) |    /* SPIAC */
+            1;            /* SCAC  */
+        break;
+
+    case 0x458:	/* DMA_CAPS_3 */
+        *ret = (1 << 5) | /* CCC */
+            (1 << 4) |    /* IC  */
+            (1 << 3) |    /* ARC */
+            (1 << 2) |    /* AEC */
+            (1 << 1) |    /* FSC */
+            1;            /* ESC */
+        break;
+
+    case 0x45a:	/* DMA_CAPS_4 */
+        *ret = (1 << 6) | /* SSC  */
+            (1 << 5) |    /* BIC  */
+            (1 << 4) |    /* LFIC */
+            (1 << 3) |    /* FIC  */
+            (1 << 2) |    /* HFIC */
+            (1 << 1) |    /* EDIC */
+            1;            /* TOIC */
+        break;
+
+    case 0x460:	/* DMA_PCh2_SR */
+    case 0x480:	/* DMA_PCh0_SR */
+    case 0x482:	/* DMA_PCh1_SR */
+    case 0x4c0:	/* DMA_PChD_SR_0 */
+        printf("%s: Physical Channel Status Registers not implemented.\n",
+               __FUNCTION__);
+        *ret = 0xff;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch, offset = addr - s->base;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x300 ... 0x3fe:
+        if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_1_lcd_read(&s->lcd_ch, offset, &ret))
+                break;
+            return ret;
+        }
+        /* Fall through. */
+    case 0x000 ... 0x2fe:
+        reg = offset & 0x3f;
+        ch = (offset >> 6) & 0x0f;
+        if (omap_dma_ch_reg_read(s, &s->ch[ch], reg, &ret))
+            break;
+        return ret;
+
+    case 0x404 ... 0x4fe:
+        if (s->model == omap_dma_3_1)
+            break;
+        /* Fall through. */
+    case 0x400:
+        if (omap_dma_sys_read(s, offset, &ret))
+            break;
+        return ret;
+
+    case 0xb00 ... 0xbfe:
+        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_2_lcd_read(&s->lcd_ch, offset, &ret))
+                break;
+            return ret;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dma_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch, offset = addr - s->base;
+
+    switch (offset) {
+    case 0x300 ... 0x3fe:
+        if (s->model == omap_dma_3_1 || !s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_1_lcd_write(&s->lcd_ch, offset, value))
+                break;
+            return;
+        }
+        /* Fall through.  */
+    case 0x000 ... 0x2fe:
+        reg = offset & 0x3f;
+        ch = (offset >> 6) & 0x0f;
+        if (omap_dma_ch_reg_write(s, &s->ch[ch], reg, value))
+            break;
+        return;
+
+    case 0x404 ... 0x4fe:
+        if (s->model == omap_dma_3_1)
+            break;
+    case 0x400:
+        /* Fall through. */
+        if (omap_dma_sys_write(s, offset, value))
+            break;
+        return;
+
+    case 0xb00 ... 0xbfe:
+        if (s->model == omap_dma_3_2 && s->omap_3_1_mapping_disabled) {
+            if (omap_dma_3_2_lcd_write(&s->lcd_ch, offset, value))
+                break;
+            return;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+}
+
 static CPUReadMemoryFunc *omap_dma_readfn[] = {
     omap_badwidth_read16,
     omap_dma_read,
@@ -1005,7 +1666,7 @@
     if (req) {
         if (~s->drq & (1 << drq)) {
             s->drq |= 1 << drq;
-            omap_dma_request_run(s, 0, drq);
+            omap_dma_process_request(s, drq);
         }
     } else
         s->drq &= ~(1 << drq);
@@ -1026,37 +1687,33 @@
     }
 }
 
-static void omap_dma_reset(struct omap_dma_s *s)
+struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
+                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
+                enum omap_dma_model model)
 {
-    int i;
-
-    qemu_del_timer(s->tm);
-    s->gcr = 0x0004;
-    s->drq = 0x00000000;
-    s->run_count = 0;
-    s->lcd_ch.src = emiff;
-    s->lcd_ch.condition = 0;
-    s->lcd_ch.interrupts = 0;
-    s->lcd_ch.dual = 0;
-    memset(s->ch, 0, sizeof(s->ch));
-    for (i = 0; i < s->chans; i ++)
-        s->ch[i].interrupts = 0x0003;
-}
-
-struct omap_dma_s *omap_dma_init(target_phys_addr_t base,
-                qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk)
-{
-    int iomemtype;
+    int iomemtype, num_irqs, memsize, i;
     struct omap_dma_s *s = (struct omap_dma_s *)
             qemu_mallocz(sizeof(struct omap_dma_s));
 
-    s->ih = pic;
+    if (model == omap_dma_3_1) {
+        num_irqs = 6;
+        memsize = 0x800;
+    } else {
+        num_irqs = 16;
+        memsize = 0xc00;
+    }
     s->base = base;
-    s->chans = 9;
+    s->model = model;
     s->mpu = mpu;
     s->clk = clk;
-    s->lcd_ch.irq = pic[OMAP_INT_DMA_LCD];
+    s->lcd_ch.irq = lcd_irq;
     s->lcd_ch.mpu = mpu;
+    while (num_irqs --)
+        s->ch[num_irqs].irq = irqs[num_irqs];
+    for (i = 0; i < 3; i ++) {
+        s->ch[i].sibling = &s->ch[i + 6];
+        s->ch[i + 6].sibling = &s->ch[i];
+    }
     s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s);
     omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
     mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 32);
@@ -1065,7 +1722,7 @@
 
     iomemtype = cpu_register_io_memory(0, omap_dma_readfn,
                     omap_dma_writefn, s);
-    cpu_register_physical_memory(s->base, 0x800, iomemtype);
+    cpu_register_physical_memory(s->base, memsize, iomemtype);
 
     return s;
 }
@@ -2919,8 +3576,8 @@
         if (*row & cols)
             rows |= i;
 
-    qemu_set_irq(s->kbd_irq, rows && ~s->kbd_mask && s->clk);
-    s->row_latch = rows ^ 0x1f;
+    qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk);
+    s->row_latch = ~rows;
 }
 
 static uint32_t omap_mpuio_read(void *opaque, target_phys_addr_t addr)
@@ -2952,7 +3609,7 @@
         return s->edge;
 
     case 0x20:	/* KBD_INT */
-        return (s->row_latch != 0x1f) && !s->kbd_mask;
+        return (~s->row_latch & 0x1f) && !s->kbd_mask;
 
     case 0x24:	/* GPIO_INT */
         ret = s->ints;
@@ -4919,13 +5576,39 @@
         cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB);
 }
 
+struct dma_irq_map {
+    int ih;
+    int intr;
+};
+
+static const struct dma_irq_map omap_dma_irq_map[] = {
+    { 0, OMAP_INT_DMA_CH0_6 },
+    { 0, OMAP_INT_DMA_CH1_7 },
+    { 0, OMAP_INT_DMA_CH2_8 },
+    { 0, OMAP_INT_DMA_CH3 },
+    { 0, OMAP_INT_DMA_CH4 },
+    { 0, OMAP_INT_DMA_CH5 },
+    { 1, OMAP_INT_1610_DMA_CH6 },
+    { 1, OMAP_INT_1610_DMA_CH7 },
+    { 1, OMAP_INT_1610_DMA_CH8 },
+    { 1, OMAP_INT_1610_DMA_CH9 },
+    { 1, OMAP_INT_1610_DMA_CH10 },
+    { 1, OMAP_INT_1610_DMA_CH11 },
+    { 1, OMAP_INT_1610_DMA_CH12 },
+    { 1, OMAP_INT_1610_DMA_CH13 },
+    { 1, OMAP_INT_1610_DMA_CH14 },
+    { 1, OMAP_INT_1610_DMA_CH15 }
+};
+
 struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
                 DisplayState *ds, const char *core)
 {
+    int i;
     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
             qemu_mallocz(sizeof(struct omap_mpu_state_s));
     ram_addr_t imif_base, emiff_base;
     qemu_irq *cpu_irq;
+    qemu_irq dma_irqs[6];
     int sdindex;
 
     if (!core)
@@ -4964,8 +5647,11 @@
     s->irq[0] = s->ih[0]->pins;
     s->irq[1] = s->ih[1]->pins;
 
-    s->dma = omap_dma_init(0xfffed800, s->irq[0], s,
-                    omap_findclk(s, "dma_ck"));
+    for (i = 0; i < 6; i ++)
+        dma_irqs[i] = s->irq[omap_dma_irq_map[i].ih][omap_dma_irq_map[i].intr];
+    s->dma = omap_dma_init(0xfffed800, dma_irqs, s->irq[0][OMAP_INT_DMA_LCD],
+                           s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
+
     s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
     s->port[emifs    ].addr_valid = omap_validate_emifs_addr;
     s->port[imif     ].addr_valid = omap_validate_imif_addr;

Modified: trunk/src/host/qemu-neo1973/hw/omap.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/omap.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/omap.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -336,26 +336,68 @@
 # define OMAP_INT_243X_HS_USB_DMA	93
 # define OMAP_INT_243X_CARKIT		94
 
+enum omap_dma_model {
+    omap_dma_3_1 = 0,
+    omap_dma_3_2
+};
+
 struct omap_dma_s;
-struct omap_dma_s *omap_dma_init(target_phys_addr_t base,
-                qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk);
+struct omap_dma_s *omap_dma_init(target_phys_addr_t base, qemu_irq *irqs,
+                qemu_irq lcd_irq, struct omap_mpu_state_s *mpu, omap_clk clk,
+                enum omap_dma_model model);
 
 enum omap_dma_port {
     emiff = 0,
     emifs,
-    imif,
+    imif,	/* omap16xx: ocp_t1 */
     tipb,
-    local,
+    local,	/* omap16xx: ocp_t2 */
     tipb_mpui,
     omap_dma_port_last,
 };
 
+typedef enum {
+    constant = 0,
+    post_incremented,
+    single_index,
+    double_index,
+} omap_dma_addressing_t;
+
 struct omap_dma_lcd_channel_s {
     enum omap_dma_port src;
     target_phys_addr_t src_f1_top;
     target_phys_addr_t src_f1_bottom;
     target_phys_addr_t src_f2_top;
     target_phys_addr_t src_f2_bottom;
+
+    /* Used in OMAP DMA 3.2 gigacell */
+    unsigned char brust_f1;
+    unsigned char pack_f1;
+    unsigned char data_type_f1;
+    unsigned char brust_f2;
+    unsigned char pack_f2;
+    unsigned char data_type_f2;
+    unsigned char end_prog;
+    unsigned char repeat;
+    unsigned char auto_init;
+    unsigned char priority;
+    unsigned char fs;
+    unsigned char running;
+    unsigned char bs;
+    unsigned char omap_3_1_compatible_disable;
+    unsigned char dst;
+    unsigned char lch_type;
+    int16_t element_index_f1;
+    int16_t element_index_f2;
+    int32_t frame_index_f1;
+    int32_t frame_index_f2;
+    uint16_t elements_f1;
+    uint16_t frames_f1;
+    uint16_t elements_f2;
+    uint16_t frames_f2;
+    omap_dma_addressing_t mode_f1;
+    omap_dma_addressing_t mode_f2;
+
     /* Destination port is fixed.  */
     int interrupts;
     int condition;

Modified: trunk/src/host/qemu-neo1973/hw/pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pci.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/pci.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -42,6 +42,7 @@
     PCIBus *next;
     /* The bus IRQ state is the logical OR of the connected devices.
        Keep a count of the number of devices with raised IRQs.  */
+    int nirq;
     int irq_count[];
 };
 
@@ -52,16 +53,51 @@
 static int pci_irq_index;
 static PCIBus *first_bus;
 
+static void pcibus_save(QEMUFile *f, void *opaque)
+{
+    PCIBus *bus = (PCIBus *)opaque;
+    int i;
+
+    qemu_put_be32(f, bus->nirq);
+    for (i = 0; i < bus->nirq; i++)
+        qemu_put_be32(f, bus->irq_count[i]);
+}
+
+static int  pcibus_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PCIBus *bus = (PCIBus *)opaque;
+    int i, nirq;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    nirq = qemu_get_be32(f);
+    if (bus->nirq != nirq) {
+        fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n",
+                nirq, bus->nirq);
+        return -EINVAL;
+    }
+
+    for (i = 0; i < nirq; i++)
+        bus->irq_count[i] = qemu_get_be32(f);
+
+    return 0;
+}
+
 PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                          qemu_irq *pic, int devfn_min, int nirq)
 {
     PCIBus *bus;
+    static int nbus = 0;
+
     bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
     bus->set_irq = set_irq;
     bus->map_irq = map_irq;
     bus->irq_opaque = pic;
     bus->devfn_min = devfn_min;
+    bus->nirq = nirq;
     first_bus = bus;
+    register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
     return bus;
 }
 
@@ -83,18 +119,29 @@
 
 void pci_device_save(PCIDevice *s, QEMUFile *f)
 {
-    qemu_put_be32(f, 1); /* PCI device version */
+    int i;
+
+    qemu_put_be32(f, 2); /* PCI device version */
     qemu_put_buffer(f, s->config, 256);
+    for (i = 0; i < 4; i++)
+        qemu_put_be32(f, s->irq_state[i]);
 }
 
 int pci_device_load(PCIDevice *s, QEMUFile *f)
 {
     uint32_t version_id;
+    int i;
+
     version_id = qemu_get_be32(f);
-    if (version_id != 1)
+    if (version_id > 2)
         return -EINVAL;
     qemu_get_buffer(f, s->config, 256);
     pci_update_mappings(s);
+
+    if (version_id >= 2)
+        for (i = 0; i < 4; i ++)
+            s->irq_state[i] = qemu_get_be32(f);
+
     return 0;
 }
 

Modified: trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/pflash_cfi01.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -483,11 +483,11 @@
     return ret;
 }
 
-pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off,
-                           BlockDriverState *bs,
-                           target_ulong sector_len, int nb_blocs, int width,
-                           uint16_t id0, uint16_t id1,
-                           uint16_t id2, uint16_t id3)
+pflash_t *pflash_cfi01_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs, target_ulong sector_len,
+                                int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3)
 {
     pflash_t *pfl;
     target_long total_len;

Modified: trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -524,11 +524,11 @@
     return ret;
 }
 
-pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off,
-                           BlockDriverState *bs,
-                           uint32_t sector_len, int nb_blocs, int width,
-                           uint16_t id0, uint16_t id1,
-                           uint16_t id2, uint16_t id3)
+pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
+                                BlockDriverState *bs, uint32_t sector_len,
+                                int nb_blocs, int width,
+                                uint16_t id0, uint16_t id1,
+                                uint16_t id2, uint16_t id3)
 {
     pflash_t *pfl;
     int32_t total_len;

Modified: trunk/src/host/qemu-neo1973/hw/piix_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/piix_pci.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/piix_pci.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -57,6 +57,7 @@
 
 static uint32_t isa_page_descs[384 / 4];
 static uint8_t smm_enabled;
+static int pci_irq_levels[4];
 
 static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
 {
@@ -139,22 +140,32 @@
 static void i440fx_save(QEMUFile* f, void *opaque)
 {
     PCIDevice *d = opaque;
+    int i;
+
     pci_device_save(d, f);
     qemu_put_8s(f, &smm_enabled);
+
+    for (i = 0; i < 4; i++)
+        qemu_put_be32(f, pci_irq_levels[i]);
 }
 
 static int i440fx_load(QEMUFile* f, void *opaque, int version_id)
 {
     PCIDevice *d = opaque;
-    int ret;
+    int ret, i;
 
-    if (version_id != 1)
+    if (version_id > 2)
         return -EINVAL;
     ret = pci_device_load(d, f);
     if (ret < 0)
         return ret;
     i440fx_update_memory_mappings(d);
     qemu_get_8s(f, &smm_enabled);
+
+    if (version_id >= 2)
+        for (i = 0; i < 4; i++)
+            pci_irq_levels[i] = qemu_get_be32(f);
+
     return 0;
 }
 
@@ -192,7 +203,7 @@
 
     d->config[0x72] = 0x02; /* SMRAM */
 
-    register_savevm("I440FX", 0, 1, i440fx_save, i440fx_load, d);
+    register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d);
     *pi440fx_state = d;
     return b;
 }
@@ -205,8 +216,6 @@
 /* just used for simpler irq handling. */
 #define PCI_IRQ_WORDS   ((PCI_DEVICES_MAX + 31) / 32)
 
-static int pci_irq_levels[4];
-
 static void piix3_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
@@ -314,31 +323,6 @@
     return pci_device_load(d, f);
 }
 
-static int piix_init(PCIBus *bus, int devfn)
-{
-    PCIDevice *d;
-    uint8_t *pci_conf;
-
-    d = pci_register_device(bus, "PIIX", sizeof(PCIDevice),
-                                    devfn, NULL, NULL);
-    register_savevm("PIIX", 0, 2, piix_save, piix_load, d);
-
-    piix3_dev = d;
-    pci_conf = d->config;
-
-    pci_conf[0x00] = 0x86; // Intel
-    pci_conf[0x01] = 0x80;
-    pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge
-    pci_conf[0x03] = 0x12;
-    pci_conf[0x08] = 0x02; // Step A1
-    pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
-    pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
-    pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
-
-    piix3_reset(d);
-    return d->devfn;
-}
-
 int piix3_init(PCIBus *bus, int devfn)
 {
     PCIDevice *d;

Modified: trunk/src/host/qemu-neo1973/hw/ppc405_boards.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc405_boards.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/ppc405_boards.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -234,9 +234,9 @@
                fl_idx, bios_size, bios_offset, -bios_size,
                bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
 #endif
-        pflash_register((uint32_t)(-bios_size), bios_offset,
-                        drives_table[index].bdrv, 65536, fl_sectors, 2,
-                        0x0001, 0x22DA, 0x0000, 0x0000);
+        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+                              drives_table[index].bdrv, 65536, fl_sectors, 2,
+                              0x0001, 0x22DA, 0x0000, 0x0000);
         fl_idx++;
     } else
 #endif
@@ -551,9 +551,9 @@
                fl_idx, bios_size, bios_offset, -bios_size,
                bdrv_get_device_name(drives_table[index].bdrv), fl_sectors);
 #endif
-        pflash_register((uint32_t)(-bios_size), bios_offset,
-                        drives_table[index].bdrv, 65536, fl_sectors, 4,
-                        0x0001, 0x22DA, 0x0000, 0x0000);
+        pflash_cfi02_register((uint32_t)(-bios_size), bios_offset,
+                              drives_table[index].bdrv, 65536, fl_sectors, 4,
+                              0x0001, 0x22DA, 0x0000, 0x0000);
         fl_idx++;
     } else
 #endif
@@ -587,9 +587,9 @@
                fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
                bdrv_get_device_name(drives_table[index].bdrv));
 #endif
-        pflash_register(0xfc000000, bios_offset, drives_table[index].bdrv,
-                        65536, fl_sectors, 4,
-                        0x0001, 0x22DA, 0x0000, 0x0000);
+        pflash_cfi02_register(0xfc000000, bios_offset,
+                              drives_table[index].bdrv, 65536, fl_sectors, 4,
+                              0x0001, 0x22DA, 0x0000, 0x0000);
         fl_idx++;
     }
     /* Register CLPD & LCD display */

Modified: trunk/src/host/qemu-neo1973/hw/scsi-disk.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/scsi-disk.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/scsi-disk.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -37,7 +37,7 @@
 #define SCSI_DMA_BUF_SIZE    65536
 
 typedef struct SCSIRequest {
-    SCSIDevice *dev;
+    SCSIDeviceState *dev;
     uint32_t tag;
     /* ??? We should probably keep track of whether the data trasfer is
        a read or a write.  Currently we rely on the host getting it right.  */
@@ -51,7 +51,7 @@
     struct SCSIRequest *next;
 } SCSIRequest;
 
-struct SCSIDevice
+struct SCSIDeviceState
 {
     BlockDriverState *bdrv;
     SCSIRequest *requests;
@@ -69,7 +69,7 @@
 /* Global pool of SCSIRequest structures.  */
 static SCSIRequest *free_requests = NULL;
 
-static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag)
+static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
 {
     SCSIRequest *r;
 
@@ -93,7 +93,7 @@
 static void scsi_remove_request(SCSIRequest *r)
 {
     SCSIRequest *last;
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
 
     if (s->requests == r) {
         s->requests = r->next;
@@ -111,7 +111,7 @@
     free_requests = r;
 }
 
-static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag)
+static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
 {
     SCSIRequest *r;
 
@@ -125,7 +125,7 @@
 /* Helper function for command completion.  */
 static void scsi_command_complete(SCSIRequest *r, int sense)
 {
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
     uint32_t tag;
     DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense);
     s->sense = sense;
@@ -135,8 +135,9 @@
 }
 
 /* Cancel a pending data transfer.  */
-void scsi_cancel_io(SCSIDevice *s, uint32_t tag)
+static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
     DPRINTF("Cancel tag=0x%x\n", tag);
     r = scsi_find_request(s, tag);
@@ -151,7 +152,7 @@
 static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIRequest *r = (SCSIRequest *)opaque;
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
 
     if (ret) {
         DPRINTF("IO error\n");
@@ -164,8 +165,9 @@
 }
 
 /* Read more data from scsi device into buffer.  */
-void scsi_read_data(SCSIDevice *s, uint32_t tag)
+static void scsi_read_data(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
     uint32_t n;
 
@@ -204,7 +206,7 @@
 static void scsi_write_complete(void * opaque, int ret)
 {
     SCSIRequest *r = (SCSIRequest *)opaque;
-    SCSIDevice *s = r->dev;
+    SCSIDeviceState *s = r->dev;
     uint32_t len;
 
     if (ret) {
@@ -228,8 +230,9 @@
 
 /* Write data to a scsi device.  Returns nonzero on failure.
    The transfer may complete asynchronously.  */
-int scsi_write_data(SCSIDevice *s, uint32_t tag)
+static int scsi_write_data(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
     uint32_t n;
 
@@ -259,8 +262,9 @@
 }
 
 /* Return a pointer to the data buffer.  */
-uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag)
+static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
 {
+    SCSIDeviceState *s = d->state;
     SCSIRequest *r;
 
     r = scsi_find_request(s, tag);
@@ -276,8 +280,10 @@
    (eg. disk reads), negative for transfers to the device (eg. disk writes),
    and zero if the command does not transfer any data.  */
 
-int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
+static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
+                                 uint8_t *buf, int lun)
 {
+    SCSIDeviceState *s = d->state;
     int64_t nb_sectors;
     uint32_t lba;
     uint32_t len;
@@ -291,7 +297,7 @@
     r = scsi_find_request(s, tag);
     if (r) {
         BADF("Tag 0x%x already in use\n", tag);
-        scsi_cancel_io(s, tag);
+        scsi_cancel_io(d, tag);
     }
     /* ??? Tags are not unique for different luns.  We only implement a
        single lun, so this should not matter.  */
@@ -576,19 +582,19 @@
     }
 }
 
-void scsi_disk_destroy(SCSIDevice *s)
+static void scsi_destroy(SCSIDevice *d)
 {
-    qemu_free(s);
+    qemu_free(d->state);
+    qemu_free(d);
 }
 
-SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
-                           int tcq,
-                           scsi_completionfn completion,
-                           void *opaque)
+SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
+                           scsi_completionfn completion, void *opaque)
 {
-    SCSIDevice *s;
+    SCSIDevice *d;
+    SCSIDeviceState *s;
 
-    s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
+    s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
     s->bdrv = bdrv;
     s->tcq = tcq;
     s->completion = completion;
@@ -599,6 +605,14 @@
         s->cluster_size = 1;
     }
 
-    return s;
+    d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
+    d->state = s;
+    d->destroy = scsi_destroy;
+    d->send_command = scsi_send_command;
+    d->read_data = scsi_read_data;
+    d->write_data = scsi_write_data;
+    d->cancel_io = scsi_cancel_io;
+    d->get_buf = scsi_get_buf;
+
+    return d;
 }
-

Modified: trunk/src/host/qemu-neo1973/hw/scsi-disk.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/scsi-disk.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/scsi-disk.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -7,24 +7,25 @@
     SCSI_REASON_DATA  /* Transfer complete, more data required.  */
 };
 
+typedef struct SCSIDeviceState SCSIDeviceState;
 typedef struct SCSIDevice SCSIDevice;
 typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag,
                                   uint32_t arg);
 
-SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
-                           int tcq,
-                           scsi_completionfn completion,
-                           void *opaque);
-void scsi_disk_destroy(SCSIDevice *s);
+struct SCSIDevice
+{
+    SCSIDeviceState *state;
+    void (*destroy)(SCSIDevice *s);
+    int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf,
+                            int lun);
+    void (*read_data)(SCSIDevice *s, uint32_t tag);
+    int (*write_data)(SCSIDevice *s, uint32_t tag);
+    void (*cancel_io)(SCSIDevice *s, uint32_t tag);
+    uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
+};
 
-int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun);
-/* SCSI data transfers are asynchrnonous.  However, unlike the block IO
-   layer the completion routine may be called directly by
-   scsi_{read,write}_data.  */
-void scsi_read_data(SCSIDevice *s, uint32_t tag);
-int scsi_write_data(SCSIDevice *s, uint32_t tag);
-void scsi_cancel_io(SCSIDevice *s, uint32_t tag);
-uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag);
+SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
+                           scsi_completionfn completion, void *opaque);
 
 /* cdrom.c */
 int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);

Modified: trunk/src/host/qemu-neo1973/hw/sun4m.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4m.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/sun4m.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -72,6 +72,8 @@
     target_phys_addr_t serial_base, fd_base;
     target_phys_addr_t dma_base, esp_base, le_base;
     target_phys_addr_t tcx_base, cs_base, power_base;
+    target_phys_addr_t ecc_base;
+    uint32_t ecc_version;
     long vram_size, nvram_size;
     // IRQ numbers are not PIL ones, but master interrupt controller register
     // bit numbers
@@ -479,6 +481,9 @@
     nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
                boot_device, RAM_size, kernel_size, graphic_width,
                graphic_height, graphic_depth, hwdef->machine_id);
+
+    if (hwdef->ecc_base != (target_phys_addr_t)-1)
+        ecc_init(hwdef->ecc_base, hwdef->ecc_version);
 }
 
 static const struct hwdef hwdefs[] = {
@@ -498,6 +503,7 @@
         .esp_base     = 0x78800000,
         .le_base      = 0x78c00000,
         .power_base   = 0x7a000000,
+        .ecc_base     = -1,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -534,6 +540,8 @@
         .esp_base     = 0xef0800000ULL,
         .le_base      = 0xef0c00000ULL,
         .power_base   = 0xefa000000ULL,
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x10000000, // version 0, implementation 1
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -570,6 +578,8 @@
         .esp_base     = 0xef0080000ULL,
         .le_base      = 0xef0060000ULL,
         .power_base   = 0xefa000000ULL,
+        .ecc_base     = 0xf00000000ULL,
+        .ecc_version  = 0x00000000, // version 0, implementation 0
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,

Modified: trunk/src/host/qemu-neo1973/hw/sun4m.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4m.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/sun4m.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -72,4 +72,7 @@
 void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
                 qemu_irq irq, qemu_irq *reset);
 
+/* eccmemctl.c */
+void *ecc_init(target_phys_addr_t base, uint32_t version);
+
 #endif

Modified: trunk/src/host/qemu-neo1973/hw/usb-msd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-msd.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/hw/usb-msd.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -149,9 +149,9 @@
     s->data_len -= len;
     if (s->scsi_len == 0) {
         if (s->mode == USB_MSDM_DATAIN) {
-            scsi_read_data(s->scsi_dev, s->tag);
+            s->scsi_dev->read_data(s->scsi_dev, s->tag);
         } else if (s->mode == USB_MSDM_DATAOUT) {
-            scsi_write_data(s->scsi_dev, s->tag);
+            s->scsi_dev->write_data(s->scsi_dev, s->tag);
         }
     }
 }
@@ -204,7 +204,7 @@
         return;
     }
     s->scsi_len = arg;
-    s->scsi_buf = scsi_get_buf(s->scsi_dev, tag);
+    s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag);
     if (p) {
         usb_msd_copy_data(s);
         if (s->usb_len == 0) {
@@ -342,7 +342,7 @@
 static void usb_msd_cancel_io(USBPacket *p, void *opaque)
 {
     MSDState *s = opaque;
-    scsi_cancel_io(s->scsi_dev, s->tag);
+    s->scsi_dev->cancel_io(s->scsi_dev, s->tag);
     s->packet = NULL;
     s->scsi_len = 0;
 }
@@ -390,14 +390,14 @@
             DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
                     s->tag, cbw.flags, cbw.cmd_len, s->data_len);
             s->residue = 0;
-            scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
+            s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
             /* ??? Should check that USB and SCSI data transfer
                directions match.  */
             if (s->residue == 0) {
                 if (s->mode == USB_MSDM_DATAIN) {
-                    scsi_read_data(s->scsi_dev, s->tag);
+                    s->scsi_dev->read_data(s->scsi_dev, s->tag);
                 } else if (s->mode == USB_MSDM_DATAOUT) {
-                    scsi_write_data(s->scsi_dev, s->tag);
+                    s->scsi_dev->write_data(s->scsi_dev, s->tag);
                 }
             }
             ret = len;
@@ -508,7 +508,7 @@
 {
     MSDState *s = (MSDState *)dev;
 
-    scsi_disk_destroy(s->scsi_dev);
+    s->scsi_dev->destroy(s->scsi_dev);
     bdrv_delete(s->bs);
     qemu_free(s);
 }

Modified: trunk/src/host/qemu-neo1973/linux-user/ppc/syscall.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/ppc/syscall.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/linux-user/ppc/syscall.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -26,20 +26,24 @@
 #define __USER_DS	(1)
 
 struct target_pt_regs {
-	unsigned long gpr[32];
-	unsigned long nip;
-	unsigned long msr;
-	unsigned long orig_gpr3;	/* Used for restarting system calls */
-	unsigned long ctr;
-	unsigned long link;
-	unsigned long xer;
-	unsigned long ccr;
-	unsigned long mq;		/* 601 only (not used at present) */
+	abi_ulong gpr[32];
+	abi_ulong nip;
+	abi_ulong msr;
+	abi_ulong orig_gpr3;	/* Used for restarting system calls */
+	abi_ulong ctr;
+	abi_ulong link;
+	abi_ulong xer;
+	abi_ulong ccr;
+#if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
+        abi_ulong softe;
+#else
+	abi_ulong mq;		/* 601 only (not used at present) */
+#endif
 					/* Used on APUS to hold IPL value. */
-	unsigned long trap;		/* Reason for being here */
-	unsigned long dar;		/* Fault registers */
-	unsigned long dsisr;
-	unsigned long result; 		/* Result of a system call */
+	abi_ulong trap;		/* Reason for being here */
+	abi_ulong dar;		/* Fault registers */
+	abi_ulong dsisr;
+	abi_ulong result; 		/* Result of a system call */
 };
 
 /* ioctls */

Modified: trunk/src/host/qemu-neo1973/linux-user/ppc/target_signal.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/ppc/target_signal.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/linux-user/ppc/target_signal.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -7,7 +7,7 @@
 
 typedef struct target_sigaltstack {
 	abi_ulong ss_sp;
-	abi_long ss_flags;
+	int ss_flags;
 	abi_ulong ss_size;
 } target_stack_t;
 

Modified: trunk/src/host/qemu-neo1973/linux-user/socket.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/socket.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/linux-user/socket.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -109,12 +109,21 @@
 	#define TARGET_SO_LINGER       13
 	#define TARGET_SO_BSDCOMPAT    14
 	/* To add :#define TARGET_SO_REUSEPORT 15 */
+#if defined(TARGET_PPC)
+	#define TARGET_SO_RCVLOWAT     16
+	#define TARGET_SO_SNDLOWAT     17
+	#define TARGET_SO_RCVTIMEO     18
+	#define TARGET_SO_SNDTIMEO     19
+	#define TARGET_SO_PASSCRED     20
+	#define TARGET_SO_PEERCRED     21
+#else
 	#define TARGET_SO_PASSCRED     16
 	#define TARGET_SO_PEERCRED     17
 	#define TARGET_SO_RCVLOWAT     18
 	#define TARGET_SO_SNDLOWAT     19
 	#define TARGET_SO_RCVTIMEO     20
 	#define TARGET_SO_SNDTIMEO     21
+#endif
 
 	/* Security levels - as per NRL IPv6 - don't actually do anything */
 	#define TARGET_SO_SECURITY_AUTHENTICATION              22

Modified: trunk/src/host/qemu-neo1973/linux-user/syscall.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/syscall.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/linux-user/syscall.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -443,50 +443,66 @@
     }
 }
 
-static inline fd_set *target_to_host_fds(fd_set *fds,
-                                         abi_long *target_fds, int n)
+static inline abi_long copy_from_user_fdset(fd_set *fds,
+                                            abi_ulong target_fds_addr,
+                                            int n)
 {
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
-    return (fd_set *)target_fds;
-#else
-    int i, b;
-    if (target_fds) {
-        FD_ZERO(fds);
-        for(i = 0;i < n; i++) {
-            b = (tswapl(target_fds[i / TARGET_ABI_BITS]) >>
-                 (i & (TARGET_ABI_BITS - 1))) & 1;
-            if (b)
-                FD_SET(i, fds);
+    int i, nw, j, k;
+    abi_ulong b, *target_fds;
+
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    if (!(target_fds = lock_user(VERIFY_READ,
+                                 target_fds_addr,
+                                 sizeof(abi_ulong) * nw,
+                                 1)))
+        return -TARGET_EFAULT;
+
+    FD_ZERO(fds);
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        /* grab the abi_ulong */
+        __get_user(b, &target_fds[i]);
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            /* check the bit inside the abi_ulong */
+            if ((b >> j) & 1)
+                FD_SET(k, fds);
+            k++;
         }
-        return fds;
-    } else {
-        return NULL;
     }
-#endif
+
+    unlock_user(target_fds, target_fds_addr, 0);
+
+    return 0;
 }
 
-static inline void host_to_target_fds(abi_long *target_fds,
-                                      fd_set *fds, int n)
+static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
+                                          const fd_set *fds,
+                                          int n)
 {
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
-    /* nothing to do */
-#else
     int i, nw, j, k;
     abi_long v;
+    abi_ulong *target_fds;
 
-    if (target_fds) {
-        nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
-        k = 0;
-        for(i = 0;i < nw; i++) {
-            v = 0;
-            for(j = 0; j < TARGET_ABI_BITS; j++) {
-                v |= ((FD_ISSET(k, fds) != 0) << j);
-                k++;
-            }
-            target_fds[i] = tswapl(v);
+    nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+    if (!(target_fds = lock_user(VERIFY_WRITE,
+                                 target_fds_addr,
+                                 sizeof(abi_ulong) * nw,
+                                 0)))
+        return -TARGET_EFAULT;
+
+    k = 0;
+    for (i = 0; i < nw; i++) {
+        v = 0;
+        for (j = 0; j < TARGET_ABI_BITS; j++) {
+            v |= ((FD_ISSET(k, fds) != 0) << j);
+            k++;
         }
+        __put_user(v, &target_fds[i]);
     }
-#endif
+
+    unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+    return 0;
 }
 
 #if defined(__alpha__)
@@ -534,105 +550,93 @@
     return 0;
 }
 
-static inline abi_long target_to_host_timeval(struct timeval *tv,
-                                              abi_ulong target_addr)
+static inline abi_long copy_from_user_timeval(struct timeval *tv,
+                                              abi_ulong target_tv_addr)
 {
     struct target_timeval *target_tv;
 
-    if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1))
+    if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
         return -TARGET_EFAULT;
-    tv->tv_sec = tswapl(target_tv->tv_sec);
-    tv->tv_usec = tswapl(target_tv->tv_usec);
-    unlock_user_struct(target_tv, target_addr, 0);
 
+    __get_user(tv->tv_sec, &target_tv->tv_sec);
+    __get_user(tv->tv_usec, &target_tv->tv_usec);
+
+    unlock_user_struct(target_tv, target_tv_addr, 0);
+
     return 0;
 }
 
-static inline abi_long host_to_target_timeval(abi_ulong target_addr,
-                                              const struct timeval *tv)
+static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
+                                            const struct timeval *tv)
 {
     struct target_timeval *target_tv;
 
-    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0))
+    if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
         return -TARGET_EFAULT;
-    target_tv->tv_sec = tswapl(tv->tv_sec);
-    target_tv->tv_usec = tswapl(tv->tv_usec);
-    unlock_user_struct(target_tv, target_addr, 1);
 
+    __put_user(tv->tv_sec, &target_tv->tv_sec);
+    __put_user(tv->tv_usec, &target_tv->tv_usec);
+
+    unlock_user_struct(target_tv, target_tv_addr, 1);
+
     return 0;
 }
 
 
 /* do_select() must return target values and target errnos. */
 static abi_long do_select(int n,
-                          abi_ulong rfd_p, abi_ulong wfd_p,
-                          abi_ulong efd_p, abi_ulong target_tv)
+                          abi_ulong rfd_addr, abi_ulong wfd_addr,
+                          abi_ulong efd_addr, abi_ulong target_tv_addr)
 {
     fd_set rfds, wfds, efds;
     fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
-    abi_long *target_rfds, *target_wfds, *target_efds;
     struct timeval tv, *tv_ptr;
     abi_long ret;
-    int ok;
 
-    if (rfd_p) {
-        target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1);
-        if (!target_rfds) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        rfds_ptr = target_to_host_fds(&rfds, target_rfds, n);
+    if (rfd_addr) {
+        if (copy_from_user_fdset(&rfds, rfd_addr, n))
+            return -TARGET_EFAULT;
+        rfds_ptr = &rfds;
     } else {
-        target_rfds = NULL;
         rfds_ptr = NULL;
     }
-    if (wfd_p) {
-        target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1);
-        if (!target_wfds) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        wfds_ptr = target_to_host_fds(&wfds, target_wfds, n);
+    if (wfd_addr) {
+        if (copy_from_user_fdset(&wfds, wfd_addr, n))
+            return -TARGET_EFAULT;
+        wfds_ptr = &wfds;
     } else {
-        target_wfds = NULL;
         wfds_ptr = NULL;
     }
-    if (efd_p) {
-        target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1);
-        if (!target_efds) {
-            ret = -TARGET_EFAULT;
-            goto end;
-        }
-        efds_ptr = target_to_host_fds(&efds, target_efds, n);
+    if (efd_addr) {
+        if (copy_from_user_fdset(&efds, efd_addr, n))
+            return -TARGET_EFAULT;
+        efds_ptr = &efds;
     } else {
-        target_efds = NULL;
         efds_ptr = NULL;
     }
 
-    if (target_tv) {
-        target_to_host_timeval(&tv, target_tv);
+    if (target_tv_addr) {
+        if (copy_from_user_timeval(&tv, target_tv_addr))
+            return -TARGET_EFAULT;
         tv_ptr = &tv;
     } else {
         tv_ptr = NULL;
     }
+
     ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
-    ok = !is_error(ret);
 
-    if (ok) {
-        host_to_target_fds(target_rfds, rfds_ptr, n);
-        host_to_target_fds(target_wfds, wfds_ptr, n);
-        host_to_target_fds(target_efds, efds_ptr, n);
+    if (!is_error(ret)) {
+        if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+            return -TARGET_EFAULT;
+        if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+            return -TARGET_EFAULT;
+        if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+            return -TARGET_EFAULT;
 
-        if (target_tv) {
-            host_to_target_timeval(target_tv, &tv);
-        }
+        if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
+            return -TARGET_EFAULT;
     }
 
-end:
-    unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0);
-    unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0);
-    unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0);
-
     return ret;
 }
 
@@ -3186,7 +3190,7 @@
 
             argc = 0;
             guest_argp = arg2;
-            for (gp = guest_argp; ; gp++) {
+            for (gp = guest_argp; ; gp += sizeof(abi_ulong)) {
                 if (get_user_ual(addr, gp))
                     goto efault;
                 if (!addr)
@@ -3195,7 +3199,7 @@
             }
             envc = 0;
             guest_envp = arg3;
-            for (gp = guest_envp; ; gp++) {
+            for (gp = guest_envp; ; gp += sizeof(abi_ulong)) {
                 if (get_user_ual(addr, gp))
                     goto efault;
                 if (!addr)
@@ -3391,9 +3395,10 @@
         {
             struct timeval *tvp, tv[2];
             if (arg2) {
-                target_to_host_timeval(&tv[0], arg2);
-                target_to_host_timeval(&tv[1],
-                    arg2 + sizeof (struct target_timeval));
+                if (copy_from_user_timeval(&tv[0], arg2)
+                    || copy_from_user_timeval(&tv[1],
+                                              arg2 + sizeof(struct target_timeval)))
+                    goto efault;
                 tvp = tv;
             } else {
                 tvp = NULL;
@@ -3932,14 +3937,16 @@
             struct timeval tv;
             ret = get_errno(gettimeofday(&tv, NULL));
             if (!is_error(ret)) {
-                host_to_target_timeval(arg1, &tv);
+                if (copy_to_user_timeval(arg1, &tv))
+                    goto efault;
             }
         }
         break;
     case TARGET_NR_settimeofday:
         {
             struct timeval tv;
-            target_to_host_timeval(&tv, arg1);
+            if (copy_from_user_timeval(&tv, arg1))
+                goto efault;
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
@@ -4314,19 +4321,20 @@
 
             if (arg2) {
                 pvalue = &value;
-                target_to_host_timeval(&pvalue->it_interval,
-                                       arg2);
-                target_to_host_timeval(&pvalue->it_value,
-                                       arg2 + sizeof(struct target_timeval));
+                if (copy_from_user_timeval(&pvalue->it_interval, arg2)
+                    || copy_from_user_timeval(&pvalue->it_value,
+                                              arg2 + sizeof(struct target_timeval)))
+                    goto efault;
             } else {
                 pvalue = NULL;
             }
             ret = get_errno(setitimer(arg1, pvalue, &ovalue));
             if (!is_error(ret) && arg3) {
-                host_to_target_timeval(arg3,
-                                       &ovalue.it_interval);
-                host_to_target_timeval(arg3 + sizeof(struct target_timeval),
-                                       &ovalue.it_value);
+                if (copy_to_user_timeval(arg3,
+                                         &ovalue.it_interval)
+                    || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
+                                            &ovalue.it_value))
+                    goto efault;
             }
         }
         break;
@@ -4336,10 +4344,11 @@
 
             ret = get_errno(getitimer(arg1, &value));
             if (!is_error(ret) && arg2) {
-                host_to_target_timeval(arg2,
-                                       &value.it_interval);
-                host_to_target_timeval(arg2 + sizeof(struct target_timeval),
-                                       &value.it_value);
+                if (copy_to_user_timeval(arg2,
+                                         &value.it_interval)
+                    || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
+                                            &value.it_value))
+                    goto efault;
             }
         }
         break;

Modified: trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -1086,10 +1086,10 @@
 #elif defined(TARGET_PPC)
 
 struct target_stat {
-	unsigned short st_dev;
+	abi_ulong st_dev;
 	abi_ulong st_ino;
 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
-	unsigned short st_nlink;
+	abi_ulong st_nlink;
 	unsigned int st_mode;
 #else
 	unsigned int st_mode;
@@ -1097,16 +1097,16 @@
 #endif
 	unsigned int st_uid;
 	unsigned int st_gid;
-	unsigned short st_rdev;
+	abi_ulong  st_rdev;
 	abi_ulong  st_size;
 	abi_ulong  st_blksize;
 	abi_ulong  st_blocks;
 	abi_ulong  target_st_atime;
-	abi_ulong  __unused1;
+	abi_ulong  target_st_atime_nsec;
 	abi_ulong  target_st_mtime;
-	abi_ulong  __unused2;
+	abi_ulong  target_st_mtime_nsec;
 	abi_ulong  target_st_ctime;
-	abi_ulong  __unused3;
+	abi_ulong  target_st_ctime_nsec;
 	abi_ulong  __unused4;
 	abi_ulong  __unused5;
 #if defined(TARGET_PPC64) && !defined(TARGET_ABI32)
@@ -1122,19 +1122,18 @@
 	unsigned int st_uid;
 	unsigned int st_gid;
 	unsigned long long st_rdev;
-	long long pad0;
-	long long st_size;
-	abi_ulong	st_blksize;
-	abi_ulong	pad1;
-	long long	st_blocks;	/* Number 512-byte blocks allocated. */
-	abi_ulong	target_st_atime;
-        abi_ulong    target_st_atime_nsec;
-	abi_ulong	target_st_mtime;
-        abi_ulong    target_st_mtime_nsec;
-	abi_ulong	target_st_ctime;
-        abi_ulong    target_st_ctime_nsec;
-        abi_ulong    __unused4;
-        abi_ulong    __unused5;
+	unsigned short pad0;
+	long long      st_size;
+	int	       st_blksize;
+	long long      st_blocks;	/* Number 512-byte blocks allocated. */
+	int	       target_st_atime;
+        unsigned int   target_st_atime_nsec;
+	int	       target_st_mtime;
+        unsigned int   target_st_mtime_nsec;
+	int            target_st_ctime;
+        unsigned int   target_st_ctime_nsec;
+        unsigned int   __unused4;
+        unsigned int   __unused5;
 };
 
 #elif defined(TARGET_M68K)

Modified: trunk/src/host/qemu-neo1973/target-arm/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/helper.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-arm/helper.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -187,6 +187,7 @@
     if (!env)
         return NULL;
     cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
     env->cp15.c0_cpuid = id;
     cpu_reset(env);
     return env;

Modified: trunk/src/host/qemu-neo1973/target-i386/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/exec.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-i386/exec.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -199,6 +199,7 @@
 void helper_syscall(int next_eip_addend);
 void helper_sysret(int dflag);
 void helper_rdtsc(void);
+void helper_rdpmc(void);
 void helper_rdmsr(void);
 void helper_wrmsr(void);
 void helper_lsl(void);

Modified: trunk/src/host/qemu-neo1973/target-i386/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/helper.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-i386/helper.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -2743,6 +2743,18 @@
     EDX = (uint32_t)(val >> 32);
 }
 
+void helper_rdpmc(void)
+{
+    if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
+        raise_exception(EXCP0D_GPF);
+    }
+
+    if (!svm_check_intercept_param(SVM_EXIT_RDPMC, 0)) {
+        /* currently unimplemented */
+        raise_exception_err(EXCP06_ILLOP, 0);
+    }
+}
+
 #if defined(CONFIG_USER_ONLY)
 void helper_wrmsr(void)
 {
@@ -4250,7 +4262,8 @@
             uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
             uint16_t port = (uint16_t) (param >> 16);
 
-            if(ldub_phys(addr + port / 8) & (1 << (port % 8)))
+            uint16_t mask = (1 << ((param >> 4) & 7)) - 1;
+            if(lduw_phys(addr + port / 8) & (mask << (port & 7)))
                 vmexit(type, param);
         }
         break;

Modified: trunk/src/host/qemu-neo1973/target-i386/helper2.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/helper2.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-i386/helper2.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -99,6 +99,7 @@
     if (!env)
         return NULL;
     cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
 
     /* init various static tables */
     if (!inited) {
@@ -255,7 +256,7 @@
                 }
                 x86_cpu_def->stepping = stepping;
             } else {
-                fprintf(stderr, "unregnized feature %s\n", featurestr);
+                fprintf(stderr, "unrecognized feature %s\n", featurestr);
                 x86_cpu_def = 0;
                 goto error;
             }

Modified: trunk/src/host/qemu-neo1973/target-i386/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/op.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-i386/op.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -953,6 +953,11 @@
     helper_rdtsc();
 }
 
+void OPPROTO op_rdpmc(void)
+{
+    helper_rdpmc();
+}
+
 void OPPROTO op_cpuid(void)
 {
     helper_cpuid();

Modified: trunk/src/host/qemu-neo1973/target-i386/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/translate.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-i386/translate.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -5658,6 +5658,10 @@
         gen_jmp_im(pc_start - s->cs_base);
         gen_op_rdtsc();
         break;
+    case 0x133: /* rdpmc */
+        gen_jmp_im(pc_start - s->cs_base);
+        gen_op_rdpmc();
+        break;
     case 0x134: /* sysenter */
         if (CODE64(s))
             goto illegal_op;

Modified: trunk/src/host/qemu-neo1973/target-m68k/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/helper.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-m68k/helper.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -126,11 +126,13 @@
         return NULL;
     cpu_exec_init(env);
 
+    env->cpu_model_str = cpu_model;
+
     if (cpu_m68k_set_model(env, cpu_model) < 0) {
         cpu_m68k_close(env);
         return NULL;
     }
-        
+
     cpu_reset(env);
     return env;
 }

Modified: trunk/src/host/qemu-neo1973/target-mips/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/translate.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-mips/translate.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -6786,6 +6786,7 @@
     env->cpu_model = def;
 
     cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
     cpu_reset(env);
     return env;
 }

Modified: trunk/src/host/qemu-neo1973/target-ppc/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/cpu.h	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-ppc/cpu.h	2007-12-10 17:51:36 UTC (rev 3627)
@@ -28,7 +28,6 @@
 #if defined (TARGET_PPC64)
 /* PowerPC 64 definitions */
 typedef uint64_t ppc_gpr_t;
-#define TARGET_GPR_BITS  64
 #define TARGET_LONG_BITS 64
 #define TARGET_PAGE_BITS 12
 
@@ -41,10 +40,8 @@
  * the compiler to do unuseful masking in the micro-ops.
  */
 typedef uint64_t ppc_gpr_t;
-#define TARGET_GPR_BITS  64
 #else /* (HOST_LONG_BITS >= 64) */
 typedef uint32_t ppc_gpr_t;
-#define TARGET_GPR_BITS  32
 #endif /* (HOST_LONG_BITS >= 64) */
 
 #define TARGET_LONG_BITS 32
@@ -1235,7 +1232,7 @@
 #define SPR_40x_EVPR          (0x3D6)
 #define SPR_L3PM              (0x3D7)
 #define SPR_403_CDBCR         (0x3D7)
-#define SPR_L3OHCR            (0x3D8)
+#define SPR_L3ITCR0           (0x3D8)
 #define SPR_TCR               (0x3D8)
 #define SPR_40x_TSR           (0x3D8)
 #define SPR_IBR               (0x3DA)
@@ -1248,7 +1245,7 @@
 #define SPR_40x_SRR2          (0x3DE)
 #define SPR_SER               (0x3DF)
 #define SPR_40x_SRR3          (0x3DF)
-#define SPR_L3ITCR0           (0x3E8)
+#define SPR_L3OHCR            (0x3E8)
 #define SPR_L3ITCR1           (0x3E9)
 #define SPR_L3ITCR2           (0x3EA)
 #define SPR_L3ITCR3           (0x3EB)
@@ -1277,6 +1274,7 @@
 #define SPR_MSSCR0            (0x3F6)
 #define SPR_970_HID5          (0x3F6)
 #define SPR_MSSSR0            (0x3F7)
+#define SPR_MSSCR1            (0x3F7)
 #define SPR_DABRX             (0x3F7)
 #define SPR_40x_DAC2          (0x3F7)
 #define SPR_MMUCFG            (0x3F7)

Modified: trunk/src/host/qemu-neo1973/target-ppc/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/helper.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-ppc/helper.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -2976,6 +2976,7 @@
     if (!env)
         return NULL;
     cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
     cpu_ppc_register_internal(env, def);
     cpu_ppc_reset(env);
     return env;

Modified: trunk/src/host/qemu-neo1973/target-ppc/translate_init.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/translate_init.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-ppc/translate_init.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -1149,11 +1149,6 @@
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
     /* XXX : not implemented */
-    spr_register(env, SPR_UBAMR, "UBAMR",
-                 &spr_read_ureg, SPR_NOACCESS,
-                 &spr_read_ureg, SPR_NOACCESS,
-                 0x00000000);
-    /* XXX : not implemented */
     spr_register(env, SPR_MSSCR0, "MSSCR0",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
@@ -1195,30 +1190,6 @@
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
-    /* L3ITCR1 */
-    /* XXX : not implemented */
-    spr_register(env, SPR_L3ITCR1, "L3ITCR1",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
-    /* L3ITCR2 */
-    /* XXX : not implemented */
-    spr_register(env, SPR_L3ITCR2, "L3ITCR2",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
-    /* L3ITCR3 */
-    /* XXX : not implemented */
-    spr_register(env, SPR_L3ITCR3, "L3ITCR3",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
-    /* L3OHCR */
-    /* XXX : not implemented */
-    spr_register(env, SPR_L3OHCR, "L3OHCR",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
     /* L3PM */
     /* XXX : not implemented */
     spr_register(env, SPR_L3PM, "L3PM",
@@ -3052,6 +3023,14 @@
     return 0;
 }
 
+static int check_pow_hid0_74xx (CPUPPCState *env)
+{
+    if (env->spr[SPR_HID0] & 0x00600000)
+        return 1;
+
+    return 0;
+}
+
 /*****************************************************************************/
 /* PowerPC implementations definitions                                       */
 
@@ -4829,6 +4808,7 @@
     ppc6xx_irq_init(env);
 }
 
+/* PowerPC 750CX                                                             */
 #define POWERPC_INSNS_750cx  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
                               PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
                               PPC_FLOAT_FRSQRTE | PPC_FLOAT_STFIWX |          \
@@ -4876,9 +4856,8 @@
                  0x00000000);
     /* Memory management */
     gen_low_BATs(env);
-    /* XXX: high BATs are also present but are known to be bugged on
-     *      die version 1.x
-     */
+    /* PowerPC 750cx has 8 DBATs and 8 IBATs */
+    gen_high_BATs(env);
     init_excp_750cx(env);
     env->dcache_line_size = 32;
     env->icache_line_size = 32;
@@ -5147,7 +5126,7 @@
 #define POWERPC_FLAG_7400    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
                               POWERPC_FLAG_BUS_CLK)
-#define check_pow_7400       check_pow_hid0
+#define check_pow_7400       check_pow_hid0_74xx
 
 static void init_proc_7400 (CPUPPCState *env)
 {
@@ -5157,6 +5136,17 @@
     gen_tbl(env);
     /* 74xx specific SPR */
     gen_spr_74xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX: this seems not implemented on all revisions. */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSCR1, "MSSCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
     /* Thermal management */
     gen_spr_thrm(env);
     /* Memory management */
@@ -5188,7 +5178,7 @@
 #define POWERPC_FLAG_7410    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
                               POWERPC_FLAG_BUS_CLK)
-#define check_pow_7410       check_pow_hid0
+#define check_pow_7410       check_pow_hid0_74xx
 
 static void init_proc_7410 (CPUPPCState *env)
 {
@@ -5198,6 +5188,11 @@
     gen_tbl(env);
     /* 74xx specific SPR */
     gen_spr_74xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
     /* Thermal management */
     gen_spr_thrm(env);
     /* L2PMCR */
@@ -5241,7 +5236,7 @@
 #define POWERPC_FLAG_7440    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
                               POWERPC_FLAG_BUS_CLK)
-#define check_pow_7440       check_pow_hid0
+#define check_pow_7440       check_pow_hid0_74xx
 
 __attribute__ (( unused ))
 static void init_proc_7440 (CPUPPCState *env)
@@ -5252,6 +5247,11 @@
     gen_tbl(env);
     /* 74xx specific SPR */
     gen_spr_74xx(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
     /* LDSTCR */
     /* XXX : not implemented */
     spr_register(env, SPR_LDSTCR, "LDSTCR",
@@ -5321,7 +5321,7 @@
 #define POWERPC_FLAG_7450    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
                               POWERPC_FLAG_BUS_CLK)
-#define check_pow_7450       check_pow_hid0
+#define check_pow_7450       check_pow_hid0_74xx
 
 __attribute__ (( unused ))
 static void init_proc_7450 (CPUPPCState *env)
@@ -5334,6 +5334,35 @@
     gen_spr_74xx(env);
     /* Level 3 cache control */
     gen_l3_ctrl(env);
+    /* L3ITCR1 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR1, "L3ITCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR2 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR2, "L3ITCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR3 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR3, "L3ITCR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3OHCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3OHCR, "L3OHCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
     /* LDSTCR */
     /* XXX : not implemented */
     spr_register(env, SPR_LDSTCR, "LDSTCR",
@@ -5403,7 +5432,7 @@
 #define POWERPC_FLAG_7445    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
                               POWERPC_FLAG_BUS_CLK)
-#define check_pow_7445       check_pow_hid0
+#define check_pow_7445       check_pow_hid0_74xx
 
 __attribute__ (( unused ))
 static void init_proc_7445 (CPUPPCState *env)
@@ -5517,7 +5546,7 @@
 #define POWERPC_FLAG_7455    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
                               POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
                               POWERPC_FLAG_BUS_CLK)
-#define check_pow_7455       check_pow_hid0
+#define check_pow_7455       check_pow_hid0_74xx
 
 __attribute__ (( unused ))
 static void init_proc_7455 (CPUPPCState *env)
@@ -5613,6 +5642,146 @@
     ppc6xx_irq_init(env);
 }
 
+/* PowerPC 7457 (aka G4)                                                     */
+#define POWERPC_INSNS_7457   (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI |                    \
+                              PPC_CACHE_DCBA | PPC_CACHE_DCBZ |               \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_MEM_TLBIA | PPC_74xx_TLB |                  \
+                              PPC_SEGMENT | PPC_EXTERN |                      \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7457    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7457     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7457    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7457   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7457    (bfd_mach_ppc_7400)
+#define POWERPC_FLAG_7457    (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_7457       check_pow_hid0_74xx
+
+__attribute__ (( unused ))
+static void init_proc_7457 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Level 3 cache control */
+    gen_l3_ctrl(env);
+    /* L3ITCR1 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR1, "L3ITCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR2 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR2, "L3ITCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR3 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR3, "L3ITCR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3OHCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3OHCR, "L3OHCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    env->dcache_line_size = 32;
+    env->icache_line_size = 32;
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
 #if defined (TARGET_PPC64)
 /* PowerPC 970                                                               */
 #define POWERPC_INSNS_970    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
@@ -6651,6 +6820,7 @@
     CPU_POWERPC_7400_v10           = 0x000C0100,
     CPU_POWERPC_7400_v11           = 0x000C0101,
     CPU_POWERPC_7400_v20           = 0x000C0200,
+    CPU_POWERPC_7400_v21           = 0x000C0201,
     CPU_POWERPC_7400_v22           = 0x000C0202,
     CPU_POWERPC_7400_v26           = 0x000C0206,
     CPU_POWERPC_7400_v27           = 0x000C0207,
@@ -6671,10 +6841,12 @@
     CPU_POWERPC_7450_v10           = 0x80000100,
     CPU_POWERPC_7450_v11           = 0x80000101,
     CPU_POWERPC_7450_v12           = 0x80000102,
-    CPU_POWERPC_7450_v20           = 0x80000200, /* aka D: 2.04 */
+    CPU_POWERPC_7450_v20           = 0x80000200, /* aka A, B, C, D: 2.04 */
     CPU_POWERPC_7450_v21           = 0x80000201, /* aka E */
-    CPU_POWERPC_74x1               = 0x80000203,
-    CPU_POWERPC_74x1G              = 0x80000210, /* aka G: 2.3 */
+#define CPU_POWERPC_74x1             CPU_POWERPC_74x1_v23
+    CPU_POWERPC_74x1_v23           = 0x80000203, /* aka G: 2.3 */
+    /* XXX: this entry might be a bug in some documentation */
+    CPU_POWERPC_74x1_v210          = 0x80000210, /* aka G: 2.3 ? */
 #define CPU_POWERPC_74x5             CPU_POWERPC_74x5_v32
     CPU_POWERPC_74x5_v10           = 0x80010100,
     /* XXX: missing 0x80010200 */
@@ -8300,6 +8472,8 @@
     POWERPC_DEF("7400_v1.1",     CPU_POWERPC_7400_v11,               7400),
     /* PowerPC 7400 v2.0 (G4)                                                */
     POWERPC_DEF("7400_v2.0",     CPU_POWERPC_7400_v20,               7400),
+    /* PowerPC 7400 v2.1 (G4)                                                */
+    POWERPC_DEF("7400_v2.1",     CPU_POWERPC_7400_v21,               7400),
     /* PowerPC 7400 v2.2 (G4)                                                */
     POWERPC_DEF("7400_v2.2",     CPU_POWERPC_7400_v22,               7400),
     /* PowerPC 7400 v2.6 (G4)                                                */
@@ -8352,10 +8526,16 @@
     POWERPC_DEF("7441",          CPU_POWERPC_74x1,                   7440),
     /* PowerPC 7451 (G4)                                                     */
     POWERPC_DEF("7451",          CPU_POWERPC_74x1,                   7450),
-    /* PowerPC 7441g (G4)                                                    */
-    POWERPC_DEF("7441g",         CPU_POWERPC_74x1G,                  7440),
-    /* PowerPC 7451g (G4)                                                    */
-    POWERPC_DEF("7451g",         CPU_POWERPC_74x1G,                  7450),
+    /* PowerPC 7441 v2.1 (G4)                                                */
+    POWERPC_DEF("7441_v2.1",     CPU_POWERPC_7450_v21,               7440),
+    /* PowerPC 7441 v2.3 (G4)                                                */
+    POWERPC_DEF("7441_v2.3",     CPU_POWERPC_74x1_v23,               7440),
+    /* PowerPC 7451 v2.3 (G4)                                                */
+    POWERPC_DEF("7451_v2.3",     CPU_POWERPC_74x1_v23,               7450),
+    /* PowerPC 7441 v2.10 (G4)                                                */
+    POWERPC_DEF("7441_v2.10",    CPU_POWERPC_74x1_v210,              7440),
+    /* PowerPC 7451 v2.10 (G4)                                               */
+    POWERPC_DEF("7451_v2.10",    CPU_POWERPC_74x1_v210,              7450),
     /* PowerPC 7445 (G4)                                                     */
     POWERPC_DEF("7445",          CPU_POWERPC_74x5,                   7445),
     /* PowerPC 7455 (G4)                                                     */
@@ -8396,8 +8576,6 @@
     POWERPC_DEF("7447_v1.1",     CPU_POWERPC_74x7_v11,               7445),
     /* PowerPC 7457 v1.1 (G4)                                                */
     POWERPC_DEF("7457_v1.1",     CPU_POWERPC_74x7_v11,               7455),
-    /* PowerPC 7447 v1.2 (G4)                                                */
-    POWERPC_DEF("7447_v1.2",     CPU_POWERPC_74x7_v12,               7445),
     /* PowerPC 7457 v1.2 (G4)                                                */
     POWERPC_DEF("7457_v1.2",     CPU_POWERPC_74x7_v12,               7455),
     /* PowerPC 7447A (G4)                                                    */

Modified: trunk/src/host/qemu-neo1973/target-sparc/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/translate.c	2007-12-10 17:40:35 UTC (rev 3626)
+++ trunk/src/host/qemu-neo1973/target-sparc/translate.c	2007-12-10 17:51:36 UTC (rev 3627)
@@ -3792,6 +3792,7 @@
     if (!env)
         return NULL;
     cpu_exec_init(env);
+    env->cpu_model_str = cpu_model;
     env->version = def->iu_version;
     env->fsr = def->fpu_version;
 #if !defined(TARGET_SPARC64)





More information about the commitlog mailing list