r2080 - in trunk/src/host/qemu-neo1973: . hw linux-user pc-bios target-arm target-m68k target-mips target-sparc

andrew at sita.openmoko.org andrew at sita.openmoko.org
Thu May 24 21:28:59 CEST 2007


Author: andrew
Date: 2007-05-24 21:28:30 +0200 (Thu, 24 May 2007)
New Revision: 2080

Added:
   trunk/src/host/qemu-neo1973/hw/an5206.c
   trunk/src/host/qemu-neo1973/hw/mcf5206.c
   trunk/src/host/qemu-neo1973/hw/ptimer.c
   trunk/src/host/qemu-neo1973/target-m68k/op_helper.c
   trunk/src/host/qemu-neo1973/target-m68k/op_mem.h
Removed:
   trunk/src/host/qemu-neo1973/pc-bios/linux_boot.S
   trunk/src/host/qemu-neo1973/pc-bios/linux_boot.bin
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-exec.c
   trunk/src/host/qemu-neo1973/exec-all.h
   trunk/src/host/qemu-neo1973/exec.c
   trunk/src/host/qemu-neo1973/hw/acpi.c
   trunk/src/host/qemu-neo1973/hw/arm_timer.c
   trunk/src/host/qemu-neo1973/hw/esp.c
   trunk/src/host/qemu-neo1973/hw/fdc.c
   trunk/src/host/qemu-neo1973/hw/i2c.h
   trunk/src/host/qemu-neo1973/hw/iommu.c
   trunk/src/host/qemu-neo1973/hw/m48t59.c
   trunk/src/host/qemu-neo1973/hw/m48t59.h
   trunk/src/host/qemu-neo1973/hw/pc.c
   trunk/src/host/qemu-neo1973/hw/pcnet.c
   trunk/src/host/qemu-neo1973/hw/pxa2xx.c
   trunk/src/host/qemu-neo1973/hw/slavio_intctl.c
   trunk/src/host/qemu-neo1973/hw/slavio_misc.c
   trunk/src/host/qemu-neo1973/hw/slavio_serial.c
   trunk/src/host/qemu-neo1973/hw/slavio_timer.c
   trunk/src/host/qemu-neo1973/hw/sparc32_dma.c
   trunk/src/host/qemu-neo1973/hw/sun4m.c
   trunk/src/host/qemu-neo1973/hw/tcx.c
   trunk/src/host/qemu-neo1973/linux-user/main.c
   trunk/src/host/qemu-neo1973/monitor.c
   trunk/src/host/qemu-neo1973/pc-bios/Makefile
   trunk/src/host/qemu-neo1973/pc-bios/README
   trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc32
   trunk/src/host/qemu-neo1973/qemu-doc.texi
   trunk/src/host/qemu-neo1973/softmmu_header.h
   trunk/src/host/qemu-neo1973/target-arm/op.c
   trunk/src/host/qemu-neo1973/target-m68k/cpu.h
   trunk/src/host/qemu-neo1973/target-m68k/exec.h
   trunk/src/host/qemu-neo1973/target-m68k/helper.c
   trunk/src/host/qemu-neo1973/target-m68k/op-hacks.h
   trunk/src/host/qemu-neo1973/target-m68k/op.c
   trunk/src/host/qemu-neo1973/target-m68k/qregs.def
   trunk/src/host/qemu-neo1973/target-m68k/translate.c
   trunk/src/host/qemu-neo1973/target-mips/cpu.h
   trunk/src/host/qemu-neo1973/target-mips/exec.h
   trunk/src/host/qemu-neo1973/target-mips/helper.c
   trunk/src/host/qemu-neo1973/target-mips/op.c
   trunk/src/host/qemu-neo1973/target-mips/op_helper.c
   trunk/src/host/qemu-neo1973/target-mips/op_mem.c
   trunk/src/host/qemu-neo1973/target-mips/translate.c
   trunk/src/host/qemu-neo1973/target-sparc/cpu.h
   trunk/src/host/qemu-neo1973/target-sparc/helper.c
   trunk/src/host/qemu-neo1973/target-sparc/op_helper.c
   trunk/src/host/qemu-neo1973/target-sparc/translate.c
   trunk/src/host/qemu-neo1973/vl.c
   trunk/src/host/qemu-neo1973/vl.h
Log:
Sync this week's changes from upstream.


Modified: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/Makefile	2007-05-24 19:28:30 UTC (rev 2080)
@@ -79,7 +79,7 @@
 	$(INSTALL) -m 755 -s $(TOOLS) "$(DESTDIR)$(bindir)"
 	mkdir -p "$(DESTDIR)$(datadir)"
 	for x in bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \
-		video.x openbios-sparc32 linux_boot.bin pxe-ne2k_pci.bin \
+		video.x openbios-sparc32 pxe-ne2k_pci.bin \
 		pxe-rtl8139.bin pxe-pcnet.bin; do \
 		$(INSTALL) -m 644 $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
 	done
@@ -174,7 +174,6 @@
 	$(datadir)/ppc_rom.bin \
 	$(datadir)/video.x \
 	$(datadir)/openbios-sparc32 \
-	$(datadir)/linux_boot.bin \
         $(datadir)/pxe-ne2k_pci.bin \
 	$(datadir)/pxe-rtl8139.bin \
         $(datadir)/pxe-pcnet.bin \

Modified: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/Makefile.target	2007-05-24 19:28:30 UTC (rev 2080)
@@ -308,7 +308,7 @@
 endif
 
 ifeq ($(TARGET_BASE_ARCH), m68k)
-LIBOBJS+= helper.o
+LIBOBJS+= op_helper.o helper.o
 endif
 
 ifeq ($(TARGET_BASE_ARCH), alpha)
@@ -461,7 +461,7 @@
 ifeq ($(TARGET_BASE_ARCH), arm)
 VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
 VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl181.o pl190.o
-VL_OBJS+= versatile_pci.o sd.o
+VL_OBJS+= versatile_pci.o sd.o ptimer.o
 VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
 VL_OBJS+= arm-semi.o
 VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
@@ -475,6 +475,9 @@
 ifeq ($(TARGET_BASE_ARCH), sh4)
 VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
 endif
+ifeq ($(TARGET_BASE_ARCH), m68k)
+VL_OBJS+= an5206.o mcf5206.o ptimer.o
+endif
 ifdef CONFIG_GDBSTUB
 VL_OBJS+=gdbstub.o 
 endif
@@ -619,8 +622,8 @@
 
 ifeq ($(TARGET_BASE_ARCH), mips)
 helper.o: cpu.h exec-all.h
-op.o: op_template.c fop_template.c op_mem.c exec.h
-op_helper.o: op_helper_mem.c exec.h softmmu_template.h
+op.o: op_template.c fop_template.c op_mem.c exec.h cpu.h
+op_helper.o: op_helper_mem.c exec.h softmmu_template.h cpu.h
 translate.o: translate_init.c exec-all.h disas.h
 endif
 

Modified: trunk/src/host/qemu-neo1973/configure
===================================================================
--- trunk/src/host/qemu-neo1973/configure	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/configure	2007-05-24 19:28:30 UTC (rev 2080)
@@ -468,7 +468,7 @@
 if test -z "$target_list" ; then
 # these targets are portable
     if [ "$softmmu" = "yes" ] ; then
-        target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu "
+        target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu"
     fi
 # the following are Linux specific
     if [ "$linux_user" = "yes" ] ; then

Modified: trunk/src/host/qemu-neo1973/cpu-exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-exec.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/cpu-exec.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -196,7 +196,7 @@
     cs_base = 0;
     pc = env->PC;
 #elif defined(TARGET_M68K)
-    flags = env->fpcr & M68K_FPCR_PREC;
+    flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S);
     cs_base = 0;
     pc = env->pc;
 #elif defined(TARGET_SH4)
@@ -297,7 +297,7 @@
             return EXCP_HALTED;
         }
     }
-#elif defined(TARGET_ALPHA)
+#elif defined(TARGET_ALPHA) || defined(TARGET_M68K)
     if (env1->halted) {
         if (env1->interrupt_request & CPU_INTERRUPT_HARD) {
             env1->halted = 0;
@@ -390,6 +390,8 @@
 		    do_interrupt(env);
 #elif defined(TARGET_ALPHA)
                     do_interrupt(env);
+#elif defined(TARGET_M68K)
+                    do_interrupt(0);
 #endif
                 }
                 env->exception_index = -1;
@@ -542,6 +544,18 @@
                     if (interrupt_request & CPU_INTERRUPT_HARD) {
                         do_interrupt(env);
                     }
+#elif defined(TARGET_M68K)
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && ((env->sr & SR_I) >> SR_I_SHIFT)
+                            < env->pending_level) {
+                        /* Real hardware gets the interrupt vector via an
+                           IACK cycle at this point.  Current emulated
+                           hardware doesn't rely on this, so we
+                           provide/save the vector when the interrupt is
+                           first signalled.  */
+                        env->exception_index = env->pending_vector;
+                        do_interrupt(1);
+                    }
 #endif
                    /* Don't use the cached interupt_request value,
                       do_interrupt may have updated the EXITTB flag. */

Modified: trunk/src/host/qemu-neo1973/exec-all.h
===================================================================
--- trunk/src/host/qemu-neo1973/exec-all.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/exec-all.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -584,6 +584,8 @@
     is_user = ((env->sr & SR_MD) == 0);
 #elif defined (TARGET_ALPHA)
     is_user = ((env->ps >> 3) & 3);
+#elif defined (TARGET_M68K)
+    is_user = ((env->sr & SR_S) == 0);
 #else
 #error unimplemented CPU
 #endif
@@ -593,7 +595,11 @@
     }
     pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
     if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+#ifdef TARGET_SPARC
+        do_unassigned_access(addr, 0, 1, 0);
+#else
         cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
+#endif
     }
     return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
 }

Modified: trunk/src/host/qemu-neo1973/exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/exec.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/exec.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -64,6 +64,8 @@
 
 #if defined(TARGET_SPARC64)
 #define TARGET_PHYS_ADDR_SPACE_BITS 41
+#elif defined(TARGET_SPARC)
+#define TARGET_PHYS_ADDR_SPACE_BITS 36
 #elif defined(TARGET_ALPHA)
 #define TARGET_PHYS_ADDR_SPACE_BITS 42
 #define TARGET_VIRT_ADDR_SPACE_BITS 42
@@ -1957,11 +1959,10 @@
 static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
 {
 #ifdef DEBUG_UNASSIGNED
-    printf("Unassigned mem read  0x%08x\n", (int)addr);
+    printf("Unassigned mem read " TARGET_FMT_lx "\n", addr);
 #endif
 #ifdef TARGET_SPARC
-    // Not enabled yet because of bugs in gdbstub etc.
-    //raise_exception(TT_DATA_ACCESS);
+    do_unassigned_access(addr, 0, 0, 0);
 #endif
     return 0;
 }
@@ -1969,11 +1970,10 @@
 static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
 #ifdef DEBUG_UNASSIGNED
-    printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
+    printf("Unassigned mem write " TARGET_FMT_lx " = 0x%x\n", addr, val);
 #endif
 #ifdef TARGET_SPARC
-    // Not enabled yet because of bugs in gdbstub etc.
-    //raise_exception(TT_DATA_ACCESS);
+    do_unassigned_access(addr, 1, 0, 0);
 #endif
 }
 

Modified: trunk/src/host/qemu-neo1973/hw/acpi.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/acpi.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/acpi.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -281,7 +281,7 @@
     case 0x3:
         if (read) {
             uint16_t val;
-            smbus_read_word(bus, addr, cmd);
+            val = smbus_read_word(bus, addr, cmd);
             s->smb_data0 = val;
             s->smb_data1 = val >> 8;
         } else {

Added: trunk/src/host/qemu-neo1973/hw/an5206.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/an5206.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/an5206.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -0,0 +1,89 @@
+/* 
+ * Arnewsh 5206 ColdFire system emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+
+#include "vl.h"
+
+#define KERNEL_LOAD_ADDR 0x10000
+#define AN5206_MBAR_ADDR 0x10000000
+#define AN5206_RAMBAR_ADDR 0x20000000
+
+/* Stub functions for hardware that doesn't exist.  */
+void pic_info(void)
+{
+}
+
+void irq_info(void)
+{
+}
+
+void DMA_run (void)
+{
+}
+
+/* Board init.  */
+
+static void an5206_init(int ram_size, int vga_ram_size, int boot_device,
+                     DisplayState *ds, const char **fd_filename, int snapshot,
+                     const char *kernel_filename, const char *kernel_cmdline,
+                     const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    int kernel_size;
+    uint64_t elf_entry;
+    target_ulong entry;
+
+    env = cpu_init();
+    if (!cpu_model)
+        cpu_model = "m5206";
+    cpu_m68k_set_model(env, cpu_model);
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+    /* TODO: allow changing MBAR and RAMBAR.  */
+    env->mbar = AN5206_MBAR_ADDR | 1;
+    env->rambar0 = AN5206_RAMBAR_ADDR | 1;
+
+    /* DRAM at address zero */
+    cpu_register_physical_memory(0, ram_size,
+        qemu_ram_alloc(ram_size) | IO_MEM_RAM);
+
+    /* Internal SRAM.  */
+    cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
+        qemu_ram_alloc(512) | IO_MEM_RAM);
+
+    mcf5206_init(AN5206_MBAR_ADDR, env);
+
+    /* Load kernel.  */
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+
+    kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+    entry = elf_entry;
+    if (kernel_size < 0) {
+        kernel_size = load_uboot(kernel_filename, &entry, NULL);
+    }
+    if (kernel_size < 0) {
+        kernel_size = load_image(kernel_filename,
+                                 phys_ram_base + KERNEL_LOAD_ADDR);
+        entry = KERNEL_LOAD_ADDR;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+
+    env->pc = entry;
+}
+
+QEMUMachine an5206_machine = {
+    "an5206",
+    "Arnewsh 5206",
+    an5206_init,
+};

Modified: trunk/src/host/qemu-neo1973/hw/arm_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_timer.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/arm_timer.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -22,116 +22,26 @@
 #define TIMER_CTRL_ENABLE       (1 << 7)
 
 typedef struct {
-    int64_t next_time;
-    int64_t expires;
-    int64_t loaded;
-    QEMUTimer *timer;
+    ptimer_state *timer;
     uint32_t control;
-    uint32_t count;
     uint32_t limit;
-    int raw_freq;
     int freq;
     int int_level;
     qemu_irq irq;
 } arm_timer_state;
 
-/* Calculate the new expiry time of the given timer.  */
-
-static void arm_timer_reload(arm_timer_state *s)
-{
-    int64_t delay;
-
-    s->loaded = s->expires;
-    delay = muldiv64(s->count, ticks_per_sec, s->freq);
-    if (delay == 0)
-        delay = 1;
-    s->expires += delay;
-}
-
 /* Check all active timers, and schedule the next timer interrupt.  */
 
-static void arm_timer_update(arm_timer_state *s, int64_t now)
+static void arm_timer_update(arm_timer_state *s)
 {
-    int64_t next;
-
-    /* Ignore disabled timers.  */
-    if ((s->control & TIMER_CTRL_ENABLE) == 0)
-        return;
-    /* Ignore expired one-shot timers.  */
-    if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
-        return;
-    if (s->expires - now <= 0) {
-        /* Timer has expired.  */
-        s->int_level = 1;
-        if (s->control & TIMER_CTRL_ONESHOT) {
-            /* One-shot.  */
-            s->count = 0;
-        } else {
-            if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
-                /* Free running.  */
-                if (s->control & TIMER_CTRL_32BIT)
-                    s->count = 0xffffffff;
-                else
-                    s->count = 0xffff;
-            } else {
-                  /* Periodic.  */
-                  s->count = s->limit;
-            }
-        }
-    }
-    while (s->expires - now <= 0) {
-        arm_timer_reload(s);
-    }
     /* Update interrupts.  */
     if (s->int_level && (s->control & TIMER_CTRL_IE)) {
         qemu_irq_raise(s->irq);
     } else {
         qemu_irq_lower(s->irq);
     }
-
-    next = now;
-    if (next - s->expires < 0)
-        next = s->expires;
-
-    /* Schedule the next timer interrupt.  */
-    if (next == now) {
-        qemu_del_timer(s->timer);
-        s->next_time = 0;
-    } else if (next != s->next_time) {
-        qemu_mod_timer(s->timer, next);
-        s->next_time = next;
-    }
 }
 
-/* Return the current value of the timer.  */
-static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
-{
-    int64_t left;
-    int64_t period;
-
-    if (s->count == 0)
-        return 0;
-    if ((s->control & TIMER_CTRL_ENABLE) == 0)
-        return s->count;
-    left = s->expires - now;
-    period = s->expires - s->loaded;
-    /* If the timer should have expired then return 0.  This can happen
-       when the host timer signal doesnt occur immediately.  It's better to
-       have a timer appear to sit at zero for a while than have it wrap
-       around before the guest interrupt is raised.  */
-    /* ??? Could we trigger the interrupt here?  */
-    if (left < 0)
-        return 0;
-    /* We need to calculate count * elapsed / period without overfowing.
-       Scale both elapsed and period so they fit in a 32-bit int.  */
-    while (period != (int32_t)period) {
-        period >>= 1;
-        left >>= 1;
-    }
-    return ((uint64_t)s->count * (uint64_t)(int32_t)left)
-            / (int32_t)period;
-}
-
 uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
 {
     arm_timer_state *s = (arm_timer_state *)opaque;
@@ -141,7 +51,7 @@
     case 6: /* TimerBGLoad */
         return s->limit;
     case 1: /* TimerValue */
-        return arm_timer_getcount(s, qemu_get_clock(vm_clock));
+        return ptimer_get_count(s->timer);
     case 2: /* TimerControl */
         return s->control;
     case 4: /* TimerRIS */
@@ -151,24 +61,40 @@
             return 0;
         return s->int_level;
     default:
-        cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
+        cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n",
+                   (int)offset);
         return 0;
     }
 }
 
+/* Reset the timer limit after settings have changed.  */
+static void arm_timer_recalibrate(arm_timer_state *s, int reload)
+{
+    uint32_t limit;
+
+    if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
+        /* Free running.  */
+        if (s->control & TIMER_CTRL_32BIT)
+            limit = 0xffffffff;
+        else
+            limit = 0xffff;
+    } else {
+          /* Periodic.  */
+          limit = s->limit;
+    }
+    ptimer_set_limit(s->timer, limit, reload);
+}
+
 static void arm_timer_write(void *opaque, target_phys_addr_t offset,
                             uint32_t value)
 {
     arm_timer_state *s = (arm_timer_state *)opaque;
-    int64_t now;
+    int freq;
 
-    now = qemu_get_clock(vm_clock);
     switch (offset >> 2) {
     case 0: /* TimerLoad */
         s->limit = value;
-        s->count = value;
-        s->expires = now;
-        arm_timer_reload(s);
+        arm_timer_recalibrate(s, 1);
         break;
     case 1: /* TimerValue */
         /* ??? Linux seems to want to write to this readonly register.
@@ -179,19 +105,20 @@
             /* Pause the timer if it is running.  This may cause some
                inaccuracy dure to rounding, but avoids a whole lot of other
                messyness.  */
-            s->count = arm_timer_getcount(s, now);
+            ptimer_stop(s->timer);
         }
         s->control = value;
-        s->freq = s->raw_freq;
+        freq = s->freq;
         /* ??? Need to recalculate expiry time after changing divisor.  */
         switch ((value >> 2) & 3) {
-        case 1: s->freq >>= 4; break;
-        case 2: s->freq >>= 8; break;
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 8; break;
         }
+        arm_timer_recalibrate(s, 0);
+        ptimer_set_freq(s->timer, freq);
         if (s->control & TIMER_CTRL_ENABLE) {
             /* Restart the timer if still enabled.  */
-            s->expires = now;
-            arm_timer_reload(s);
+            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
         }
         break;
     case 3: /* TimerIntClr */
@@ -199,32 +126,34 @@
         break;
     case 6: /* TimerBGLoad */
         s->limit = value;
+        arm_timer_recalibrate(s, 0);
         break;
     default:
-        cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
+        cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n",
+                   (int)offset);
     }
-    arm_timer_update(s, now);
+    arm_timer_update(s);
 }
 
 static void arm_timer_tick(void *opaque)
 {
-    int64_t now;
-
-    now = qemu_get_clock(vm_clock);
-    arm_timer_update((arm_timer_state *)opaque, now);
+    arm_timer_state *s = (arm_timer_state *)opaque;
+    s->int_level = 1;
+    arm_timer_update(s);
 }
 
 static void *arm_timer_init(uint32_t freq, qemu_irq irq)
 {
     arm_timer_state *s;
+    QEMUBH *bh;
 
     s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
     s->irq = irq;
-    s->raw_freq = s->freq = 1000000;
+    s->freq = freq;
     s->control = TIMER_CTRL_IE;
-    s->count = 0xffffffff;
 
-    s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
+    bh = qemu_bh_new(arm_timer_tick, s);
+    s->timer = ptimer_init(bh);
     /* ??? Save/restore.  */
     return s;
 }

Modified: trunk/src/host/qemu-neo1973/hw/esp.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/esp.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/esp.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -562,7 +562,8 @@
     s->scsi_dev[id] = scsi_disk_init(bd, 0, esp_command_complete, s);
 }
 
-void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque)
+void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
+               void *dma_opaque)
 {
     ESPState *s;
     int esp_io_memory;

Modified: trunk/src/host/qemu-neo1973/hw/fdc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/fdc.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/fdc.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -370,7 +370,7 @@
     /* HW */
     qemu_irq irq;
     int dma_chann;
-    uint32_t io_base;
+    target_phys_addr_t io_base;
     /* Controller state */
     QEMUTimer *result_timer;
     uint8_t state;
@@ -464,13 +464,13 @@
 
 static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
 {
-    return fdctrl_read(opaque, reg);
+    return fdctrl_read(opaque, (uint32_t)reg);
 }
 
 static void fdctrl_write_mem (void *opaque, 
                               target_phys_addr_t reg, uint32_t value)
 {
-    fdctrl_write(opaque, reg, value);
+    fdctrl_write(opaque, (uint32_t)reg, value);
 }
 
 static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
@@ -579,7 +579,7 @@
 }
 
 fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, 
-                       uint32_t io_base,
+                       target_phys_addr_t io_base,
                        BlockDriverState **fds)
 {
     fdctrl_t *fdctrl;
@@ -613,10 +613,14 @@
         io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
         cpu_register_physical_memory(io_base, 0x08, io_mem);
     } else {
-        register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
-        register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
-        register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
-        register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
+        register_ioport_read((uint32_t)io_base + 0x01, 5, 1, &fdctrl_read,
+                             fdctrl);
+        register_ioport_read((uint32_t)io_base + 0x07, 1, 1, &fdctrl_read,
+                             fdctrl);
+        register_ioport_write((uint32_t)io_base + 0x01, 5, 1, &fdctrl_write,
+                              fdctrl);
+        register_ioport_write((uint32_t)io_base + 0x07, 1, 1, &fdctrl_write,
+                              fdctrl);
     }
     register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
     qemu_register_reset(fdctrl_external_reset, fdctrl);

Modified: trunk/src/host/qemu-neo1973/hw/i2c.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i2c.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/i2c.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -80,4 +80,5 @@
 void pcf_gpo_handler_set(i2c_slave *i2c, int line, qemu_irq handler);
 void pcf_onkey_set(i2c_slave *i2c, int level);
 void pcf_exton_set(i2c_slave *i2c, int level);
+
 #endif

Modified: trunk/src/host/qemu-neo1973/hw/iommu.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/iommu.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/iommu.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -87,15 +87,15 @@
 #define PAGE_MASK	(PAGE_SIZE - 1)
 
 typedef struct IOMMUState {
-    uint32_t addr;
+    target_phys_addr_t addr;
     uint32_t regs[IOMMU_NREGS];
-    uint32_t iostart;
+    target_phys_addr_t iostart;
 } IOMMUState;
 
 static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     IOMMUState *s = opaque;
-    uint32_t saddr;
+    target_phys_addr_t saddr;
 
     saddr = (addr - s->addr) >> 2;
     switch (saddr) {
@@ -110,7 +110,7 @@
 static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     IOMMUState *s = opaque;
-    uint32_t saddr;
+    target_phys_addr_t saddr;
 
     saddr = (addr - s->addr) >> 2;
     DPRINTF("write reg[%d] = %x\n", saddr, val);
@@ -118,32 +118,32 @@
     case IOMMU_CTRL:
 	switch (val & IOMMU_CTRL_RNGE) {
 	case IOMMU_RNGE_16MB:
-	    s->iostart = 0xff000000;
+	    s->iostart = 0xffffffffff000000ULL;
 	    break;
 	case IOMMU_RNGE_32MB:
-	    s->iostart = 0xfe000000;
+	    s->iostart = 0xfffffffffe000000ULL;
 	    break;
 	case IOMMU_RNGE_64MB:
-	    s->iostart = 0xfc000000;
+	    s->iostart = 0xfffffffffc000000ULL;
 	    break;
 	case IOMMU_RNGE_128MB:
-	    s->iostart = 0xf8000000;
+	    s->iostart = 0xfffffffff8000000ULL;
 	    break;
 	case IOMMU_RNGE_256MB:
-	    s->iostart = 0xf0000000;
+	    s->iostart = 0xfffffffff0000000ULL;
 	    break;
 	case IOMMU_RNGE_512MB:
-	    s->iostart = 0xe0000000;
+	    s->iostart = 0xffffffffe0000000ULL;
 	    break;
 	case IOMMU_RNGE_1GB:
-	    s->iostart = 0xc0000000;
+	    s->iostart = 0xffffffffc0000000ULL;
 	    break;
 	default:
 	case IOMMU_RNGE_2GB:
-	    s->iostart = 0x80000000;
+	    s->iostart = 0xffffffff80000000ULL;
 	    break;
 	}
-	DPRINTF("iostart = %x\n", s->iostart);
+	DPRINTF("iostart = %llx\n", s->iostart);
 	s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION);
 	break;
     case IOMMU_BASE:
@@ -186,7 +186,7 @@
     iommu_mem_writew,
 };
 
-static uint32_t iommu_page_get_flags(IOMMUState *s, uint32_t addr)
+static uint32_t iommu_page_get_flags(IOMMUState *s, target_phys_addr_t addr)
 {
     uint32_t iopte;
 
@@ -196,21 +196,27 @@
     return ldl_phys(iopte);
 }
 
-static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa)
+static target_phys_addr_t iommu_translate_pa(IOMMUState *s,
+                                             target_phys_addr_t addr,
+                                             uint32_t pte)
 {
     uint32_t tmppte;
+    target_phys_addr_t pa;
 
-    tmppte = pa;
-    pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
-    DPRINTF("xlate dva %x => pa %x (iopte = %x)\n", addr, pa, tmppte);
+    tmppte = pte;
+    pa = ((pte & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
+    DPRINTF("xlate dva " TARGET_FMT_plx " => pa " TARGET_FMT_plx
+            " (iopte = %x)\n", addr, pa, tmppte);
+
     return pa;
 }
 
 void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
                            uint8_t *buf, int len, int is_write)
 {
-    int l, flags;
-    target_ulong page, phys_addr;
+    int l;
+    uint32_t flags;
+    target_phys_addr_t page, phys_addr;
 
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
@@ -239,10 +245,9 @@
     IOMMUState *s = opaque;
     int i;
     
-    qemu_put_be32s(f, &s->addr);
     for (i = 0; i < IOMMU_NREGS; i++)
 	qemu_put_be32s(f, &s->regs[i]);
-    qemu_put_be32s(f, &s->iostart);
+    qemu_put_be64s(f, &s->iostart);
 }
 
 static int iommu_load(QEMUFile *f, void *opaque, int version_id)
@@ -250,13 +255,12 @@
     IOMMUState *s = opaque;
     int i;
     
-    if (version_id != 1)
+    if (version_id != 2)
         return -EINVAL;
 
-    qemu_get_be32s(f, &s->addr);
     for (i = 0; i < IOMMU_NREGS; i++)
 	qemu_put_be32s(f, &s->regs[i]);
-    qemu_get_be32s(f, &s->iostart);
+    qemu_get_be64s(f, &s->iostart);
 
     return 0;
 }
@@ -270,7 +274,7 @@
     s->regs[0] = IOMMU_VERSION;
 }
 
-void *iommu_init(uint32_t addr)
+void *iommu_init(target_phys_addr_t addr)
 {
     IOMMUState *s;
     int iommu_io_memory;
@@ -284,7 +288,7 @@
     iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
     cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
     
-    register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
+    register_savevm("iommu", addr, 2, iommu_save, iommu_load, s);
     qemu_register_reset(iommu_reset, s);
     return s;
 }

Modified: trunk/src/host/qemu-neo1973/hw/m48t59.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/m48t59.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/m48t59.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -43,7 +43,7 @@
     /* Hardware parameters */
     qemu_irq IRQ;
     int mem_index;
-    uint32_t mem_base;
+    target_phys_addr_t mem_base;
     uint32_t io_base;
     uint16_t size;
     /* RTC management */
@@ -610,12 +610,12 @@
 }
 
 /* Initialisation routine */
-m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base,
+m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base,
                        uint32_t io_base, uint16_t size,
                        int type)
 {
     m48t59_t *s;
-    target_ulong save_base;
+    target_phys_addr_t save_base;
 
     s = qemu_mallocz(sizeof(m48t59_t));
     if (!s)

Modified: trunk/src/host/qemu-neo1973/hw/m48t59.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/m48t59.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/m48t59.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -6,7 +6,7 @@
 void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val);
 uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr);
 void m48t59_toggle_lock (m48t59_t *NVRAM, int lock);
-m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base,
+m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base,
                        uint32_t io_base, uint16_t size,
                        int type);
 

Added: trunk/src/host/qemu-neo1973/hw/mcf5206.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mcf5206.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/mcf5206.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -0,0 +1,813 @@
+/* 
+ * Motorola ColdFire MCF5206 SoC embedded peripheral emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+#include "vl.h"
+
+/* General purpose timer module.  */
+typedef struct {
+    uint16_t tmr;
+    uint16_t trr;
+    uint16_t tcr;
+    uint16_t ter;
+    ptimer_state *timer;
+    qemu_irq irq;
+    int irq_state;
+} m5206_timer_state;
+
+#define TMR_RST 0x01
+#define TMR_CLK 0x06
+#define TMR_FRR 0x08
+#define TMR_ORI 0x10
+#define TMR_OM  0x20
+#define TMR_CE  0xc0
+
+#define TER_CAP 0x01
+#define TER_REF 0x02
+
+static void m5206_timer_update(m5206_timer_state *s)
+{
+    if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void m5206_timer_reset(m5206_timer_state *s)
+{
+    s->tmr = 0;
+    s->trr = 0;
+}
+
+static void m5206_timer_recalibrate(m5206_timer_state *s)
+{
+    int prescale;
+    int mode;
+
+    ptimer_stop(s->timer);
+
+    if ((s->tmr & TMR_RST) == 0)
+        return;
+
+    prescale = (s->tmr >> 8) + 1;
+    mode = (s->tmr >> 1) & 3;
+    if (mode == 2)
+        prescale *= 16;
+
+    if (mode == 3 || mode == 0)
+        cpu_abort(cpu_single_env, 
+                  "m5206_timer: mode %d not implemented\n", mode);
+    if ((s->tmr & TMR_FRR) == 0)
+        cpu_abort(cpu_single_env,
+                  "m5206_timer: free running mode not implemented\n");
+
+    /* Assume 66MHz system clock.  */
+    ptimer_set_freq(s->timer, 66000000 / prescale);
+
+    ptimer_set_limit(s->timer, s->trr, 0);
+
+    ptimer_run(s->timer, 0);
+}
+
+static void m5206_timer_trigger(void *opaque)
+{
+    m5206_timer_state *s = (m5206_timer_state *)opaque;
+    s->ter |= TER_REF;
+    m5206_timer_update(s);
+}
+
+static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr)
+{
+    switch (addr) {
+    case 0:
+        return s->tmr;
+    case 4:
+        return s->trr;
+    case 8:
+        return s->tcr;
+    case 0xc:
+        return s->trr - ptimer_get_count(s->timer);
+    case 0x11:
+        return s->ter;
+    default:
+        return 0;
+    }
+}
+
+static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val)
+{
+    switch (addr) {
+    case 0:
+        if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) {
+            m5206_timer_reset(s);
+        }
+        s->tmr = val;
+        m5206_timer_recalibrate(s);
+        break;
+    case 4:
+        s->trr = val;
+        m5206_timer_recalibrate(s);
+        break;
+    case 8:
+        s->tcr = val;
+        break;
+    case 0xc:
+        ptimer_set_count(s->timer, val);
+        break;
+    case 0x11:
+        s->ter &= ~val;
+        break;
+    default:
+        break;
+    }
+    m5206_timer_update(s);
+}
+
+static m5206_timer_state *m5206_timer_init(qemu_irq irq)
+{
+    m5206_timer_state *s;
+    QEMUBH *bh;
+
+    s = (m5206_timer_state *)qemu_mallocz(sizeof(m5206_timer_state));
+    bh = qemu_bh_new(m5206_timer_trigger, s);
+    s->timer = ptimer_init(bh);
+    s->irq = irq;
+    m5206_timer_reset(s);
+    return s;
+}
+
+/* UART */
+
+typedef struct {
+    uint8_t mr[2];
+    uint8_t sr;
+    uint8_t isr;
+    uint8_t imr;
+    uint8_t bg1;
+    uint8_t bg2;
+    uint8_t fifo[4];
+    uint8_t tb;
+    int current_mr;
+    int fifo_len;
+    int tx_enabled;
+    int rx_enabled;
+    qemu_irq irq;
+    CharDriverState *chr;
+} m5206_uart_state;
+
+/* UART Status Register bits.  */
+#define M5206_UART_RxRDY  0x01
+#define M5206_UART_FFULL  0x02
+#define M5206_UART_TxRDY  0x04
+#define M5206_UART_TxEMP  0x08
+#define M5206_UART_OE     0x10
+#define M5206_UART_PE     0x20
+#define M5206_UART_FE     0x40
+#define M5206_UART_RB     0x80
+
+/* Interrupt flags.  */
+#define M5206_UART_TxINT  0x01
+#define M5206_UART_RxINT  0x02
+#define M5206_UART_DBINT  0x04
+#define M5206_UART_COSINT 0x80
+
+/* UMR1 flags.  */
+#define M5206_UART_BC0    0x01
+#define M5206_UART_BC1    0x02
+#define M5206_UART_PT     0x04
+#define M5206_UART_PM0    0x08
+#define M5206_UART_PM1    0x10
+#define M5206_UART_ERR    0x20
+#define M5206_UART_RxIRQ  0x40
+#define M5206_UART_RxRTS  0x80
+
+static void m5206_uart_update(m5206_uart_state *s)
+{
+    s->isr &= ~(M5206_UART_TxINT | M5206_UART_RxINT);
+    if (s->sr & M5206_UART_TxRDY)
+        s->isr |= M5206_UART_TxINT;
+    if ((s->sr & ((s->mr[0] & M5206_UART_RxIRQ)
+                  ? M5206_UART_FFULL : M5206_UART_RxRDY)) != 0)
+        s->isr |= M5206_UART_RxINT;
+
+    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
+}
+
+static uint32_t m5206_uart_read(m5206_uart_state *s, uint32_t addr)
+{
+    switch (addr) {
+    case 0x00:
+        return s->mr[s->current_mr];
+    case 0x04:
+        return s->sr;
+    case 0x0c:
+        {
+            uint8_t val;
+            int i;
+
+            if (s->fifo_len == 0)
+                return 0;
+
+            val = s->fifo[0];
+            s->fifo_len--;
+            for (i = 0; i < s->fifo_len; i++)
+                s->fifo[i] = s->fifo[i + 1];
+            s->sr &= ~M5206_UART_FFULL;
+            if (s->fifo_len == 0)
+                s->sr &= ~M5206_UART_RxRDY;
+            m5206_uart_update(s);
+            return val;
+        }
+    case 0x10:
+        /* TODO: Implement IPCR.  */
+        return 0;
+    case 0x14:
+        return s->isr;
+    case 0x18:
+        return s->bg1;
+    case 0x1c:
+        return s->bg2;
+    default:
+        return 0;
+    }
+}
+
+/* Update TxRDY flag and set data if present and enabled.  */
+static void m5206_uart_do_tx(m5206_uart_state *s)
+{
+    if (s->tx_enabled && (s->sr & M5206_UART_TxEMP) == 0) {
+        if (s->chr)
+            qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
+        s->sr |= M5206_UART_TxEMP;
+    }
+    if (s->tx_enabled) {
+        s->sr |= M5206_UART_TxRDY;
+    } else {
+        s->sr &= ~M5206_UART_TxRDY;
+    }
+}
+
+static void m5206_do_command(m5206_uart_state *s, uint8_t cmd)
+{
+    /* Misc command.  */
+    switch ((cmd >> 4) & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Reset mode register pointer.  */
+        s->current_mr = 0;
+        break;
+    case 2: /* Reset receiver.  */
+        s->rx_enabled = 0;
+        s->fifo_len = 0;
+        s->sr &= ~(M5206_UART_RxRDY | M5206_UART_FFULL);
+        break;
+    case 3: /* Reset transmitter.  */
+        s->tx_enabled = 0;
+        s->sr |= M5206_UART_TxEMP;
+        s->sr &= ~M5206_UART_TxRDY;
+        break;
+    case 4: /* Reset error status.  */
+        break;
+    case 5: /* Reset break-change interrupt.  */
+        s->isr &= ~M5206_UART_DBINT;
+        break;
+    case 6: /* Start break.  */
+    case 7: /* Stop break.  */
+        break;
+    }
+
+    /* Transmitter command.  */
+    switch ((cmd >> 2) & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Enable.  */
+        s->tx_enabled = 1;
+        m5206_uart_do_tx(s);
+        break;
+    case 2: /* Disable.  */
+        s->tx_enabled = 0;
+        m5206_uart_do_tx(s);
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "m5206_uart: Bad TX command\n");
+        break;
+    }
+
+    /* Receiver command.  */
+    switch (cmd & 3) {
+    case 0: /* No-op.  */
+        break;
+    case 1: /* Enable.  */
+        s->rx_enabled = 1;
+        break;
+    case 2:
+        s->rx_enabled = 0;
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "m5206_uart: Bad RX command\n");
+        break;
+    }
+}
+
+static void m5206_uart_write(m5206_uart_state *s, uint32_t addr, uint32_t val)
+{
+    switch (addr) {
+    case 0x00:
+        s->mr[s->current_mr] = val;
+        s->current_mr = 1;
+        break;
+    case 0x04:
+        /* CSR is ignored.  */
+        break;
+    case 0x08: /* Command Register.  */
+        m5206_do_command(s, val);
+        break;
+    case 0x0c: /* Transmit Buffer.  */
+        s->sr &= ~M5206_UART_TxEMP;
+        s->tb = val;
+        m5206_uart_do_tx(s);
+        break;
+    case 0x10:
+        /* ACR is ignored.  */
+        break;
+    case 0x14:
+        s->imr = val;
+        break;
+    default:
+        break;
+    }
+    m5206_uart_update(s);
+}
+
+static void m5206_uart_reset(m5206_uart_state *s)
+{
+    s->fifo_len = 0;
+    s->mr[0] = 0;
+    s->mr[1] = 0;
+    s->sr = M5206_UART_TxEMP;
+    s->tx_enabled = 0;
+    s->rx_enabled = 0;
+    s->isr = 0;
+    s->imr = 0;
+}
+
+static void m5206_uart_push_byte(m5206_uart_state *s, uint8_t data)
+{
+    /* Break events overwrite the last byte if the fifo is full.  */
+    if (s->fifo_len == 4)
+        s->fifo_len--;
+
+    s->fifo[s->fifo_len] = data;
+    s->fifo_len++;
+    s->sr |= M5206_UART_RxRDY;
+    if (s->fifo_len == 4)
+        s->sr |= M5206_UART_FFULL;
+
+    m5206_uart_update(s);
+}
+
+static void m5206_uart_event(void *opaque, int event)
+{
+    m5206_uart_state *s = (m5206_uart_state *)opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        s->isr |= M5206_UART_DBINT;
+        m5206_uart_push_byte(s, 0);
+        break;
+    default:
+        break;
+    }
+}
+
+static int m5206_uart_can_receive(void *opaque)
+{
+    m5206_uart_state *s = (m5206_uart_state *)opaque;
+
+    return s->rx_enabled && (s->sr & M5206_UART_FFULL) == 0;
+}
+
+static void m5206_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    m5206_uart_state *s = (m5206_uart_state *)opaque;
+
+    m5206_uart_push_byte(s, buf[0]);
+}
+
+static m5206_uart_state *m5206_uart_init(qemu_irq irq, CharDriverState *chr)
+{
+    m5206_uart_state *s;
+
+    s = qemu_mallocz(sizeof(m5206_uart_state));
+    s->chr = chr;
+    s->irq = irq;
+    if (chr) {
+        qemu_chr_add_handlers(chr, m5206_uart_can_receive, m5206_uart_receive,
+                              m5206_uart_event, s);
+    }
+    m5206_uart_reset(s);
+    return s;
+}
+
+/* System Integration Module.  */
+
+typedef struct {
+    CPUState *env;
+    m5206_timer_state *timer[2];
+    m5206_uart_state *uart[2];
+    uint8_t scr;
+    uint8_t icr[14];
+    uint16_t imr; /* 1 == interrupt is masked.  */
+    uint16_t ipr;
+    uint8_t rsr;
+    uint8_t swivr;
+    uint8_t par;
+    /* Include the UART vector registers here.  */
+    uint8_t uivr[2];
+} m5206_mbar_state;
+
+/* Interrupt controller.  */
+
+static int m5206_find_pending_irq(m5206_mbar_state *s)
+{
+    int level;
+    int vector;
+    uint16_t active;
+    int i;
+
+    level = 0;
+    vector = 0;
+    active = s->ipr & ~s->imr;
+    if (!active)
+        return 0;
+
+    for (i = 1; i < 14; i++) {
+        if (active & (1 << i)) {
+            if ((s->icr[i] & 0x1f) > level) {
+                level = s->icr[i] & 0x1f;
+                vector = i;
+            }
+        }
+    }
+
+    if (level < 4)
+        vector = 0;
+
+    return vector;
+}
+
+static void m5206_mbar_update(m5206_mbar_state *s)
+{
+    int irq;
+    int vector;
+    int level;
+
+    irq = m5206_find_pending_irq(s);
+    if (irq) {
+        int tmp;
+        tmp = s->icr[irq];
+        level = (tmp >> 2) & 7;
+        if (tmp & 0x80) {
+            /* Autovector.  */
+            vector = 24 + level;
+        } else {
+            switch (irq) {
+            case 8: /* SWT */
+                vector = s->swivr;
+                break;
+            case 12: /* UART1 */
+                vector = s->uivr[0];
+                break;
+            case 13: /* UART2 */
+                vector = s->uivr[1];
+                break;
+            default:
+                /* Unknown vector.  */
+                fprintf(stderr, "Unhandled vector for IRQ %d\n", irq);
+                vector = 0xf;
+                break;
+            }
+        }
+    } else {
+        level = 0;
+        vector = 0;
+    }
+    m68k_set_irq_level(s->env, level, vector);
+}
+
+static void m5206_mbar_set_irq(void *opaque, int irq, int level)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    if (level) {
+        s->ipr |= 1 << irq;
+    } else {
+        s->ipr &= ~(1 << irq);
+    }
+    m5206_mbar_update(s);
+}
+
+/* System Integration Module.  */
+
+static void m5206_mbar_reset(m5206_mbar_state *s)
+{
+    s->scr = 0xc0;
+    s->icr[1] = 0x04;
+    s->icr[2] = 0x08;
+    s->icr[3] = 0x0c;
+    s->icr[4] = 0x10;
+    s->icr[5] = 0x14;
+    s->icr[6] = 0x18;
+    s->icr[7] = 0x1c;
+    s->icr[8] = 0x1c;
+    s->icr[9] = 0x80;
+    s->icr[10] = 0x80;
+    s->icr[11] = 0x80;
+    s->icr[12] = 0x00;
+    s->icr[13] = 0x00;
+    s->imr = 0x3ffe;
+    s->rsr = 0x80;
+    s->swivr = 0x0f;
+    s->par = 0;
+}
+
+static uint32_t m5206_mbar_read(m5206_mbar_state *s, uint32_t offset)
+{
+    if (offset >= 0x100 && offset < 0x120) {
+        return m5206_timer_read(s->timer[0], offset - 0x100);
+    } else if (offset >= 0x120 && offset < 0x140) {
+        return m5206_timer_read(s->timer[1], offset - 0x120);
+    } else if (offset >= 0x140 && offset < 0x160) {
+        return m5206_uart_read(s->uart[0], offset - 0x140);
+    } else if (offset >= 0x180 && offset < 0x1a0) {
+        return m5206_uart_read(s->uart[1], offset - 0x180);
+    }
+    switch (offset) {
+    case 0x03: return s->scr;
+    case 0x14 ... 0x20: return s->icr[offset - 0x13];
+    case 0x36: return s->imr;
+    case 0x3a: return s->ipr;
+    case 0x40: return s->rsr;
+    case 0x41: return 0;
+    case 0x42: return s->swivr;
+    case 0x50:
+        /* DRAM mask register.  */
+        /* FIXME: currently hardcoded to 128Mb.  */
+        {
+            uint32_t mask = ~0;
+            while (mask > ram_size)
+                mask >>= 1;
+            return mask & 0x0ffe0000;
+        }
+    case 0x5c: return 1; /* DRAM bank 1 empty.  */
+    case 0xcb: return s->par;
+    case 0x170: return s->uivr[0];
+    case 0x1b0: return s->uivr[1];
+    }
+    cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
+    return 0;
+}
+
+static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset,
+                             uint32_t value)
+{
+    if (offset >= 0x100 && offset < 0x120) {
+        m5206_timer_write(s->timer[0], offset - 0x100, value);
+        return;
+    } else if (offset >= 0x120 && offset < 0x140) {
+        m5206_timer_write(s->timer[1], offset - 0x120, value);
+        return;
+    } else if (offset >= 0x140 && offset < 0x160) {
+        m5206_uart_write(s->uart[0], offset - 0x140, value);
+        return;
+    } else if (offset >= 0x180 && offset < 0x1a0) {
+        m5206_uart_write(s->uart[1], offset - 0x180, value);
+        return;
+    }
+    switch (offset) {
+    case 0x03:
+        s->scr = value;
+        break;
+    case 0x14 ... 0x20:
+        s->icr[offset - 0x13] = value;
+        m5206_mbar_update(s);
+        break;
+    case 0x36:
+        s->imr = value;
+        m5206_mbar_update(s);
+        break;
+    case 0x40:
+        s->rsr &= ~value;
+        break;
+    case 0x41:
+        /* TODO: implement watchdog.  */
+        break;
+    case 0x42:
+        s->swivr = value;
+        break;
+    case 0xcb:
+        s->par = value;
+        break;
+    case 0x170:
+        s->uivr[0] = value;
+        break;
+    case 0x178: case 0x17c: case 0x1c8: case 0x1bc:
+        /* Not implemented: UART Output port bits.  */
+        break;
+    case 0x1b0:
+        s->uivr[1] = value;
+        break;
+    default:
+        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
+        break;
+    }
+}
+
+/* Internal peripherals use a variety of register widths.
+   This lookup table allows a single routine to handle all of them.  */
+static const int m5206_mbar_width[] = 
+{
+  /* 000-040 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  2, 2, 2, 2,
+  /* 040-080 */ 1, 2, 2, 2,  4, 1, 2, 4,  1, 2, 4, 2,  2, 4, 2, 2,
+  /* 080-0c0 */ 4, 2, 2, 4,  2, 2, 4, 2,  2, 4, 2, 2,  4, 2, 2, 4,
+  /* 0c0-100 */ 2, 2, 1, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,
+  /* 100-140 */ 2, 2, 2, 2,  1, 0, 0, 0,  2, 2, 2, 2,  1, 0, 0, 0,
+  /* 140-180 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+  /* 180-1c0 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+  /* 1c0-200 */ 1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+};
+
+static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset);
+static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset);
+
+static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
+    }
+    if (m5206_mbar_width[offset >> 2] > 1) {
+        uint16_t val;
+        val = m5206_mbar_readw(opaque, offset & ~1);
+        if ((offset & 1) == 0) {
+            val >>= 8;
+        }
+        return val & 0xff;
+    }
+    return m5206_mbar_read(s, offset);
+}
+
+static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width > 2) {
+        uint32_t val;
+        val = m5206_mbar_readl(opaque, offset & ~3);
+        if ((offset & 3) == 0)
+            val >>= 16;
+        return val & 0xffff;
+    } else if (width < 2) {
+        uint16_t val;
+        val = m5206_mbar_readb(opaque, offset) << 8;
+        val |= m5206_mbar_readb(opaque, offset + 1);
+        return val;
+    }
+    return m5206_mbar_read(s, offset);
+}
+
+static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        cpu_abort(cpu_single_env, "Bad MBAR read offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width < 4) {
+        uint32_t val;
+        val = m5206_mbar_readw(opaque, offset) << 16;
+        val |= m5206_mbar_readw(opaque, offset + 2);
+        return val;
+    }
+    return m5206_mbar_read(s, offset);
+}
+
+static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
+                              uint32_t value);
+static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
+                              uint32_t value);
+
+static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width > 1) {
+        uint32_t tmp;
+        tmp = m5206_mbar_readw(opaque, offset & ~1);
+        if (offset & 1) {
+            tmp = (tmp & 0xff00) | value;
+        } else {
+            tmp = (tmp & 0x00ff) | (value << 8);
+        }
+        m5206_mbar_writew(opaque, offset & ~1, tmp);
+        return;
+    }
+    m5206_mbar_write(s, offset, value);
+}
+
+static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width > 2) {
+        uint32_t tmp;
+        tmp = m5206_mbar_readl(opaque, offset & ~3);
+        if (offset & 3) {
+            tmp = (tmp & 0xffff0000) | value;
+        } else {
+            tmp = (tmp & 0x0000ffff) | (value << 16);
+        }
+        m5206_mbar_writel(opaque, offset & ~3, tmp);
+        return;
+    } else if (width < 2) {
+        m5206_mbar_writeb(opaque, offset, value >> 8);
+        m5206_mbar_writeb(opaque, offset + 1, value & 0xff);
+        return;
+    }
+    m5206_mbar_write(s, offset, value);
+}
+
+static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset,
+                              uint32_t value)
+{
+    m5206_mbar_state *s = (m5206_mbar_state *)opaque;
+    int width;
+    offset &= 0x3ff;
+    if (offset > 0x200) {
+        cpu_abort(cpu_single_env, "Bad MBAR write offset 0x%x", (int)offset);
+    }
+    width = m5206_mbar_width[offset >> 2];
+    if (width < 4) {
+        m5206_mbar_writew(opaque, offset, value >> 16);
+        m5206_mbar_writew(opaque, offset + 2, value & 0xffff);
+        return;
+    }
+    m5206_mbar_write(s, offset, value);
+}
+
+static CPUReadMemoryFunc *m5206_mbar_readfn[] = {
+   m5206_mbar_readb,
+   m5206_mbar_readw,
+   m5206_mbar_readl
+};
+
+static CPUWriteMemoryFunc *m5206_mbar_writefn[] = {
+   m5206_mbar_writeb,
+   m5206_mbar_writew,
+   m5206_mbar_writel
+};
+
+qemu_irq *mcf5206_init(uint32_t base, CPUState *env)
+{
+    m5206_mbar_state *s;
+    qemu_irq *pic;
+    int iomemtype;
+
+    s = (m5206_mbar_state *)qemu_mallocz(sizeof(m5206_mbar_state));
+    iomemtype = cpu_register_io_memory(0, m5206_mbar_readfn,
+                                       m5206_mbar_writefn, s);
+    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+
+    pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14);
+    s->timer[0] = m5206_timer_init(pic[9]);
+    s->timer[1] = m5206_timer_init(pic[10]);
+    s->uart[0] = m5206_uart_init(pic[12], serial_hds[0]);
+    s->uart[1] = m5206_uart_init(pic[13], serial_hds[1]);
+    s->env = env;
+
+    m5206_mbar_reset(s);
+    return pic;
+}
+

Modified: trunk/src/host/qemu-neo1973/hw/pc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pc.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/pc.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -29,12 +29,7 @@
 #define BIOS_FILENAME "bios.bin"
 #define VGABIOS_FILENAME "vgabios.bin"
 #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
-#define LINUX_BOOT_FILENAME "linux_boot.bin"
 
-#define KERNEL_LOAD_ADDR     0x00100000
-#define MAX_INITRD_LOAD_ADDR 0x38000000
-#define KERNEL_PARAMS_ADDR   0x00090000
-#define KERNEL_CMDLINE_ADDR  0x00099000
 /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables.  */
 #define ACPI_DATA_SIZE       0x10000
 
@@ -350,7 +345,62 @@
     register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL);
 }
 
+/* Generate an initial boot sector which sets state and jump to
+   a specified vector */
+static void generate_bootsect(uint32_t gpr[8], uint16_t segs[6], uint16_t ip)
+{
+    uint8_t bootsect[512], *p;
+    int i;
 
+    if (bs_table[0] == NULL) {
+	fprintf(stderr, "A disk image must be given for 'hda' when booting "
+		"a Linux kernel\n");
+	exit(1);
+    }
+
+    memset(bootsect, 0, sizeof(bootsect));
+
+    /* Copy the MSDOS partition table if possible */
+    bdrv_read(bs_table[0], 0, bootsect, 1);
+
+    /* Make sure we have a partition signature */
+    bootsect[510] = 0x55;
+    bootsect[511] = 0xaa;
+
+    /* Actual code */
+    p = bootsect;
+    *p++ = 0xfa;		/* CLI */
+    *p++ = 0xfc;		/* CLD */
+
+    for (i = 0; i < 6; i++) {
+	if (i == 1)		/* Skip CS */
+	    continue;
+
+	*p++ = 0xb8;		/* MOV AX,imm16 */
+	*p++ = segs[i];
+	*p++ = segs[i] >> 8;
+	*p++ = 0x8e;		/* MOV <seg>,AX */
+	*p++ = 0xc0 + (i << 3);
+    }
+
+    for (i = 0; i < 8; i++) {
+	*p++ = 0x66;		/* 32-bit operand size */
+	*p++ = 0xb8 + i;	/* MOV <reg>,imm32 */
+	*p++ = gpr[i];
+	*p++ = gpr[i] >> 8;
+	*p++ = gpr[i] >> 16;
+	*p++ = gpr[i] >> 24;
+    }
+
+    *p++ = 0xea;		/* JMP FAR */
+    *p++ = ip;			/* IP */
+    *p++ = ip >> 8;
+    *p++ = segs[1];		/* CS */
+    *p++ = segs[1] >> 8;
+
+    bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
+}
+
 int load_kernel(const char *filename, uint8_t *addr, 
                 uint8_t *real_addr)
 {
@@ -370,7 +420,7 @@
     if (read(fd, real_addr + 512, setup_sects * 512) != 
         setup_sects * 512)
         goto fail;
-    
+
     /* load 32 bit code */
     size = read(fd, addr, 16 * 1024 * 1024);
     if (size < 0)
@@ -382,6 +432,169 @@
     return -1;
 }
 
+static long get_file_size(FILE *f)
+{
+    long where, size;
+
+    /* XXX: on Unix systems, using fstat() probably makes more sense */
+
+    where = ftell(f);
+    fseek(f, 0, SEEK_END);
+    size = ftell(f);
+    fseek(f, where, SEEK_SET);
+
+    return size;
+}
+
+static void load_linux(const char *kernel_filename,
+		       const char *initrd_filename,
+		       const char *kernel_cmdline)
+{
+    uint16_t protocol;
+    uint32_t gpr[8];
+    uint16_t seg[6];
+    uint16_t real_seg;
+    int setup_size, kernel_size, initrd_size, cmdline_size;
+    uint32_t initrd_max;
+    uint8_t header[1024];
+    uint8_t *real_addr, *prot_addr, *cmdline_addr, *initrd_addr;
+    FILE *f, *fi;
+
+    /* Align to 16 bytes as a paranoia measure */
+    cmdline_size = (strlen(kernel_cmdline)+16) & ~15;
+
+    /* load the kernel header */
+    f = fopen(kernel_filename, "rb");
+    if (!f || !(kernel_size = get_file_size(f)) ||
+	fread(header, 1, 1024, f) != 1024) {
+	fprintf(stderr, "qemu: could not load kernel '%s'\n",
+		kernel_filename);
+	exit(1);
+    }
+
+    /* kernel protocol version */
+    fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
+    if (ldl_p(header+0x202) == 0x53726448)
+	protocol = lduw_p(header+0x206);
+    else
+	protocol = 0;
+
+    if (protocol < 0x200 || !(header[0x211] & 0x01)) {
+	/* Low kernel */
+	real_addr    = phys_ram_base + 0x90000;
+	cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size;
+	prot_addr    = phys_ram_base + 0x10000;
+    } else if (protocol < 0x202) {
+	/* High but ancient kernel */
+	real_addr    = phys_ram_base + 0x90000;
+	cmdline_addr = phys_ram_base + 0x9a000 - cmdline_size;
+	prot_addr    = phys_ram_base + 0x100000;
+    } else {
+	/* High and recent kernel */
+	real_addr    = phys_ram_base + 0x10000;
+	cmdline_addr = phys_ram_base + 0x20000;
+	prot_addr    = phys_ram_base + 0x100000;
+    }
+
+    fprintf(stderr,
+	    "qemu: real_addr     = %#zx\n"
+	    "qemu: cmdline_addr  = %#zx\n"
+	    "qemu: prot_addr     = %#zx\n",
+	    real_addr-phys_ram_base,
+	    cmdline_addr-phys_ram_base,
+	    prot_addr-phys_ram_base);
+
+    /* highest address for loading the initrd */
+    if (protocol >= 0x203)
+	initrd_max = ldl_p(header+0x22c);
+    else
+	initrd_max = 0x37ffffff;
+
+    if (initrd_max >= ram_size-ACPI_DATA_SIZE)
+	initrd_max = ram_size-ACPI_DATA_SIZE-1;
+
+    /* kernel command line */
+    pstrcpy(cmdline_addr, 4096, kernel_cmdline);
+
+    if (protocol >= 0x202) {
+	stl_p(header+0x228, cmdline_addr-phys_ram_base);
+    } else {
+	stw_p(header+0x20, 0xA33F);
+	stw_p(header+0x22, cmdline_addr-real_addr);
+    }
+
+    /* loader type */
+    /* High nybble = B reserved for Qemu; low nybble is revision number.
+       If this code is substantially changed, you may want to consider
+       incrementing the revision. */
+    if (protocol >= 0x200)
+	header[0x210] = 0xB0;
+
+    /* heap */
+    if (protocol >= 0x201) {
+	header[0x211] |= 0x80;	/* CAN_USE_HEAP */
+	stw_p(header+0x224, cmdline_addr-real_addr-0x200);
+    }
+
+    /* load initrd */
+    if (initrd_filename) {
+	if (protocol < 0x200) {
+	    fprintf(stderr, "qemu: linux kernel too old to load a ram disk\n");
+	    exit(1);
+	}
+
+	fi = fopen(initrd_filename, "rb");
+	if (!fi) {
+	    fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+		    initrd_filename);
+	    exit(1);
+	}
+
+	initrd_size = get_file_size(fi);
+	initrd_addr = phys_ram_base + ((initrd_max-initrd_size) & ~4095);
+
+	fprintf(stderr, "qemu: loading initrd (%#x bytes) at %#zx\n",
+		initrd_size, initrd_addr-phys_ram_base);
+
+	if (fread(initrd_addr, 1, initrd_size, fi) != initrd_size) {
+	    fprintf(stderr, "qemu: read error on initial ram disk '%s'\n",
+		    initrd_filename);
+	    exit(1);
+	}
+	fclose(fi);
+
+	stl_p(header+0x218, initrd_addr-phys_ram_base);
+	stl_p(header+0x21c, initrd_size);
+    }
+
+    /* store the finalized header and load the rest of the kernel */
+    memcpy(real_addr, header, 1024);
+
+    setup_size = header[0x1f1];
+    if (setup_size == 0)
+	setup_size = 4;
+
+    setup_size = (setup_size+1)*512;
+    kernel_size -= setup_size;	/* Size of protected-mode code */
+
+    if (fread(real_addr+1024, 1, setup_size-1024, f) != setup_size-1024 ||
+	fread(prot_addr, 1, kernel_size, f) != kernel_size) {
+	fprintf(stderr, "qemu: read error on kernel '%s'\n",
+		kernel_filename);
+	exit(1);
+    }
+    fclose(f);
+
+    /* generate bootsector to set up the initial register state */
+    real_seg = (real_addr-phys_ram_base) >> 4;
+    seg[0] = seg[2] = seg[3] = seg[4] = seg[4] = real_seg;
+    seg[1] = real_seg+0x20;	/* CS */
+    memset(gpr, 0, sizeof gpr);
+    gpr[4] = cmdline_addr-real_addr-16;	/* SP (-16 is paranoia) */
+
+    generate_bootsect(gpr, seg, 0);
+}
+
 static void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
@@ -453,9 +666,8 @@
                      int pci_enabled)
 {
     char buf[1024];
-    int ret, linux_boot, initrd_size, i;
+    int ret, linux_boot, i;
     ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
-    ram_addr_t initrd_offset;
     int bios_size, isa_bios_size, vga_bios_size;
     PCIBus *pci_bus;
     int piix3_devfn = -1;
@@ -570,82 +782,9 @@
     
     bochs_bios_init();
 
-    if (linux_boot) {
-        uint8_t bootsect[512];
-        uint8_t old_bootsect[512];
+    if (linux_boot)
+	load_linux(kernel_filename, initrd_filename, kernel_cmdline);
 
-        if (bs_table[0] == NULL) {
-            fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n");
-            exit(1);
-        }
-        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
-        ret = load_image(buf, bootsect);
-        if (ret != sizeof(bootsect)) {
-            fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
-                    buf);
-            exit(1);
-        }
-
-        if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) {
-            /* copy the MSDOS partition table */
-            memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40);
-        }
-
-        bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
-
-        /* now we can load the kernel */
-        ret = load_kernel(kernel_filename, 
-                          phys_ram_base + KERNEL_LOAD_ADDR,
-                          phys_ram_base + KERNEL_PARAMS_ADDR);
-        if (ret < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
-                    kernel_filename);
-            exit(1);
-        }
-        
-        /* load initrd */
-        initrd_size = 0;
-        initrd_offset = 0;
-        if (initrd_filename) {
-            initrd_size = get_image_size (initrd_filename);
-            if (initrd_size > 0) {
-                initrd_offset = (ram_size - initrd_size) & TARGET_PAGE_MASK;
-                /* Leave space for BIOS ACPI tables.  */
-                initrd_offset -= ACPI_DATA_SIZE;
-                /* Avoid the last 64k to avoid 2.2.x kernel bugs.  */
-                initrd_offset -= 0x10000;
-                if (initrd_offset > MAX_INITRD_LOAD_ADDR)
-                    initrd_offset = MAX_INITRD_LOAD_ADDR;
-
-                if (initrd_size > ram_size
-                    || initrd_offset < KERNEL_LOAD_ADDR + ret) {
-                    fprintf(stderr,
-                            "qemu: memory too small for initial ram disk '%s'\n",
-                            initrd_filename);
-                    exit(1);
-                }
-                initrd_size = load_image(initrd_filename,
-                                         phys_ram_base + initrd_offset);
-            }
-            if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
-                        initrd_filename);
-                exit(1);
-            }
-        }
-        if (initrd_size > 0) {
-            stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, initrd_offset);
-            stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
-        }
-        pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
-                kernel_cmdline);
-        stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F);
-        stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22,
-                KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR);
-        /* loader type */
-        stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
-    }
-
     cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
     i8259 = i8259_init(cpu_irq[0]);
     ferr_irq = i8259[13];
@@ -760,6 +899,7 @@
         uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
         i2c_bus *smbus;
 
+        /* TODO: Populate SPD eeprom data.  */
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3);
         for (i = 0; i < 8; i++) {
             smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));

Modified: trunk/src/host/qemu-neo1973/hw/pcnet.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcnet.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/pcnet.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -2018,7 +2018,8 @@
     (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
 };
 
-void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq)
+void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
+                 qemu_irq irq)
 {
     PCNetState *d;
     int lance_io_memory;

Added: trunk/src/host/qemu-neo1973/hw/ptimer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ptimer.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/ptimer.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -0,0 +1,164 @@
+/* 
+ * General purpose implementation of a simple periodic countdown timer.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GNU LGPL.
+ */
+#include "vl.h"
+
+
+struct ptimer_state
+{
+    int enabled; /* 0 = disabled, 1 = periodic, 2 = oneshot.  */
+    uint32_t limit;
+    uint32_t delta;
+    uint32_t period_frac;
+    int64_t period;
+    int64_t last_event;
+    int64_t next_event;
+    QEMUBH *bh;
+    QEMUTimer *timer;
+};
+
+/* Use a bottom-half routine to avoid reentrancy issues.  */
+static void ptimer_trigger(ptimer_state *s)
+{
+    if (s->bh) {
+        qemu_bh_schedule(s->bh);
+    }
+}
+
+static void ptimer_reload(ptimer_state *s)
+{
+    if (s->delta == 0) {
+        ptimer_trigger(s);
+        s->delta = s->limit;
+    }
+    if (s->delta == 0 || s->period == 0) {
+        fprintf(stderr, "Timer with period zero, disabling\n");
+        s->enabled = 0;
+        return;
+    }
+
+    s->last_event = s->next_event;
+    s->next_event = s->last_event + s->delta * s->period;
+    if (s->period_frac) {
+        s->next_event += ((int64_t)s->period_frac * s->delta) >> 32;
+    }
+    qemu_mod_timer(s->timer, s->next_event);
+}
+
+static void ptimer_tick(void *opaque)
+{
+    ptimer_state *s = (ptimer_state *)opaque;
+    ptimer_trigger(s);
+    s->delta = 0;
+    if (s->enabled == 2) {
+        s->enabled = 0;
+    } else {
+        ptimer_reload(s);
+    }
+}
+
+uint32_t ptimer_get_count(ptimer_state *s)
+{
+    int64_t now;
+    uint32_t counter;
+
+    if (s->enabled) {
+        now = qemu_get_clock(vm_clock);
+        /* Figure out the current counter value.  */
+        if (now - s->next_event > 0
+            || s->period == 0) {
+            /* Prevent timer underflowing if it should already have
+               triggered.  */
+            counter = 0;
+        } else {
+            int64_t rem;
+            int64_t div;
+
+            rem = s->next_event - now;
+            div = s->period;
+            counter = rem / div;
+        }
+    } else {
+        counter = s->delta;
+    }
+    return counter;
+}
+
+void ptimer_set_count(ptimer_state *s, uint32_t count)
+{
+    s->delta = count;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+void ptimer_run(ptimer_state *s, int oneshot)
+{
+    if (s->period == 0) {
+        fprintf(stderr, "Timer with period zero, disabling\n");
+        return;
+    }
+    s->enabled = oneshot ? 2 : 1;
+    s->next_event = qemu_get_clock(vm_clock);
+    ptimer_reload(s);
+}
+
+/* Pause a timer.  Note that this may cause it to "loose" time, even if it
+   is immediately restarted.  */
+void ptimer_stop(ptimer_state *s)
+{
+    if (!s->enabled)
+        return;
+
+    s->delta = ptimer_get_count(s);
+    qemu_del_timer(s->timer);
+    s->enabled = 0;
+}
+
+/* Set counter increment interval in nanoseconds.  */
+void ptimer_set_period(ptimer_state *s, int64_t period)
+{
+    if (s->enabled) {
+        fprintf(stderr, "FIXME: ptimer_set_period with running timer");
+    }
+    s->period = period;
+    s->period_frac = 0;
+}
+
+/* Set counter frequency in Hz.  */
+void ptimer_set_freq(ptimer_state *s, uint32_t freq)
+{
+    if (s->enabled) {
+        fprintf(stderr, "FIXME: ptimer_set_freq with running timer");
+    }
+    s->period = 1000000000ll / freq;
+    s->period_frac = (1000000000ll << 32) / freq;
+}
+
+/* Set the initial countdown value.  If reload is nonzero then also set
+   count = limit.  */
+void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload)
+{
+    if (s->enabled) {
+        fprintf(stderr, "FIXME: ptimer_set_limit with running timer");
+    }
+    s->limit = limit;
+    if (reload)
+        s->delta = limit;
+}
+
+ptimer_state *ptimer_init(QEMUBH *bh)
+{
+    ptimer_state *s;
+
+    s = (ptimer_state *)qemu_mallocz(sizeof(ptimer_state));
+    s->bh = bh;
+    s->timer = qemu_new_timer(vm_clock, ptimer_tick, s);
+    return s;
+}
+

Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1488,7 +1488,7 @@
 {
     int iomemtype;
     struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *)
-            qemu_mallocz(sizeof(struct pxa2xx_i2c_s));
+            i2c_slave_init(i2c_init_bus(), 0, sizeof(struct pxa2xx_i2c_s));
 
     s->base = base;
     s->irq = irq;

Modified: trunk/src/host/qemu-neo1973/hw/slavio_intctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_intctl.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/slavio_intctl.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -58,7 +58,8 @@
 } SLAVIO_INTCTLState;
 
 #define INTCTL_MAXADDR 0xf
-#define INTCTLM_MAXADDR 0xf
+#define INTCTLM_MAXADDR 0x13
+#define INTCTLM_MASK 0x1f
 static void slavio_check_interrupts(void *opaque);
 
 // per-cpu interrupt controller
@@ -143,7 +144,7 @@
     SLAVIO_INTCTLState *s = opaque;
     uint32_t saddr;
 
-    saddr = (addr & INTCTLM_MAXADDR) >> 2;
+    saddr = (addr & INTCTLM_MASK) >> 2;
     switch (saddr) {
     case 2: // clear (enable)
 	// Force clear unused bits
@@ -371,7 +372,7 @@
     s->cpu_envs[cpu] = env;
 }
 
-void *slavio_intctl_init(uint32_t addr, uint32_t addrg,
+void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
                          const uint32_t *intbit_to_level,
                          qemu_irq **irq)
 {

Modified: trunk/src/host/qemu-neo1973/hw/slavio_misc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_misc.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/slavio_misc.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -212,7 +212,8 @@
     return 0;
 }
 
-void *slavio_misc_init(uint32_t base, qemu_irq irq)
+void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
+                       qemu_irq irq)
 {
     int slavio_misc_io_memory;
     MiscState *s;
@@ -235,7 +236,7 @@
     // System control
     cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
     // Power management
-    cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(power_base, MISC_MAXADDR, slavio_misc_io_memory);
 
     s->irq = irq;
 

Modified: trunk/src/host/qemu-neo1973/hw/slavio_serial.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_serial.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/slavio_serial.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -587,8 +587,8 @@
 
 }
 
-SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1,
-                                CharDriverState *chr2)
+SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,
+                                CharDriverState *chr1, CharDriverState *chr2)
 {
     int slavio_serial_io_memory, i;
     SerialState *s;
@@ -704,7 +704,7 @@
     put_queue(s, 0);
 }
 
-void slavio_serial_ms_kbd_init(int base, qemu_irq irq)
+void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq)
 {
     int slavio_serial_io_memory, i;
     SerialState *s;

Modified: trunk/src/host/qemu-neo1973/hw/slavio_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_timer.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/slavio_timer.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -80,14 +80,12 @@
     out = (ticks > s->expire_time);
     if (out)
 	s->reached = 0x80000000;
-    if (!s->limit)
-	limit = 0x7fffffff;
-    else
-	limit = s->limit;
-
     // Convert register units to counter ticks
-    limit = limit >> 9;
+    limit = s->limit >> 9;
 
+    if (!limit)
+	limit = 0x7fffffff >> 9;
+
     // Convert cpu ticks to counter ticks
     diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
 
@@ -263,11 +261,11 @@
     s->reached = 0;
     s->mode &= 2;
     s->stopped = 1;
-    slavio_timer_get_out(s);
+    slavio_timer_irq(s);
 }
 
-void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu,
-                       void *intctl)
+void slavio_timer_init(target_phys_addr_t addr, int irq, int mode,
+                       unsigned int cpu, void *intctl)
 {
     int slavio_timer_io_memory;
     SLAVIO_TIMERState *s;

Modified: trunk/src/host/qemu-neo1973/hw/sparc32_dma.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sparc32_dma.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/sparc32_dma.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -249,8 +249,8 @@
     return 0;
 }
 
-void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq,
-                       void *iommu)
+void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq,
+                       qemu_irq leirq, void *iommu)
 {
     DMAState *s;
     int dma_io_memory;

Modified: trunk/src/host/qemu-neo1973/hw/sun4m.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4m.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/sun4m.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -48,11 +48,11 @@
 #define MAX_CPUS 16
 
 struct hwdef {
-    target_ulong iommu_base, slavio_base;
-    target_ulong intctl_base, counter_base, nvram_base, ms_kb_base, serial_base;
-    target_ulong fd_base;
-    target_ulong dma_base, esp_base, le_base;
-    target_ulong tcx_base, cs_base;
+    target_phys_addr_t iommu_base, slavio_base;
+    target_phys_addr_t intctl_base, counter_base, nvram_base, ms_kb_base;
+    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;
     long vram_size, nvram_size;
     // IRQ numbers are not PIL ones, but master interrupt controller register
     // bit numbers
@@ -243,9 +243,19 @@
 static void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
+
     cpu_reset(env);
+    env->halted = 0;
 }
 
+static void secondary_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->halted = 1;
+}
+
 static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size,
                           DisplayState *ds, const char *cpu_model)
 
@@ -266,17 +276,20 @@
         env = cpu_init();
         cpu_sparc_register(env, def);
         envs[i] = env;
-        if (i != 0)
+        if (i == 0) {
+            qemu_register_reset(main_cpu_reset, env);
+        } else {
+            qemu_register_reset(secondary_cpu_reset, env);
             env->halted = 1;
+        }
         register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
-        qemu_register_reset(main_cpu_reset, env);
     }
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, 0);
 
     iommu = iommu_init(hwdef->iommu_base);
     slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
-                                       hwdef->intctl_base + 0x10000,
+                                       hwdef->intctl_base + 0x10000ULL,
                                        &hwdef->intbit_to_level[0],
                                        &slavio_irq);
     for(i = 0; i < smp_cpus; i++) {
@@ -304,10 +317,11 @@
     nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
                         hwdef->nvram_size, 8);
     for (i = 0; i < MAX_CPUS; i++) {
-        slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE,
+        slavio_timer_init(hwdef->counter_base +
+                          (target_phys_addr_t)(i * TARGET_PAGE_SIZE),
                           hwdef->clock_irq, 0, i, slavio_intctl);
     }
-    slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2,
+    slavio_timer_init(hwdef->counter_base + 0x10000ULL, hwdef->clock1_irq, 2,
                       (unsigned int)-1, slavio_intctl);
     slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
     // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
@@ -323,9 +337,9 @@
         }
     }
 
-    slavio_misc = slavio_misc_init(hwdef->slavio_base, 
+    slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base,
                                    slavio_irq[hwdef->me_irq]);
-    if (hwdef->cs_base != (target_ulong)-1)
+    if (hwdef->cs_base != (target_phys_addr_t)-1)
         cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
     sparc32_dma_set_reset_data(dma, main_esp, main_lance);
 }
@@ -411,6 +425,7 @@
         .dma_base     = 0x78400000,
         .esp_base     = 0x78800000,
         .le_base      = 0x78c00000,
+        .power_base   = 0x7a000000,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -430,19 +445,20 @@
     },
     /* SS-10 */
     {
-        .iommu_base   = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits)
-        .tcx_base     = 0x20000000, // 0xe20000000ULL,
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
         .cs_base      = -1,
-        .slavio_base  = 0xf0000000, // 0xff0000000ULL,
-        .ms_kb_base   = 0xf1000000, // 0xff1000000ULL,
-        .serial_base  = 0xf1100000, // 0xff1100000ULL,
-        .nvram_base   = 0xf1200000, // 0xff1200000ULL,
-        .fd_base      = 0xf1700000, // 0xff1700000ULL,
-        .counter_base = 0xf1300000, // 0xff1300000ULL,
-        .intctl_base  = 0xf1400000, // 0xff1400000ULL,
-        .dma_base     = 0xf0400000, // 0xef0400000ULL,
-        .esp_base     = 0xf0800000, // 0xef0800000ULL,
-        .le_base      = 0xf0c00000, // 0xef0c00000ULL,
+        .slavio_base  = 0xff0000000ULL,
+        .ms_kb_base   = 0xff1000000ULL,
+        .serial_base  = 0xff1100000ULL,
+        .nvram_base   = 0xff1200000ULL,
+        .fd_base      = 0xff1700000ULL,
+        .counter_base = 0xff1300000ULL,
+        .intctl_base  = 0xff1400000ULL,
+        .dma_base     = 0xef0400000ULL,
+        .esp_base     = 0xef0800000ULL,
+        .le_base      = 0xef0c00000ULL,
+        .power_base   = 0xefa000000ULL,
         .vram_size    = 0x00100000,
         .nvram_size   = 0x2000,
         .esp_irq = 18,
@@ -465,8 +481,14 @@
 static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds,
                               const char *kernel_filename, const char *kernel_cmdline,
                               const char *initrd_filename, const char *cpu_model,
-                              unsigned int machine)
+                              unsigned int machine, int max_ram)
 {
+    if ((unsigned int)ram_size > (unsigned int)max_ram) {
+        fprintf(stderr, "qemu: Too much memory for this machine: %d, maximum %d\n",
+                (unsigned int)ram_size / (1024 * 1024),
+                (unsigned int)max_ram / (1024 * 1024));
+        exit(1);
+    }
     sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model);
 
     sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device,
@@ -484,7 +506,7 @@
         cpu_model = "Fujitsu MB86904";
     sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
                       kernel_cmdline, initrd_filename, cpu_model,
-                      0);
+                      0, 0x10000000);
 }
 
 /* SPARCstation 10 hardware initialisation */
@@ -497,7 +519,7 @@
         cpu_model = "TI SuperSparc II";
     sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
                       kernel_cmdline, initrd_filename, cpu_model,
-                      1);
+                      1, PROM_ADDR); // XXX prom overlap, actually first 4GB ok
 }
 
 QEMUMachine ss5_machine = {

Modified: trunk/src/host/qemu-neo1973/hw/tcx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/tcx.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/hw/tcx.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -31,7 +31,7 @@
 #define TCX_TEC_NREGS    0x1000
 
 typedef struct TCXState {
-    uint32_t addr;
+    target_phys_addr_t addr;
     DisplayState *ds;
     uint8_t *vram;
     uint32_t *vram24, *cplane;
@@ -359,7 +359,6 @@
 {
     TCXState *s = opaque;
     
-    qemu_put_be32s(f, (uint32_t *)&s->addr);
     qemu_put_be32s(f, (uint32_t *)&s->vram);
     qemu_put_be32s(f, (uint32_t *)&s->vram24);
     qemu_put_be32s(f, (uint32_t *)&s->cplane);
@@ -377,10 +376,9 @@
 {
     TCXState *s = opaque;
     
-    if (version_id != 2)
+    if (version_id != 3)
         return -EINVAL;
 
-    qemu_get_be32s(f, (uint32_t *)&s->addr);
     qemu_get_be32s(f, (uint32_t *)&s->vram);
     qemu_get_be32s(f, (uint32_t *)&s->vram24);
     qemu_get_be32s(f, (uint32_t *)&s->cplane);
@@ -492,7 +490,7 @@
     tcx_dummy_writel,
 };
 
-void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
+void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,
               unsigned long vram_offset, int vram_size, int width, int height,
               int depth)
 {
@@ -513,23 +511,23 @@
     // 8-bit plane
     s->vram = vram_base;
     size = vram_size;
-    cpu_register_physical_memory(addr + 0x00800000, size, vram_offset);
+    cpu_register_physical_memory(addr + 0x00800000ULL, size, vram_offset);
     vram_offset += size;
     vram_base += size;
 
     io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
-    cpu_register_physical_memory(addr + 0x00200000, TCX_DAC_NREGS, io_memory);
+    cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory);
 
     dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
                                           s);
-    cpu_register_physical_memory(addr + 0x00700000, TCX_TEC_NREGS,
+    cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS,
                                  dummy_memory);
     if (depth == 24) {
         // 24-bit plane
         size = vram_size * 4;
         s->vram24 = (uint32_t *)vram_base;
         s->vram24_offset = vram_offset;
-        cpu_register_physical_memory(addr + 0x02000000, size, vram_offset);
+        cpu_register_physical_memory(addr + 0x02000000ULL, size, vram_offset);
         vram_offset += size;
         vram_base += size;
 
@@ -537,19 +535,20 @@
         size = vram_size * 4;
         s->cplane = (uint32_t *)vram_base;
         s->cplane_offset = vram_offset;
-        cpu_register_physical_memory(addr + 0x0a000000, size, vram_offset);
-        cpu_register_physical_memory(addr + 0x00301000, TCX_THC_NREGS_24,
-                                     dummy_memory);
+        cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset);
         graphic_console_init(s->ds, tcx24_update_display,
                              tcx24_invalidate_display, tcx24_screen_dump, s);
     } else {
-        cpu_register_physical_memory(addr + 0x00300000, TCX_THC_NREGS_8,
+        cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8,
                                      dummy_memory);
         graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
                              tcx_screen_dump, s);
     }
+    // NetBSD writes here even with 8-bit display
+    cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24,
+                                 dummy_memory);
 
-    register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
+    register_savevm("tcx", addr, 3, tcx_save, tcx_load, s);
     qemu_register_reset(tcx_reset, s);
     tcx_reset(s);
     dpy_resize(s->ds, width, height);

Modified: trunk/src/host/qemu-neo1973/linux-user/main.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/main.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/linux-user/main.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1977,13 +1977,12 @@
     }
 #elif defined(TARGET_M68K)
     {
-        m68k_def_t *def;
-        def = m68k_find_by_name("cfv4e");
-        if (def == NULL) {
+        if (cpu_model == NULL)
+            cpu_model = "cfv4e";
+        if (cpu_m68k_set_model(env, cpu_model)) {
             cpu_abort(cpu_single_env,
                       "Unable to find m68k CPU definition\n");
         }
-        cpu_m68k_register(cpu_single_env, def);
         env->pc = regs->pc;
         env->dregs[0] = regs->d0;
         env->dregs[1] = regs->d1;

Modified: trunk/src/host/qemu-neo1973/monitor.c
===================================================================
--- trunk/src/host/qemu-neo1973/monitor.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/monitor.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -202,7 +202,7 @@
 static void do_commit(const char *device)
 {
     int i, all_devices;
-    
+
     all_devices = !strcmp(device, "all");
     for (i = 0; i < MAX_DISKS; i++) {
         if (bs_table[i]) {
@@ -211,6 +211,9 @@
                 bdrv_commit(bs_table[i]);
         }
     }
+    if (mtd_bdrv)
+        if (all_devices || !strcmp(bdrv_get_device_name(mtd_bdrv), device))
+            bdrv_commit(mtd_bdrv);
 }
 
 static void do_info(const char *item)

Modified: trunk/src/host/qemu-neo1973/pc-bios/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/pc-bios/Makefile	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/pc-bios/Makefile	2007-05-24 19:28:30 UTC (rev 2080)
@@ -6,16 +6,9 @@
 DEFINES=
 
 TARGETS=
-ifeq ($(ARCH),i386)
-TARGETS+=linux_boot.bin
-endif
 
 all: $(TARGETS)
 
-linux_boot.bin: linux_boot.o
-	ld --oformat binary -Ttext 0 -o $@ $<
-	chmod a-x $@
-
 %.o: %.S
 	$(CC) $(DEFINES) -c -o $@ $<
 

Modified: trunk/src/host/qemu-neo1973/pc-bios/README
===================================================================
--- trunk/src/host/qemu-neo1973/pc-bios/README	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/pc-bios/README	2007-05-24 19:28:30 UTC (rev 2080)
@@ -14,7 +14,7 @@
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
   1275-1994 (referred to as Open Firmware) compliant firmware.
-  The included Sparc32 image is built from SVN version 144 and Sparc64
+  The included Sparc32 image is built from SVN version 149 and Sparc64
   image from version 125.
 
 - The PXE roms come from Rom-o-Matic etherboot 5.4.2.

Deleted: trunk/src/host/qemu-neo1973/pc-bios/linux_boot.S
===================================================================
--- trunk/src/host/qemu-neo1973/pc-bios/linux_boot.S	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/pc-bios/linux_boot.S	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1,29 +0,0 @@
-/*
- * QEMU Boot sector to launch a preloaded Linux kernel
- * Copyright (c) 2004 Fabrice Bellard
- */
-
-#define LOAD_SEG 0x9000
-        
-.code16	
-.text
-	.globl	_start
-
-_start:
-        cli
-        cld
-        mov $LOAD_SEG, %ax
-        mov %ax, %ds
-        mov %ax, %es
-        mov %ax, %fs
-        mov %ax, %gs
-        mov %ax, %ss
-        mov $0x8ffe, %sp
-        ljmp $LOAD_SEG + 0x20, $0
-
-1:              
-        .fill 510 - (1b - _start), 1, 0
-
-        /* boot sector signature */
-        .byte 0x55
-        .byte 0xaa

Deleted: trunk/src/host/qemu-neo1973/pc-bios/linux_boot.bin
===================================================================
(Binary files differ)

Modified: trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc32
===================================================================
(Binary files differ)

Modified: trunk/src/host/qemu-neo1973/qemu-doc.texi
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-doc.texi	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/qemu-doc.texi	2007-05-24 19:28:30 UTC (rev 2080)
@@ -81,6 +81,7 @@
 @item ARM Versatile baseboard (ARM926E)
 @item ARM RealView Emulation baseboard (ARM926EJ-S)
 @item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor)
+ at item Arnewsh MCF5206 evaluation board (ColdFire V2).
 @end itemize
 
 For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported.
@@ -1549,6 +1550,7 @@
 * Sparc64 System emulator invocation::
 * MIPS System emulator invocation::
 * ARM System emulator invocation::
+* ColdFire System emulator invocation::
 @end menu
 
 @node QEMU PowerPC System emulator
@@ -1822,6 +1824,20 @@
 A Linux 2.6 test image is available on the QEMU web site. More
 information is available in the QEMU mailing-list archive.
 
+ at node ColdFire System emulator invocation
+ at section ColdFire System emulator invocation
+
+Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine.
+The emulator is able to boot a uClinux kernel.
+The following devices are emulated:
+
+ at itemize @minus
+ at item 
+MCF5206 ColdFire V2 Microprocessor.
+ at item
+Two on-chip UARTs.
+ at end itemize
+
 @node QEMU User space emulator 
 @chapter QEMU User space emulator 
 

Modified: trunk/src/host/qemu-neo1973/softmmu_header.h
===================================================================
--- trunk/src/host/qemu-neo1973/softmmu_header.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/softmmu_header.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -65,6 +65,8 @@
 #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
 #elif defined (TARGET_ALPHA)
 #define CPU_MEM_INDEX ((env->ps >> 3) & 3)
+#elif defined (TARGET_M68K)
+#define CPU_MEM_INDEX ((env->sr & SR_S) == 0)
 #else
 #error unsupported CPU
 #endif
@@ -86,6 +88,8 @@
 #define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
 #elif defined (TARGET_ALPHA)
 #define CPU_MEM_INDEX ((env->ps >> 3) & 3)
+#elif defined (TARGET_M68K)
+#define CPU_MEM_INDEX ((env->sr & SR_S) == 0)
 #else
 #error unsupported CPU
 #endif

Modified: trunk/src/host/qemu-neo1973/target-arm/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/op.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-arm/op.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -667,7 +667,7 @@
     if (shift >= 32) {
         env->CF = (T1 >> 31) & 1;
         T1 = (int32_t)T1 >> 31;
-    } else {
+    } else if (shift != 0) {
         env->CF = (T1 >> (shift - 1)) & 1;
         T1 = (int32_t)T1 >> shift;
     }

Modified: trunk/src/host/qemu-neo1973/target-m68k/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/cpu.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/cpu.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1,7 +1,7 @@
 /*
  * m68k virtual CPU header
  * 
- *  Copyright (c) 2005-2006 CodeSourcery
+ *  Copyright (c) 2005-2007 CodeSourcery
  *  Written by Paul Brook
  *
  * This library is free software; you can redistribute it and/or
@@ -50,6 +50,8 @@
 #define EXCP_UNSUPPORTED    61
 #define EXCP_ICE            13
 
+#define EXCP_RTE            0x100
+
 typedef struct CPUM68KState {
     uint32_t dregs[8];
     uint32_t aregs[8];
@@ -76,6 +78,12 @@
     struct {
         uint32_t ar;
     } mmu;
+
+    /* Control registers.  */
+    uint32_t vbr;
+    uint32_t mbar;
+    uint32_t rambar0;
+
     /* ??? remove this.  */
     uint32_t t1;
 
@@ -84,8 +92,11 @@
     int exception_index;
     int interrupt_request;
     int user_mode_only;
-    uint32_t address;
+    int halted;
 
+    int pending_vector;
+    int pending_level;
+
     uint32_t qregs[MAX_QREGS];
 
     CPU_COMMON
@@ -94,6 +105,7 @@
 CPUM68KState *cpu_m68k_init(void);
 int cpu_m68k_exec(CPUM68KState *s);
 void cpu_m68k_close(CPUM68KState *s);
+void do_interrupt(int is_hw);
 /* you can call this signal handler from your SIGBUS and SIGSEGV
    signal handlers to inform the virtual CPU of exceptions. non zero
    is returned if the signal was handled by the virtual CPU.  */
@@ -120,13 +132,20 @@
 #define CCF_V 0x02
 #define CCF_Z 0x04
 #define CCF_N 0x08
-#define CCF_X 0x01
+#define CCF_X 0x10
 
+#define SR_I_SHIFT 8
+#define SR_I  0x0700
+#define SR_M  0x1000
+#define SR_S  0x2000
+#define SR_T  0x8000
+
 typedef struct m68k_def_t m68k_def_t;
 
-m68k_def_t *m68k_find_by_name(const char *);
-void cpu_m68k_register(CPUM68KState *, m68k_def_t *);
+int cpu_m68k_set_model(CPUM68KState *env, const char * name);
 
+void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
+
 #define M68K_FPCR_PREC (1 << 6)
 
 #ifdef CONFIG_USER_ONLY

Modified: trunk/src/host/qemu-neo1973/target-m68k/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/exec.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/exec.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -40,8 +40,12 @@
 int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu);
 
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif
 
 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op);
 float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1);
+void helper_movec(CPUM68KState *env, int reg, uint32_t val);
 
 void cpu_loop_exit(void);

Modified: trunk/src/host/qemu-neo1973/target-m68k/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/helper.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/helper.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1,7 +1,7 @@
 /*
  *  m68k op helpers
  * 
- *  Copyright (c) 2006 CodeSourcery
+ *  Copyright (c) 2006-2007 CodeSourcery
  *  Written by Paul Brook
  *
  * This library is free software; you can redistribute it and/or
@@ -147,3 +147,65 @@
     }
     return res;
 }
+
+void helper_movec(CPUM68KState *env, int reg, uint32_t val)
+{
+    switch (reg) {
+    case 0x02: /* CACR */
+        /* Ignored.  */
+        break;
+    case 0x801: /* VBR */
+        env->vbr = val;
+        break;
+    /* TODO: Implement control registers.  */
+    default:
+        cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
+                  reg, val);
+    }
+}
+
+/* MMU */
+
+/* TODO: This will need fixing once the MMU is implemented.  */
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
+
+#if defined(CONFIG_USER_ONLY) 
+
+int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int is_user, int is_softmmu)
+{
+    env->exception_index = EXCP_ACCESS;
+    env->mmu.ar = address;
+    return 1;
+}
+
+#else
+
+int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                               int is_user, int is_softmmu)
+{
+    int prot;
+
+    address &= TARGET_PAGE_MASK;
+    prot = PAGE_READ | PAGE_WRITE;
+    return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
+}
+
+/* Notify CPU of a pending interrupt.  Prioritization and vectoring should
+   be handled by the interrupt controller.  Real hardware only requests
+   the vector when the interrupt is acknowledged by the CPU.  For
+   simplicitly we calculate it when the interrupt is signalled.  */
+void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
+{
+    env->pending_level = level;
+    env->pending_vector = vector;
+    if (level)
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    else
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+#endif

Modified: trunk/src/host/qemu-neo1973/target-m68k/op-hacks.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/op-hacks.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/op-hacks.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -27,16 +27,38 @@
     return qreg;
 }
 
-static inline void gen_op_ldf32(int dest, int addr)
+static inline void gen_op_ldf32_raw(int dest, int addr)
 {
-    gen_op_ld32(dest, addr);
+    gen_op_ld32_raw(dest, addr);
 }
 
-static inline void gen_op_stf32(int addr, int dest)
+static inline void gen_op_stf32_raw(int addr, int dest)
 {
-    gen_op_st32(addr, dest);
+    gen_op_st32_raw(addr, dest);
 }
 
+#if !defined(CONFIG_USER_ONLY)
+static inline void gen_op_ldf32_user(int dest, int addr)
+{
+    gen_op_ld32_user(dest, addr);
+}
+
+static inline void gen_op_stf32_user(int addr, int dest)
+{
+    gen_op_st32_user(addr, dest);
+}
+
+static inline void gen_op_ldf32_kernel(int dest, int addr)
+{
+    gen_op_ld32_kernel(dest, addr);
+}
+
+static inline void gen_op_stf32_kernel(int addr, int dest)
+{
+    gen_op_st32_kernel(addr, dest);
+}
+#endif
+
 static inline void gen_op_pack_32_f32(int dest, int src)
 {
     gen_op_mov32(dest, src);

Modified: trunk/src/host/qemu-neo1973/target-m68k/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/op.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/op.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1,7 +1,7 @@
 /*
  *  m68k micro operations
  * 
- *  Copyright (c) 2006 CodeSourcery
+ *  Copyright (c) 2006-2007 CodeSourcery
  *  Written by Paul Brook
  *
  * This library is free software; you can redistribute it and/or
@@ -48,23 +48,23 @@
 uint32_t
 get_op(int qreg)
 {
-    if (qreg == QREG_T0) {
+    if (qreg >= TARGET_NUM_QREGS) {
+        return env->qregs[qreg - TARGET_NUM_QREGS];
+    } else if (qreg == QREG_T0) {
         return T0;
-    } else if (qreg < TARGET_NUM_QREGS) {
-        return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
     } else {
-        return env->qregs[qreg - TARGET_NUM_QREGS];
+        return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
     }
 }
 
 void set_op(int qreg, uint32_t val)
 {
-    if (qreg == QREG_T0) {
+    if (qreg >= TARGET_NUM_QREGS) {
+        env->qregs[qreg - TARGET_NUM_QREGS] = val;
+    } else if (qreg == QREG_T0) {
         T0 = val;
-    } else if (qreg < TARGET_NUM_QREGS) {
-        *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
     } else {
-        env->qregs[qreg - TARGET_NUM_QREGS] = val;
+        *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
     }
 }
 
@@ -86,7 +86,7 @@
     }
 }
 
-#define OP(name) void OPPROTO op_##name (void)
+#define OP(name) void OPPROTO glue(op_,name) (void)
 
 OP(mov32)
 {
@@ -170,7 +170,7 @@
     FORCE_RET();
 }
 
-OP(addx_cc)
+OP(subx_cc)
 {
     uint32_t op1 = get_op(PARAM1);
     uint32_t op2 = get_op(PARAM2);
@@ -188,7 +188,7 @@
     FORCE_RET();
 }
 
-OP(subx_cc)
+OP(addx_cc)
 {
     uint32_t op1 = get_op(PARAM1);
     uint32_t op2 = get_op(PARAM2);
@@ -316,77 +316,6 @@
     FORCE_RET();
 }
 
-/* Load/store ops.  */
-OP(ld8u32)
-{
-    uint32_t addr = get_op(PARAM2);
-    set_op(PARAM1, ldub(addr));
-    FORCE_RET();
-}
-
-OP(ld8s32)
-{
-    uint32_t addr = get_op(PARAM2);
-    set_op(PARAM1, ldsb(addr));
-    FORCE_RET();
-}
-
-OP(ld16u32)
-{
-    uint32_t addr = get_op(PARAM2);
-    set_op(PARAM1, lduw(addr));
-    FORCE_RET();
-}
-
-OP(ld16s32)
-{
-    uint32_t addr = get_op(PARAM2);
-    set_op(PARAM1, ldsw(addr));
-    FORCE_RET();
-}
-
-OP(ld32)
-{
-    uint32_t addr = get_op(PARAM2);
-    set_op(PARAM1, ldl(addr));
-    FORCE_RET();
-}
-
-OP(st8)
-{
-    uint32_t addr = get_op(PARAM1);
-    stb(addr, get_op(PARAM2));
-    FORCE_RET();
-}
-
-OP(st16)
-{
-    uint32_t addr = get_op(PARAM1);
-    stw(addr, get_op(PARAM2));
-    FORCE_RET();
-}
-
-OP(st32)
-{
-    uint32_t addr = get_op(PARAM1);
-    stl(addr, get_op(PARAM2));
-    FORCE_RET();
-}
-
-OP(ldf64)
-{
-    uint32_t addr = get_op(PARAM2);
-    set_opf64(PARAM1, ldfq(addr));
-    FORCE_RET();
-}
-
-OP(stf64)
-{
-    uint32_t addr = get_op(PARAM1);
-    stfq(addr, get_opf64(PARAM2));
-    FORCE_RET();
-}
-
 OP(flush_flags)
 {
     int cc_op  = PARAM1;
@@ -454,6 +383,13 @@
     FORCE_RET();
 }
 
+OP(halt)
+{
+    env->halted = 1;
+    RAISE_EXCEPTION(EXCP_HLT);
+    FORCE_RET();
+}
+
 OP(raise_exception)
 {
     RAISE_EXCEPTION(PARAM1);
@@ -679,3 +615,22 @@
     set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
     FORCE_RET();
 }
+
+OP(movec)
+{
+    int op1 = get_op(PARAM1);
+    uint32_t op2 = get_op(PARAM2);
+    helper_movec(env, op1, op2);
+}
+
+/* Memory access.  */
+
+#define MEMSUFFIX _raw
+#include "op_mem.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _user
+#include "op_mem.h"
+#define MEMSUFFIX _kernel
+#include "op_mem.h"
+#endif

Added: trunk/src/host/qemu-neo1973/target-m68k/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/op_helper.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/op_helper.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -0,0 +1,140 @@
+/*
+ *  M68K helper routines
+ * 
+ *  Copyright (c) 2007 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "exec.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+void do_interrupt(int is_hw)
+{
+    env->exception_index = -1;
+}
+
+#else
+
+#define MMUSUFFIX _mmu
+#define GETPC() (__builtin_return_address(0))
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* Try to fill the TLB and return an exception if error. If retaddr is
+   NULL, it means that the function was called in C code (i.e. not
+   from generated code or from helper.c) */
+/* XXX: fix it to restore all registers */
+void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+    TranslationBlock *tb;
+    CPUState *saved_env;
+    target_phys_addr_t pc;
+    int ret;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1);
+    if (__builtin_expect(ret, 0)) {
+        if (retaddr) {
+            /* now we have a real cpu fault */
+            pc = (target_phys_addr_t)retaddr;
+            tb = tb_find_pc(pc);
+            if (tb) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc, NULL);
+            }
+        }
+        cpu_loop_exit();
+    }
+    env = saved_env;
+}
+
+static void do_rte(void)
+{
+    uint32_t sp;
+    uint32_t fmt;
+
+    sp = env->aregs[7];
+    fmt = ldl_kernel(sp);
+    env->pc = ldl_kernel(sp + 4);
+    sp |= (fmt >> 28) & 3;
+    env->sr = fmt & 0xffff;
+    env->aregs[7] = sp + 8;
+}
+
+void do_interrupt(int is_hw)
+{
+    uint32_t sp;
+    uint32_t fmt;
+    uint32_t retaddr;
+    uint32_t vector;
+
+    fmt = 0;
+    retaddr = env->pc;
+
+    if (!is_hw) {
+        switch (env->exception_index) {
+        case EXCP_RTE:
+            /* Return from an exception.  */
+            do_rte();
+            return;
+        }
+        if (env->exception_index >= EXCP_TRAP0
+            && env->exception_index <= EXCP_TRAP15) {
+            /* Move the PC after the trap instruction.  */
+            retaddr += 2;
+        }
+    }
+
+    /* TODO: Implement USP.  */
+    sp = env->aregs[7];
+
+    vector = env->exception_index << 2;
+
+    fmt |= 0x40000000;
+    fmt |= (sp & 3) << 28;
+    fmt |= vector << 16;
+    fmt |= env->sr;
+
+    /* ??? This could cause MMU faults.  */
+    sp &= ~3;
+    sp -= 4;
+    stl_kernel(sp, retaddr);
+    sp -= 4;
+    stl_kernel(sp, fmt);
+    env->aregs[7] = sp;
+    env->sr |= SR_S;
+    if (is_hw) {
+        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
+    }
+    /* Jump to vector.  */
+    env->pc = ldl_kernel(env->vbr + vector);
+}
+
+#endif

Added: trunk/src/host/qemu-neo1973/target-m68k/op_mem.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/op_mem.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/op_mem.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -0,0 +1,46 @@
+/* Load/store ops.  */
+#define MEM_LD_OP(name,suffix) \
+OP(glue(glue(ld,name),MEMSUFFIX)) \
+{ \
+    uint32_t addr = get_op(PARAM2); \
+    set_op(PARAM1, glue(glue(ld,suffix),MEMSUFFIX)(addr)); \
+    FORCE_RET(); \
+}
+
+MEM_LD_OP(8u32,ub)
+MEM_LD_OP(8s32,sb)
+MEM_LD_OP(16u32,uw)
+MEM_LD_OP(16s32,sw)
+MEM_LD_OP(32,l)
+
+#undef MEM_LD_OP
+
+#define MEM_ST_OP(name,suffix) \
+OP(glue(glue(st,name),MEMSUFFIX)) \
+{ \
+    uint32_t addr = get_op(PARAM1); \
+    glue(glue(st,suffix),MEMSUFFIX)(addr, get_op(PARAM2)); \
+    FORCE_RET(); \
+}
+
+MEM_ST_OP(8,b)
+MEM_ST_OP(16,w)
+MEM_ST_OP(32,l)
+
+#undef MEM_ST_OP
+
+OP(glue(ldf64,MEMSUFFIX))
+{
+    uint32_t addr = get_op(PARAM2);
+    set_opf64(PARAM1, glue(ldfq,MEMSUFFIX)(addr));
+    FORCE_RET();
+}
+
+OP(glue(stf64,MEMSUFFIX))
+{
+    uint32_t addr = get_op(PARAM1);
+    glue(stfq,MEMSUFFIX)(addr, get_opf64(PARAM2));
+    FORCE_RET();
+}
+
+#undef MEMSUFFIX

Modified: trunk/src/host/qemu-neo1973/target-m68k/qregs.def
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/qregs.def	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/qregs.def	2007-05-24 19:28:30 UTC (rev 2080)
@@ -24,6 +24,7 @@
 DEFF64(F7, fregs[7])
 DEFF64(FP_RESULT, fp_result)
 DEFO32(PC, pc)
+DEFO32(SR, sr)
 DEFO32(CC_OP, cc_op)
 DEFR(T0, AREG1, QMODE_I32)
 DEFO32(CC_DEST, cc_dest)

Modified: trunk/src/host/qemu-neo1973/target-m68k/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/translate.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-m68k/translate.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1,7 +1,7 @@
 /*
  *  m68k translation
  * 
- *  Copyright (c) 2005-2006 CodeSourcery
+ *  Copyright (c) 2005-2007 CodeSourcery
  *  Written by Paul Brook
  *
  * This library is free software; you can redistribute it and/or
@@ -30,6 +30,8 @@
 #include "disas.h"
 #include "m68k-qreg.h"
 
+//#define DEBUG_DISPATCH 1
+
 static inline void qemu_assert(int cond, const char *msg)
 {
     if (!cond) {
@@ -43,6 +45,7 @@
     target_ulong pc;
     int is_jmp;
     int cc_op;
+    int user;
     uint32_t fpcr;
     struct TranslationBlock *tb;
     int singlestep_enabled;
@@ -50,6 +53,12 @@
 
 #define DISAS_JUMP_NEXT 4
 
+#if defined(CONFIG_USER_ONLY)
+#define IS_USER(s) 1
+#else
+#define IS_USER(s) s->user
+#endif
+
 /* XXX: move that elsewhere */
 /* ??? Fix exceptions.  */
 static void *gen_throws_exception;
@@ -68,6 +77,25 @@
 };
 
 #include "gen-op.h"
+
+#if defined(CONFIG_USER_ONLY)
+#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val)
+#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr)
+#else
+#define gen_st(s, name, addr, val) do { \
+    if (IS_USER(s)) \
+        gen_op_st##name##_user(addr, val); \
+    else \
+        gen_op_st##name##_kernel(addr, val); \
+    } while (0)
+#define gen_ld(s, name, val, addr) do { \
+    if (IS_USER(s)) \
+        gen_op_ld##name##_user(val, addr); \
+    else \
+        gen_op_ld##name##_kernel(val, addr); \
+    } while (0)
+#endif
+
 #include "op-hacks.h"
 
 #define OS_BYTE 0
@@ -101,40 +129,49 @@
 
 typedef void (*disas_proc)(DisasContext *, uint16_t);
 
+#ifdef DEBUG_DISPATCH
 #define DISAS_INSN(name) \
+  static void real_disas_##name (DisasContext *s, uint16_t insn); \
+  static void disas_##name (DisasContext *s, uint16_t insn) { \
+    if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \
+    real_disas_##name(s, insn); } \
+  static void real_disas_##name (DisasContext *s, uint16_t insn)
+#else
+#define DISAS_INSN(name) \
   static void disas_##name (DisasContext *s, uint16_t insn)
+#endif
 
 /* Generate a load from the specified address.  Narrow values are
    sign extended to full register width.  */
-static inline int gen_load(int opsize, int addr, int sign)
+static inline int gen_load(DisasContext * s, int opsize, int addr, int sign)
 {
     int tmp;
     switch(opsize) {
     case OS_BYTE:
         tmp = gen_new_qreg(QMODE_I32);
         if (sign)
-            gen_op_ld8s32(tmp, addr);
+            gen_ld(s, 8s32, tmp, addr);
         else
-            gen_op_ld8u32(tmp, addr);
+            gen_ld(s, 8u32, tmp, addr);
         break;
     case OS_WORD:
         tmp = gen_new_qreg(QMODE_I32);
         if (sign)
-            gen_op_ld16s32(tmp, addr);
+            gen_ld(s, 16s32, tmp, addr);
         else
-            gen_op_ld16u32(tmp, addr);
+            gen_ld(s, 16u32, tmp, addr);
         break;
     case OS_LONG:
         tmp = gen_new_qreg(QMODE_I32);
-        gen_op_ld32(tmp, addr);
+        gen_ld(s, 32, tmp, addr);
         break;
     case OS_SINGLE:
         tmp = gen_new_qreg(QMODE_F32);
-        gen_op_ldf32(tmp, addr);
+        gen_ld(s, f32, tmp, addr);
         break;
     case OS_DOUBLE:
         tmp  = gen_new_qreg(QMODE_F64);
-        gen_op_ldf64(tmp, addr);
+        gen_ld(s, f64, tmp, addr);
         break;
     default:
         qemu_assert(0, "bad load size");
@@ -144,23 +181,23 @@
 }
 
 /* Generate a store.  */
-static inline void gen_store(int opsize, int addr, int val)
+static inline void gen_store(DisasContext *s, int opsize, int addr, int val)
 {
     switch(opsize) {
     case OS_BYTE:
-        gen_op_st8(addr, val);
+        gen_st(s, 8, addr, val);
         break;
     case OS_WORD:
-        gen_op_st16(addr, val);
+        gen_st(s, 16, addr, val);
         break;
     case OS_LONG:
-        gen_op_st32(addr, val);
+        gen_st(s, 32, addr, val);
         break;
     case OS_SINGLE:
-        gen_op_stf32(addr, val);
+        gen_st(s, f32, addr, val);
         break;
     case OS_DOUBLE:
-        gen_op_stf64(addr, val);
+        gen_st(s, f64, addr, val);
         break;
     default:
         qemu_assert(0, "bad store size");
@@ -170,13 +207,13 @@
 
 /* Generate an unsigned load if VAL is 0 a signed load if val is -1,
    otherwise generate a store.  */
-static int gen_ldst(int opsize, int addr, int val)
+static int gen_ldst(DisasContext *s, int opsize, int addr, int val)
 {
     if (val > 0) {
-        gen_store(opsize, addr, val);
+        gen_store(s, opsize, addr, val);
         return 0;
     } else {
-        return gen_load(opsize, addr, val != 0);
+        return gen_load(s, opsize, addr, val != 0);
     }
 }
 
@@ -191,7 +228,7 @@
     int tmp;
 
     offset = s->pc;
-    ext = lduw(s->pc);
+    ext = lduw_code(s->pc);
     s->pc += 2;
     tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0);
     /* ??? Check W/L bit.  */
@@ -216,9 +253,9 @@
 static inline uint32_t read_im32(DisasContext *s)
 {
     uint32_t im;
-    im = ((uint32_t)lduw(s->pc)) << 16;
+    im = ((uint32_t)lduw_code(s->pc)) << 16;
     s->pc += 2;
-    im |= lduw(s->pc);
+    im |= lduw_code(s->pc);
     s->pc += 2;
     return im;
 }
@@ -343,7 +380,7 @@
     case 5: /* Indirect displacement.  */
         reg += QREG_A0;
         tmp = gen_new_qreg(QMODE_I32);
-        ext = lduw(s->pc);
+        ext = lduw_code(s->pc);
         s->pc += 2;
         gen_op_add32(tmp, reg, gen_im32((int16_t)ext));
         return tmp;
@@ -353,7 +390,7 @@
     case 7: /* Other */
         switch (reg) {
         case 0: /* Absolute short.  */
-            offset = ldsw(s->pc);
+            offset = ldsw_code(s->pc);
             s->pc += 2;
             return gen_im32(offset);
         case 1: /* Absolute long.  */
@@ -362,7 +399,7 @@
         case 2: /* pc displacement  */
             tmp = gen_new_qreg(QMODE_I32);
             offset = s->pc;
-            offset += ldsw(s->pc);
+            offset += ldsw_code(s->pc);
             s->pc += 2;
             return gen_im32(offset);
         case 3: /* pc index+displacement.  */
@@ -391,7 +428,7 @@
         if (addrp)
             *addrp = tmp;
     }
-    return gen_ldst(opsize, tmp, val);
+    return gen_ldst(s, opsize, tmp, val);
 }
 
 /* Generate code to load/store a value ito/from an EA.  If VAL > 0 this is
@@ -424,10 +461,10 @@
         }
     case 2: /* Indirect register */
         reg += QREG_A0;
-        return gen_ldst(opsize, reg, val);
+        return gen_ldst(s, opsize, reg, val);
     case 3: /* Indirect postincrement.  */
         reg += QREG_A0;
-        result = gen_ldst(opsize, reg, val);
+        result = gen_ldst(s, opsize, reg, val);
         /* ??? This is not exception safe.  The instruction may still
            fault after this point.  */
         if (val > 0 || !addrp)
@@ -443,7 +480,7 @@
                 if (addrp)
                     *addrp = tmp;
             }
-            result = gen_ldst(opsize, tmp, val);
+            result = gen_ldst(s, opsize, tmp, val);
             /* ??? This is not exception safe.  The instruction may still
                fault after this point.  */
             if (val > 0 || !addrp) {
@@ -467,16 +504,16 @@
             switch (opsize) {
             case OS_BYTE:
                 if (val)
-                    offset = ldsb(s->pc + 1);
+                    offset = ldsb_code(s->pc + 1);
                 else
-                    offset = ldub(s->pc + 1);
+                    offset = ldub_code(s->pc + 1);
                 s->pc += 2;
                 break;
             case OS_WORD:
                 if (val)
-                    offset = ldsw(s->pc);
+                    offset = ldsw_code(s->pc);
                 else
-                    offset = lduw(s->pc);
+                    offset = lduw_code(s->pc);
                 s->pc += 2;
                 break;
             case OS_LONG:
@@ -622,6 +659,14 @@
     gen_set_label(l1);
 }
 
+/* Force a TB lookup after an instruction that changes the CPU state.  */
+static void gen_lookup_tb(DisasContext *s)
+{
+    gen_flush_cc_op(s);
+    gen_op_mov32(QREG_PC, gen_im32(s->pc));
+    s->is_jmp = DISAS_UPDATE;
+}
+
 /* Generate a jump to to the address in qreg DEST.  */
 static void gen_jmp(DisasContext *s, int dest)
 {
@@ -735,7 +780,7 @@
     int reg;
     uint16_t ext;
 
-    ext = lduw(s->pc);
+    ext = lduw_code(s->pc);
     s->pc += 2;
     if (ext & 0x87f8) {
         gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
@@ -903,13 +948,13 @@
     gen_logic_cc(s, tmp);
 }
 
-static void gen_push(int val)
+static void gen_push(DisasContext *s, int val)
 {
     int tmp;
 
     tmp = gen_new_qreg(QMODE_I32);
     gen_op_sub32(tmp, QREG_SP, gen_im32(4));
-    gen_store(OS_LONG, tmp, val);
+    gen_store(s, OS_LONG, tmp, val);
     gen_op_mov32(QREG_SP, tmp);
 }
 
@@ -922,7 +967,7 @@
     int tmp;
     int is_load;
 
-    mask = lduw(s->pc);
+    mask = lduw_code(s->pc);
     s->pc += 2;
     tmp = gen_lea(s, insn, OS_LONG);
     addr = gen_new_qreg(QMODE_I32);
@@ -935,10 +980,10 @@
             else
                 reg = AREG(i, 0);
             if (is_load) {
-                tmp = gen_load(OS_LONG, addr, 0);
+                tmp = gen_load(s, OS_LONG, addr, 0);
                 gen_op_mov32(reg, tmp);
             } else {
-                gen_store(OS_LONG, addr, reg);
+                gen_store(s, OS_LONG, addr, reg);
             }
             if (mask != 1)
                 gen_op_add32(addr, addr, gen_im32(4));
@@ -963,7 +1008,7 @@
         opsize = OS_LONG;
     op = (insn >> 6) & 3;
 
-    bitnum = lduw(s->pc);
+    bitnum = lduw_code(s->pc);
     s->pc += 2;
     if (bitnum & 0xff00) {
         disas_undef(s, insn);
@@ -1155,9 +1200,8 @@
     gen_logic_cc(s, gen_im32(0));
 }
 
-DISAS_INSN(move_from_ccr)
+static int gen_get_ccr(DisasContext *s)
 {
-    int reg;
     int dest;
 
     gen_flush_flags(s);
@@ -1165,8 +1209,17 @@
     gen_op_get_xflag(dest);
     gen_op_shl32(dest, dest, gen_im32(4));
     gen_op_or32(dest, dest, QREG_CC_DEST);
+    return dest;
+}
+
+DISAS_INSN(move_from_ccr)
+{
+    int reg;
+    int ccr;
+
+    ccr = gen_get_ccr(s);
     reg = DREG(insn, 0);
-    gen_partset_reg(OS_WORD, reg, dest);
+    gen_partset_reg(OS_WORD, reg, ccr);
 }
 
 DISAS_INSN(neg)
@@ -1184,8 +1237,17 @@
     s->cc_op = CC_OP_SUB;
 }
 
-DISAS_INSN(move_to_ccr)
+static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
 {
+    gen_op_logic_cc(gen_im32(val & 0xf));
+    gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
+    if (!ccr_only) {
+        gen_op_mov32(QREG_SR, gen_im32(val & 0xff00));
+    }
+}
+
+static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
+{
     int src1;
     int reg;
 
@@ -1199,19 +1261,26 @@
         gen_op_shr32(src1, reg, gen_im32(4));
         gen_op_and32(src1, src1, gen_im32(1));
         gen_op_update_xflag_tst(src1);
+        if (!ccr_only) {
+            gen_op_and32(QREG_SR, reg, gen_im32(0xff00));
+        }
       }
-    else if ((insn & 0x3f) != 0x3c)
+    else if ((insn & 0x3f) == 0x3c)
       {
-        uint8_t val;
-        val = ldsb(s->pc);
+        uint16_t val;
+        val = lduw_code(s->pc);
         s->pc += 2;
-        gen_op_logic_cc(gen_im32(val & 0xf));
-        gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
+        gen_set_sr_im(s, val, ccr_only);
       }
     else
         disas_undef(s, insn);
 }
 
+DISAS_INSN(move_to_ccr)
+{
+    gen_set_sr(s, insn, 1);
+}
+
 DISAS_INSN(not)
 {
     int reg;
@@ -1244,7 +1313,7 @@
     int tmp;
 
     tmp = gen_lea(s, insn, OS_LONG);
-    gen_push(tmp);
+    gen_push(s, tmp);
 }
 
 DISAS_INSN(ext)
@@ -1322,7 +1391,7 @@
 
     /* The upper 32 bits of the product are discarded, so
        muls.l and mulu.l are functionally equivalent.  */
-    ext = lduw(s->pc);
+    ext = lduw_code(s->pc);
     s->pc += 2;
     if (ext & 0x87ff) {
         gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
@@ -1343,12 +1412,12 @@
     int reg;
     int tmp;
 
-    offset = ldsw(s->pc);
+    offset = ldsw_code(s->pc);
     s->pc += 2;
     reg = AREG(insn, 0);
     tmp = gen_new_qreg(QMODE_I32);
     gen_op_sub32(tmp, QREG_SP, gen_im32(4));
-    gen_store(OS_LONG, tmp, reg);
+    gen_store(s, OS_LONG, tmp, reg);
     if (reg != QREG_SP)
         gen_op_mov32(reg, tmp);
     gen_op_add32(QREG_SP, tmp, gen_im32(offset));
@@ -1363,7 +1432,7 @@
     src = gen_new_qreg(QMODE_I32);
     reg = AREG(insn, 0);
     gen_op_mov32(src, reg);
-    tmp = gen_load(OS_LONG, src, 0);
+    tmp = gen_load(s, OS_LONG, src, 0);
     gen_op_mov32(reg, tmp);
     gen_op_add32(QREG_SP, src, gen_im32(4));
 }
@@ -1376,7 +1445,7 @@
 {
     int tmp;
 
-    tmp = gen_load(OS_LONG, QREG_SP, 0);
+    tmp = gen_load(s, OS_LONG, QREG_SP, 0);
     gen_op_add32(QREG_SP, QREG_SP, gen_im32(4));
     gen_jmp(s, tmp);
 }
@@ -1390,7 +1459,7 @@
     tmp = gen_lea(s, insn, OS_LONG);
     if ((insn & 0x40) == 0) {
         /* jsr */
-        gen_push(gen_im32(s->pc));
+        gen_push(s, gen_im32(s->pc));
     }
     gen_jmp(s, tmp);
 }
@@ -1460,14 +1529,14 @@
     op = (insn >> 8) & 0xf;
     offset = (int8_t)insn;
     if (offset == 0) {
-        offset = ldsw(s->pc);
+        offset = ldsw_code(s->pc);
         s->pc += 2;
     } else if (offset == -1) {
         offset = read_im32(s);
     }
     if (op == 1) {
         /* bsr */
-        gen_push(gen_im32(s->pc));
+        gen_push(s, gen_im32(s->pc));
     }
     gen_flush_cc_op(s);
     if (op > 1) {
@@ -1752,68 +1821,154 @@
     cpu_abort(NULL, "Unimplemented insn: ff1");
 }
 
+static int gen_get_sr(DisasContext *s)
+{
+    int ccr;
+    int sr;
+
+    ccr = gen_get_ccr(s);
+    sr = gen_new_qreg(QMODE_I32);
+    gen_op_and32(sr, QREG_SR, gen_im32(0xffe0));
+    gen_op_or32(sr, sr, ccr);
+    return sr;
+}
+
 DISAS_INSN(strldsr)
 {
     uint16_t ext;
     uint32_t addr;
 
     addr = s->pc - 2;
-    ext = lduw(s->pc);
+    ext = lduw_code(s->pc);
     s->pc += 2;
-    if (ext != 0x46FC)
+    if (ext != 0x46FC) {
         gen_exception(s, addr, EXCP_UNSUPPORTED);
-    else
+        return;
+    }
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+    if (IS_USER(s) || (ext & SR_S) == 0) {
         gen_exception(s, addr, EXCP_PRIVILEGE);
+        return;
+    }
+    gen_push(s, gen_get_sr(s));
+    gen_set_sr_im(s, ext, 0);
 }
 
 DISAS_INSN(move_from_sr)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    int reg;
+    int sr;
+
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    sr = gen_get_sr(s);
+    reg = DREG(insn, 0);
+    gen_partset_reg(OS_WORD, reg, sr);
 }
 
 DISAS_INSN(move_to_sr)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    gen_set_sr(s, insn, 0);
+    gen_lookup_tb(s);
 }
 
 DISAS_INSN(move_from_usp)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* TODO: Implement USP.  */
+    gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
 }
 
 DISAS_INSN(move_to_usp)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* TODO: Implement USP.  */
+    gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
 }
 
 DISAS_INSN(halt)
 {
-    gen_exception(s, s->pc, EXCP_HLT);
+    gen_flush_cc_op(s);
+    gen_jmp(s, gen_im32(s->pc));
+    gen_op_halt();
 }
 
 DISAS_INSN(stop)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    uint16_t ext;
+
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    gen_set_sr_im(s, ext, 0);
+    disas_halt(s, insn);
 }
 
 DISAS_INSN(rte)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    gen_exception(s, s->pc - 2, EXCP_RTE);
 }
 
 DISAS_INSN(movec)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    uint16_t ext;
+    int reg;
+
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    if (ext & 0x8000) {
+        reg = AREG(ext, 12);
+    } else {
+        reg = DREG(ext, 12);
+    }
+    gen_op_movec(gen_im32(ext & 0xfff), reg);
+    gen_lookup_tb(s);
 }
 
 DISAS_INSN(intouch)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* ICache fetch.  Implement as no-op.  */
 }
 
 DISAS_INSN(cpushl)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* Cache push/invalidate.  Implement as no-op.  */
 }
 
 DISAS_INSN(wddata)
@@ -1823,7 +1978,12 @@
 
 DISAS_INSN(wdebug)
 {
-    gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+    if (IS_USER(s)) {
+        gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
+        return;
+    }
+    /* TODO: Implement wdebug.  */
+    qemu_assert(0, "WDEBUG not implemented");
 }
 
 DISAS_INSN(trap)
@@ -1843,7 +2003,7 @@
     int round;
     int opsize;
 
-    ext = lduw(s->pc);
+    ext = lduw_code(s->pc);
     s->pc += 2;
     opmode = ext & 0x7f;
     switch ((ext >> 13) & 7) {
@@ -1928,10 +2088,10 @@
             if (ext & mask) {
                 if (ext & (1 << 13)) {
                     /* store */
-                    gen_op_stf64(addr, dest);
+                    gen_st(s, f64, addr, dest);
                 } else {
                     /* load */
-                    gen_op_ldf64(dest, addr);
+                    gen_ld(s, f64, dest, addr);
                 }
                 if (ext & (mask - 1))
                     gen_op_add32(addr, addr, gen_im32(8));
@@ -2060,10 +2220,10 @@
     int l1;
 
     addr = s->pc;
-    offset = ldsw(s->pc);
+    offset = ldsw_code(s->pc);
     s->pc += 2;
     if (insn & (1 << 6)) {
-        offset = (offset << 16) | lduw(s->pc);
+        offset = (offset << 16) | lduw_code(s->pc);
         s->pc += 2;
     }
 
@@ -2143,6 +2303,18 @@
     gen_jmp_tb(s, 1, addr + offset);
 }
 
+DISAS_INSN(frestore)
+{
+    /* TODO: Implement frestore.  */
+    qemu_assert(0, "FRESTORE not implemented");
+}
+
+DISAS_INSN(fsave)
+{
+    /* TODO: Implement fsave.  */
+    qemu_assert(0, "FSAVE not implemented");
+}
+
 static disas_proc opcode_table[65536];
 
 static void
@@ -2168,11 +2340,10 @@
       i <<= 1;
   from = opcode & ~(i - 1);
   to = from + i;
-  for (i = from; i < to; i++)
-    {
+  for (i = from; i < to; i++) {
       if ((i & mask) == opcode)
           opcode_table[i] = proc;
-    }
+  }
 }
 
 /* Register m68k opcode handlers.  Order is important.
@@ -2274,6 +2445,8 @@
     INSN(undef_fpu, f000, f000, CF_A);
     INSN(fpu,       f200, ffc0, CF_FPU);
     INSN(fbcc,      f280, ffc0, CF_FPU);
+    INSN(frestore,  f340, ffc0, CF_FPU);
+    INSN(fsave,     f340, ffc0, CF_FPU);
     INSN(intouch,   f340, ffc0, CF_A);
     INSN(cpushl,    f428, ff38, CF_A);
     INSN(wddata,    fb00, ff00, CF_A);
@@ -2287,7 +2460,7 @@
 {
     uint16_t insn;
 
-    insn = lduw(s->pc);
+    insn = lduw_code(s->pc);
     s->pc += 2;
 
     opcode_table[insn](s, insn);
@@ -2576,6 +2749,7 @@
     dc->cc_op = CC_OP_DYNAMIC;
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->fpcr = env->fpcr;
+    dc->user = (env->sr & SR_S) == 0;
     nb_gen_labels = 0;
     lj = -1;
     do {
@@ -2675,6 +2849,19 @@
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
+void cpu_reset(CPUM68KState *env)
+{
+    memset(env, 0, offsetof(CPUM68KState, breakpoints));
+#if !defined (CONFIG_USER_ONLY)
+    env->sr = 0x2700;
+#endif
+    /* ??? FP regs should be initialized to NaN.  */
+    env->cc_op = CC_OP_FLAGS;
+    /* TODO: We should set PC from the interrupt vector.  */
+    env->pc = 0;
+    tlb_flush(env, 1);
+}
+
 CPUM68KState *cpu_m68k_init(void)
 {
     CPUM68KState *env;
@@ -2684,10 +2871,7 @@
         return NULL;
     cpu_exec_init(env);
 
-    memset(env, 0, sizeof(CPUM68KState));
-    /* ??? FP regs should be initialized to NaN.  */
-    cpu_single_env = env;
-    env->cc_op = CC_OP_FLAGS;
+    cpu_reset(env);
     return env;
 }
 
@@ -2696,23 +2880,20 @@
     free(env);
 }
 
-m68k_def_t *m68k_find_by_name(const char *name)
+int cpu_m68k_set_model(CPUM68KState *env, const char * name)
 {
     m68k_def_t *def;
 
-    def = m68k_cpu_defs;
-    while (def->name)
-      {
+    for (def = m68k_cpu_defs; def->name; def++) {
         if (strcmp(def->name, name) == 0)
-            return def;
-        def++;
-      }
-    return NULL;
-}
+            break;
+    }
+    if (!def->name)
+        return 1;
 
-void cpu_m68k_register(CPUM68KState *env, m68k_def_t *def)
-{
     register_m68k_insns(def);
+
+    return 0;
 }
 
 void cpu_dump_state(CPUState *env, FILE *f, 
@@ -2737,24 +2918,3 @@
     cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result);
 }
 
-/* ??? */
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
-    return addr;
-}
-
-#if defined(CONFIG_USER_ONLY) 
-
-int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                               int is_user, int is_softmmu)
-{
-    env->exception_index = EXCP_ACCESS;
-    env->mmu.ar = address;
-    return 1;
-}
-
-#else
-
-#error not implemented
-
-#endif

Modified: trunk/src/host/qemu-neo1973/target-mips/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/cpu.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/cpu.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -81,9 +81,9 @@
 #define FCR0_REV 0
     /* fcsr */
     uint32_t fcr31;
-#define SET_FP_COND(num,env)     do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
-#define CLEAR_FP_COND(num,env)   do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
-#define IS_FP_COND_SET(num,env)  (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0)
+#define SET_FP_COND(num,env)     do { ((env)->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0)
+#define CLEAR_FP_COND(num,env)   do { ((env)->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << 23)); } while(0)
+#define GET_FP_COND(env)         ((((env)->fcr31 >> 24) & 0xfe) | (((env)->fcr31 >> 23) & 0x1))
 #define GET_FP_CAUSE(reg)        (((reg) >> 12) & 0x3f)
 #define GET_FP_ENABLE(reg)       (((reg) >>  7) & 0x1f)
 #define GET_FP_FLAGS(reg)        (((reg) >>  2) & 0x1f)
@@ -216,8 +216,8 @@
     int32_t CP0_Config6;
     int32_t CP0_Config7;
     target_ulong CP0_LLAddr;
-    target_ulong CP0_WatchLo;
-    int32_t CP0_WatchHi;
+    target_ulong CP0_WatchLo[8];
+    int32_t CP0_WatchHi[8];
     target_ulong CP0_XContext;
     int32_t CP0_Framemask;
     int32_t CP0_Debug;

Modified: trunk/src/host/qemu-neo1973/target-mips/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/exec.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/exec.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -165,4 +165,79 @@
 void cpu_mips_clock_init (CPUState *env);
 void cpu_mips_tlb_flush (CPUState *env, int flush_global);
 
+void do_ctc1 (void);
+
+#define FOP_PROTO(op)              \
+void do_float_ ## op ## _s(void);  \
+void do_float_ ## op ## _d(void);
+FOP_PROTO(roundl)
+FOP_PROTO(roundw)
+FOP_PROTO(truncl)
+FOP_PROTO(truncw)
+FOP_PROTO(ceill)
+FOP_PROTO(ceilw)
+FOP_PROTO(floorl)
+FOP_PROTO(floorw)
+FOP_PROTO(rsqrt)
+FOP_PROTO(recip)
+#undef FOP_PROTO
+
+#define FOP_PROTO(op)              \
+void do_float_ ## op ## _s(void);  \
+void do_float_ ## op ## _d(void);  \
+void do_float_ ## op ## _ps(void);
+FOP_PROTO(add)
+FOP_PROTO(sub)
+FOP_PROTO(mul)
+FOP_PROTO(div)
+FOP_PROTO(recip1)
+FOP_PROTO(recip2)
+FOP_PROTO(rsqrt1)
+FOP_PROTO(rsqrt2)
+#undef FOP_PROTO
+
+void do_float_cvtd_s(void);
+void do_float_cvtd_w(void);
+void do_float_cvtd_l(void);
+void do_float_cvtl_d(void);
+void do_float_cvtl_s(void);
+void do_float_cvtps_pw(void);
+void do_float_cvtpw_ps(void);
+void do_float_cvts_d(void);
+void do_float_cvts_w(void);
+void do_float_cvts_l(void);
+void do_float_cvts_pl(void);
+void do_float_cvts_pu(void);
+void do_float_cvtw_s(void);
+void do_float_cvtw_d(void);
+
+void do_float_addr_ps(void);
+void do_float_mulr_ps(void);
+
+#define FOP_PROTO(op)                      \
+void do_cmp_d_ ## op(long cc);             \
+void do_cmpabs_d_ ## op(long cc);          \
+void do_cmp_s_ ## op(long cc);             \
+void do_cmpabs_s_ ## op(long cc);          \
+void do_cmp_ps_ ## op(long cc);            \
+void do_cmpabs_ps_ ## op(long cc);
+
+FOP_PROTO(f)
+FOP_PROTO(un)
+FOP_PROTO(eq)
+FOP_PROTO(ueq)
+FOP_PROTO(olt)
+FOP_PROTO(ult)
+FOP_PROTO(ole)
+FOP_PROTO(ule)
+FOP_PROTO(sf)
+FOP_PROTO(ngle)
+FOP_PROTO(seq)
+FOP_PROTO(ngl)
+FOP_PROTO(lt)
+FOP_PROTO(nge)
+FOP_PROTO(le)
+FOP_PROTO(ngt)
+#undef FOP_PROTO
+
 #endif /* !defined(__QEMU_MIPS_EXEC_H__) */

Modified: trunk/src/host/qemu-neo1973/target-mips/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/helper.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/helper.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -381,7 +381,7 @@
         break;
     case EXCP_SRESET:
         env->CP0_Status |= (1 << CP0St_SR);
-        env->CP0_WatchLo = 0;
+        memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
         goto set_error_EPC;
     case EXCP_NMI:
         env->CP0_Status |= (1 << CP0St_NMI);

Modified: trunk/src/host/qemu-neo1973/target-mips/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/op.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -3,6 +3,7 @@
  * 
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *  Copyright (c) 2006 Marius Groeger (FPU operations)
+ *  Copyright (c) 2007 Thiemo Seufer (64-bit FPU support)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -928,14 +929,14 @@
 
 OP_COND(eq, T0 == T1);
 OP_COND(ne, T0 != T1);
-OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
+OP_COND(ge, (target_long)T0 >= (target_long)T1);
 OP_COND(geu, T0 >= T1);
-OP_COND(lt, (int32_t)T0 < (int32_t)T1);
+OP_COND(lt, (target_long)T0 < (target_long)T1);
 OP_COND(ltu, T0 < T1);
-OP_COND(gez, (int32_t)T0 >= 0);
-OP_COND(gtz, (int32_t)T0 > 0);
-OP_COND(lez, (int32_t)T0 <= 0);
-OP_COND(ltz, (int32_t)T0 < 0);
+OP_COND(gez, (target_long)T0 >= 0);
+OP_COND(gtz, (target_long)T0 > 0);
+OP_COND(lez, (target_long)T0 <= 0);
+OP_COND(ltz, (target_long)T0 < 0);
 
 /* Branches */
 void OPPROTO op_goto_tb0(void)
@@ -1170,15 +1171,15 @@
     RETURN();
 }
 
-void op_mfc0_watchlo0 (void)
+void op_mfc0_watchlo (void)
 {
-    T0 = (int32_t)env->CP0_WatchLo;
+    T0 = (int32_t)env->CP0_WatchLo[PARAM1];
     RETURN();
 }
 
-void op_mfc0_watchhi0 (void)
+void op_mfc0_watchhi (void)
 {
-    T0 = env->CP0_WatchHi;
+    T0 = env->CP0_WatchHi[PARAM1];
     RETURN();
 }
 
@@ -1422,18 +1423,18 @@
     RETURN();
 }
 
-void op_mtc0_watchlo0 (void)
+void op_mtc0_watchlo (void)
 {
     /* Watch exceptions for instructions, data loads, data stores
        not implemented. */
-    env->CP0_WatchLo = (T0 & ~0x7);
+    env->CP0_WatchLo[PARAM1] = (T0 & ~0x7);
     RETURN();
 }
 
-void op_mtc0_watchhi0 (void)
+void op_mtc0_watchhi (void)
 {
-    env->CP0_WatchHi = (T0 & 0x40FF0FF8);
-    env->CP0_WatchHi &= ~(env->CP0_WatchHi & T0 & 0x7);
+    env->CP0_WatchHi[PARAM1] = (T0 & 0x40FF0FF8);
+    env->CP0_WatchHi[PARAM1] &= ~(env->CP0_WatchHi[PARAM1] & T0 & 0x7);
     RETURN();
 }
 
@@ -1550,9 +1551,9 @@
     RETURN();
 }
 
-void op_dmfc0_watchlo0 (void)
+void op_dmfc0_watchlo (void)
 {
-    T0 = env->CP0_WatchLo;
+    T0 = env->CP0_WatchLo[PARAM1];
     RETURN();
 }
 
@@ -1599,47 +1600,33 @@
     RETURN();
 }
 
-/* convert MIPS rounding mode in FCR31 to IEEE library */
-unsigned int ieee_rm[] = { 
-    float_round_nearest_even,
-    float_round_to_zero,
-    float_round_up,
-    float_round_down
-};
-
-#define RESTORE_ROUNDING_MODE \
-    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
-
-inline char ieee_ex_to_mips(char xcpt)
+void op_cp1_64bitmode(void)
 {
-    return (xcpt & float_flag_inexact) >> 5 |
-           (xcpt & float_flag_underflow) >> 3 |
-           (xcpt & float_flag_overflow) >> 1 |
-           (xcpt & float_flag_divbyzero) << 1 |
-           (xcpt & float_flag_invalid) << 4;
+    if (!(env->CP0_Status & (1 << CP0St_FR))) {
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
+    }
+    RETURN();
 }
 
-inline char mips_ex_to_ieee(char xcpt)
+/*
+ * Verify if floating point register is valid; an operation is not defined
+ * if bit 0 of any register specification is set and the FR bit in the
+ * Status register equals zero, since the register numbers specify an
+ * even-odd pair of adjacent coprocessor general registers. When the FR bit
+ * in the Status register equals one, both even and odd register numbers
+ * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers.
+ *
+ * Multiple 64 bit wide registers can be checked by calling
+ * gen_op_cp1_registers(freg1 | freg2 | ... | fregN);
+ */
+void op_cp1_registers(void)
 {
-    return (xcpt & FP_INEXACT) << 5 |
-           (xcpt & FP_UNDERFLOW) << 3 |
-           (xcpt & FP_OVERFLOW) << 1 |
-           (xcpt & FP_DIV0) >> 1 |
-           (xcpt & FP_INVALID) >> 4;
+    if (!(env->CP0_Status & (1 << CP0St_FR)) && (PARAM1 & 1)) {
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
+    }
+    RETURN();
 }
 
-inline void update_fcr31(void)
-{
-    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status));
-
-    SET_FP_CAUSE(env->fcr31, tmp);
-    if (GET_FP_ENABLE(env->fcr31) & tmp)
-        CALL_FROM_TB1(do_raise_exception, EXCP_FPE);
-    else
-        UPDATE_FP_FLAGS(env->fcr31, tmp);
-}
-
-
 void op_cfc1 (void)
 {
     switch (T1) {
@@ -1665,38 +1652,7 @@
 
 void op_ctc1 (void)
 {
-    switch(T1) {
-    case 25:
-        if (T0 & 0xffffff00)
-            goto leave;
-        env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
-                     ((T0 & 0x1) << 23);
-        break;
-    case 26:
-        if (T0 & 0x007c0000)
-            goto leave;
-        env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
-        break;
-    case 28:
-        if (T0 & 0x007c0000)
-            goto leave;
-        env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
-                     ((T0 & 0x4) << 22);
-        break;
-    case 31:
-        if (T0 & 0x007c0000)
-            goto leave;
-        env->fcr31 = T0;
-        break;
-    default:
-        goto leave;
-    }
-    /* set rounding mode */
-    RESTORE_ROUNDING_MODE;
-    set_float_exception_flags(0, &env->fp_status);
-    if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31))
-        CALL_FROM_TB1(do_raise_exception, EXCP_FPE);
- leave:
+    CALL_FROM_TB0(do_ctc1);
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1752,45 +1708,31 @@
 
 FLOAT_OP(cvtd, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = float32_to_float64(FST0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvtd_s);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtd, w)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = int32_to_float64(WT0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvtd_w);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtd, l)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FDT2 = int64_to_float64(DT0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvtd_l);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtl, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    DT2 = float64_to_int64(FDT0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
+    CALL_FROM_TB0(do_float_cvtl_d);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtl, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    DT2 = float32_to_int64(FST0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
+    CALL_FROM_TB0(do_float_cvtl_s);
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1803,81 +1745,55 @@
 }
 FLOAT_OP(cvtps, pw)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = int32_to_float32(WT0, &env->fp_status);
-    FSTH2 = int32_to_float32(WTH0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvtps_pw);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtpw, ps)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
-    WTH2 = float32_to_int32(FSTH0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
+    CALL_FROM_TB0(do_float_cvtpw_ps);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float64_to_float32(FDT0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvts_d);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, w)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = int32_to_float32(WT0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvts_w);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, l)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = int64_to_float32(DT0, &env->fp_status);
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvts_l);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, pl)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = WT0;
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvts_pl);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, pu)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = WTH0;
-    update_fcr31();
+    CALL_FROM_TB0(do_float_cvts_pu);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtw, s)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = float32_to_int32(FST0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
+    CALL_FROM_TB0(do_float_cvtw_s);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtw, d)
 {
-    set_float_exception_flags(0, &env->fp_status);
-    WT2 = float64_to_int32(FDT0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
+    CALL_FROM_TB0(do_float_cvtw_d);
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1907,178 +1823,35 @@
     RETURN();
 }
 
-FLOAT_OP(roundl, d)
-{
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    DT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
+#define FLOAT_ROUNDOP(op, ttype, stype)                    \
+FLOAT_OP(op ## ttype, stype)                               \
+{                                                          \
+    CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \
+    DEBUG_FPU_STATE();                                     \
+    RETURN();                                              \
 }
-FLOAT_OP(roundl, s)
-{
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    DT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(roundw, d)
-{
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    WT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(roundw, s)
-{
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    WT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
 
-FLOAT_OP(truncl, d)
-{
-    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(truncl, s)
-{
-    DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(truncw, d)
-{
-    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(truncw, s)
-{
-    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
+FLOAT_ROUNDOP(round, l, d)
+FLOAT_ROUNDOP(round, l, s)
+FLOAT_ROUNDOP(round, w, d)
+FLOAT_ROUNDOP(round, w, s)
 
-FLOAT_OP(ceill, d)
-{
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    DT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(ceill, s)
-{
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    DT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(ceilw, d)
-{
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    WT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(ceilw, s)
-{
-    set_float_rounding_mode(float_round_up, &env->fp_status);
-    WT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
+FLOAT_ROUNDOP(trunc, l, d)
+FLOAT_ROUNDOP(trunc, l, s)
+FLOAT_ROUNDOP(trunc, w, d)
+FLOAT_ROUNDOP(trunc, w, s)
 
-FLOAT_OP(floorl, d)
-{
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    DT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(floorl, s)
-{
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    DT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        DT2 = 0x7fffffffffffffffULL;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(floorw, d)
-{
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    WT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-FLOAT_OP(floorw, s)
-{
-    set_float_rounding_mode(float_round_down, &env->fp_status);
-    WT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-    update_fcr31();
-    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
-        WT2 = 0x7fffffff;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
+FLOAT_ROUNDOP(ceil, l, d)
+FLOAT_ROUNDOP(ceil, l, s)
+FLOAT_ROUNDOP(ceil, w, d)
+FLOAT_ROUNDOP(ceil, w, s)
 
+FLOAT_ROUNDOP(floor, l, d)
+FLOAT_ROUNDOP(floor, l, s)
+FLOAT_ROUNDOP(floor, w, d)
+FLOAT_ROUNDOP(floor, w, s)
+#undef FLOAR_ROUNDOP
+
 FLOAT_OP(movf, d)
 {
     if (!(env->fcr31 & PARAM1))
@@ -2172,49 +1945,66 @@
     RETURN();
 }
 
-/* binary operations */
-#define FLOAT_BINOP(name) \
+/* operations calling helpers, for s, d and ps */
+#define FLOAT_HOP(name) \
 FLOAT_OP(name, d)         \
 {                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
-    update_fcr31();       \
+    CALL_FROM_TB0(do_float_ ## name ## _d);  \
     DEBUG_FPU_STATE();    \
     RETURN();             \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
-    update_fcr31();       \
+    CALL_FROM_TB0(do_float_ ## name ## _s);  \
     DEBUG_FPU_STATE();    \
     RETURN();             \
 }                         \
 FLOAT_OP(name, ps)        \
 {                         \
-    set_float_exception_flags(0, &env->fp_status);            \
-    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
-    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
-    update_fcr31();       \
+    CALL_FROM_TB0(do_float_ ## name ## _ps); \
     DEBUG_FPU_STATE();    \
     RETURN();             \
 }
-FLOAT_BINOP(add)
-FLOAT_BINOP(sub)
-FLOAT_BINOP(mul)
-FLOAT_BINOP(div)
-#undef FLOAT_BINOP
+FLOAT_HOP(add)
+FLOAT_HOP(sub)
+FLOAT_HOP(mul)
+FLOAT_HOP(div)
+FLOAT_HOP(recip2)
+FLOAT_HOP(rsqrt2)
+FLOAT_HOP(rsqrt1)
+FLOAT_HOP(recip1)
+#undef FLOAT_HOP
 
-FLOAT_OP(addr, ps)
-{
-    set_float_exception_flags(0, &env->fp_status);
-    FST2 = float32_add (FST0, FSTH0, &env->fp_status);
-    FSTH2 = float32_add (FST1, FSTH1, &env->fp_status);
-    update_fcr31();
-    DEBUG_FPU_STATE();
-    RETURN();
+/* operations calling helpers, for s and d */
+#define FLOAT_HOP(name)   \
+FLOAT_OP(name, d)         \
+{                         \
+    CALL_FROM_TB0(do_float_ ## name ## _d);  \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    CALL_FROM_TB0(do_float_ ## name ## _s);  \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
 }
+FLOAT_HOP(rsqrt)
+FLOAT_HOP(recip)
+#undef FLOAT_HOP
 
+/* operations calling helpers, for ps */
+#define FLOAT_HOP(name)   \
+FLOAT_OP(name, ps)        \
+{                         \
+    CALL_FROM_TB0(do_float_ ## name ## _ps); \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
+}
+FLOAT_HOP(addr)
+FLOAT_HOP(mulr)
+#undef FLOAT_HOP
+
 /* ternary operations */
 #define FLOAT_TERNOP(name1, name2) \
 FLOAT_OP(name1 ## name2, d)        \
@@ -2289,14 +2079,7 @@
 {                         \
     FST2 = float32_ ## name(FST0, &env->fp_status);   \
     DEBUG_FPU_STATE();    \
-    RETURN();                      \
-}                         \
-FLOAT_OP(name, ps)        \
-{                         \
-    FST2 = float32_ ## name(FST0, &env->fp_status);   \
-    FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \
-    DEBUG_FPU_STATE();    \
-    RETURN();                      \
+    RETURN();             \
 }
 FLOAT_UNOP(sqrt)
 #undef FLOAT_UNOP
@@ -2380,249 +2163,77 @@
 
 extern void dump_fpu_s(CPUState *env);
 
-#define FOP_COND_D(op, cond)                   \
-void op_cmp_d_ ## op (void)                    \
-{                                              \
-    int c = cond;                              \
-    update_fcr31();                            \
-    if (c)                                     \
-        SET_FP_COND(PARAM1, env);              \
-    else                                       \
-        CLEAR_FP_COND(PARAM1, env);            \
-    DEBUG_FPU_STATE();                         \
-    RETURN();                                  \
-}                                              \
-void op_cmpabs_d_ ## op (void)                 \
-{                                              \
-    int c;                                     \
-    FDT0 &= ~(1ULL << 63);                     \
-    FDT1 &= ~(1ULL << 63);                     \
-    c = cond;                                  \
-    update_fcr31();                            \
-    if (c)                                     \
-        SET_FP_COND(PARAM1, env);              \
-    else                                       \
-        CLEAR_FP_COND(PARAM1, env);            \
-    DEBUG_FPU_STATE();                         \
-    RETURN();                                  \
+#define CMP_OP(fmt, op)                                \
+void OPPROTO op_cmp ## _ ## fmt ## _ ## op(void)       \
+{                                                      \
+    CALL_FROM_TB1(do_cmp ## _ ## fmt ## _ ## op, PARAM1); \
+    DEBUG_FPU_STATE();                                 \
+    RETURN();                                          \
+}                                                      \
+void OPPROTO op_cmpabs ## _ ## fmt ## _ ## op(void)    \
+{                                                      \
+    CALL_FROM_TB1(do_cmpabs ## _ ## fmt ## _ ## op, PARAM1); \
+    DEBUG_FPU_STATE();                                 \
+    RETURN();                                          \
 }
+#define CMP_OPS(op)   \
+CMP_OP(d, op)         \
+CMP_OP(s, op)         \
+CMP_OP(ps, op)
 
-int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
-{
-    if (float64_is_signaling_nan(a) ||
-        float64_is_signaling_nan(b) ||
-        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    } else if (float64_is_nan(a) || float64_is_nan(b)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
+CMP_OPS(f)
+CMP_OPS(un)
+CMP_OPS(eq)
+CMP_OPS(ueq)
+CMP_OPS(olt)
+CMP_OPS(ult)
+CMP_OPS(ole)
+CMP_OPS(ule)
+CMP_OPS(sf)
+CMP_OPS(ngle)
+CMP_OPS(seq)
+CMP_OPS(ngl)
+CMP_OPS(lt)
+CMP_OPS(nge)
+CMP_OPS(le)
+CMP_OPS(ngt)
+#undef CMP_OPS
+#undef CMP_OP
 
-/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0))
-FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fp_status))
-FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
-/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0))
-FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status))
-FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
-
-#define FOP_COND_S(op, cond)                   \
-void op_cmp_s_ ## op (void)                    \
-{                                              \
-    int c = cond;                              \
-    update_fcr31();                            \
-    if (c)                                     \
-        SET_FP_COND(PARAM1, env);              \
-    else                                       \
-        CLEAR_FP_COND(PARAM1, env);            \
-    DEBUG_FPU_STATE();                         \
-    RETURN();                                  \
-}                                              \
-void op_cmpabs_s_ ## op (void)                 \
-{                                              \
-    int c;                                     \
-    FST0 &= ~(1 << 31);                        \
-    FST1 &= ~(1 << 31);                        \
-    c = cond;                                  \
-    update_fcr31();                            \
-    if (c)                                     \
-        SET_FP_COND(PARAM1, env);              \
-    else                                       \
-        CLEAR_FP_COND(PARAM1, env);            \
-    DEBUG_FPU_STATE();                         \
-    RETURN();                                  \
-}
-
-flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
-{
-    extern flag float32_is_nan(float32 a);
-    if (float32_is_signaling_nan(a) ||
-        float32_is_signaling_nan(b) ||
-        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    } else if (float32_is_nan(a) || float32_is_nan(b)) {
-        return 1;
-    } else {
-        return 0;
-    }
-}
-
-/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0))
-FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status))
-FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
-FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
-/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0))
-FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status))
-FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
-FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
-
-#define FOP_COND_PS(op, condl, condh)          \
-void op_cmp_ps_ ## op (void)                   \
-{                                              \
-    int cl = condl;                            \
-    int ch = condh;                            \
-    update_fcr31();                            \
-    if (cl)                                    \
-        SET_FP_COND(PARAM1, env);              \
-    else                                       \
-        CLEAR_FP_COND(PARAM1, env);            \
-    if (ch)                                    \
-        SET_FP_COND(PARAM1 + 1, env);          \
-    else                                       \
-        CLEAR_FP_COND(PARAM1 + 1, env);        \
-    DEBUG_FPU_STATE();                         \
-    RETURN();                                  \
-}                                              \
-void op_cmpabs_ps_ ## op (void)                \
-{                                              \
-    int cl, ch;                                \
-    FST0 &= ~(1 << 31);                        \
-    FSTH0 &= ~(1 << 31);                       \
-    FST1 &= ~(1 << 31);                        \
-    FSTH1 &= ~(1 << 31);                       \
-    cl = condl;                                \
-    ch = condh;                                \
-    update_fcr31();                            \
-    if (cl)                                    \
-        SET_FP_COND(PARAM1, env);              \
-    else                                       \
-        CLEAR_FP_COND(PARAM1, env);            \
-    if (ch)                                    \
-        SET_FP_COND(PARAM1 + 1, env);          \
-    else                                       \
-        CLEAR_FP_COND(PARAM1 + 1, env);        \
-    DEBUG_FPU_STATE();                         \
-    RETURN();                                  \
-}
-
-/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0),
-                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0))
-FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status))
-FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
-/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called. */
-FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0),
-                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0))
-FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status))
-FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
-                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
-FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
-                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
-
 void op_bc1f (void)
 {
-    T0 = !IS_FP_COND_SET(PARAM1, env);
+    T0 = !!(~GET_FP_COND(env) & (0x1 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
-void op_bc1fany2 (void)
+void op_bc1any2f (void)
 {
-    T0 = (!IS_FP_COND_SET(PARAM1, env) ||
-          !IS_FP_COND_SET(PARAM1 + 1, env));
+    T0 = !!(~GET_FP_COND(env) & (0x3 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
-void op_bc1fany4 (void)
+void op_bc1any4f (void)
 {
-    T0 = (!IS_FP_COND_SET(PARAM1, env) ||
-          !IS_FP_COND_SET(PARAM1 + 1, env) ||
-          !IS_FP_COND_SET(PARAM1 + 2, env) ||
-          !IS_FP_COND_SET(PARAM1 + 3, env));
+    T0 = !!(~GET_FP_COND(env) & (0xf << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 
 void op_bc1t (void)
 {
-    T0 = IS_FP_COND_SET(PARAM1, env);
+    T0 = !!(GET_FP_COND(env) & (0x1 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
-void op_bc1tany2 (void)
+void op_bc1any2t (void)
 {
-    T0 = (IS_FP_COND_SET(PARAM1, env) ||
-          IS_FP_COND_SET(PARAM1 + 1, env));
+    T0 = !!(GET_FP_COND(env) & (0x3 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
-void op_bc1tany4 (void)
+void op_bc1any4t (void)
 {
-    T0 = (IS_FP_COND_SET(PARAM1, env) ||
-          IS_FP_COND_SET(PARAM1 + 1, env) ||
-          IS_FP_COND_SET(PARAM1 + 2, env) ||
-          IS_FP_COND_SET(PARAM1 + 3, env));
+    T0 = !!(GET_FP_COND(env) & (0xf << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -2798,17 +2409,6 @@
     RETURN();
 }
 
-void op_save_fp_status (void)
-{
-    union fps {
-        uint32_t i;
-        float_status f;
-    } fps;
-    fps.i = PARAM1;
-    env->fp_status = fps.f;
-    RETURN();
-}
-
 void op_interrupt_restart (void)
 {
     if (!(env->CP0_Status & (1 << CP0St_EXL)) &&

Modified: trunk/src/host/qemu-neo1973/target-mips/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_helper.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/op_helper.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -598,3 +598,657 @@
 }
 
 #endif
+
+/* Complex FPU operations which may need stack space. */
+
+/* convert MIPS rounding mode in FCR31 to IEEE library */
+unsigned int ieee_rm[] = {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down
+};
+
+#define RESTORE_ROUNDING_MODE \
+    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
+
+void do_ctc1 (void)
+{
+    switch(T1) {
+    case 25:
+        if (T0 & 0xffffff00)
+            return;
+        env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
+                     ((T0 & 0x1) << 23);
+        break;
+    case 26:
+        if (T0 & 0x007c0000)
+            return;
+        env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
+        break;
+    case 28:
+        if (T0 & 0x007c0000)
+            return;
+        env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
+                     ((T0 & 0x4) << 22);
+        break;
+    case 31:
+        if (T0 & 0x007c0000)
+            return;
+        env->fcr31 = T0;
+        break;
+    default:
+        return;
+    }
+    /* set rounding mode */
+    RESTORE_ROUNDING_MODE;
+    set_float_exception_flags(0, &env->fp_status);
+    if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31))
+        do_raise_exception(EXCP_FPE);
+}
+
+inline char ieee_ex_to_mips(char xcpt)
+{
+    return (xcpt & float_flag_inexact) >> 5 |
+           (xcpt & float_flag_underflow) >> 3 |
+           (xcpt & float_flag_overflow) >> 1 |
+           (xcpt & float_flag_divbyzero) << 1 |
+           (xcpt & float_flag_invalid) << 4;
+}
+
+inline char mips_ex_to_ieee(char xcpt)
+{
+    return (xcpt & FP_INEXACT) << 5 |
+           (xcpt & FP_UNDERFLOW) << 3 |
+           (xcpt & FP_OVERFLOW) << 1 |
+           (xcpt & FP_DIV0) >> 1 |
+           (xcpt & FP_INVALID) >> 4;
+}
+
+inline void update_fcr31(void)
+{
+    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status));
+
+    SET_FP_CAUSE(env->fcr31, tmp);
+    if (GET_FP_ENABLE(env->fcr31) & tmp)
+        do_raise_exception(EXCP_FPE);
+    else
+        UPDATE_FP_FLAGS(env->fcr31, tmp);
+}
+
+#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
+
+FLOAT_OP(cvtd, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = float32_to_float64(FST0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtd, w)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = int32_to_float64(WT0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtd, l)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FDT2 = int64_to_float64(DT0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtl, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(cvtl, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+
+FLOAT_OP(cvtps, pw)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = int32_to_float32(WT0, &env->fp_status);
+    FSTH2 = int32_to_float32(WTH0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtpw, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fp_status);
+    WTH2 = float32_to_int32(FSTH0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+FLOAT_OP(cvts, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float64_to_float32(FDT0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvts, w)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = int32_to_float32(WT0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvts, l)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = int64_to_float32(DT0, &env->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvts, pl)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    WT2 = WT0;
+    update_fcr31();
+}
+FLOAT_OP(cvts, pu)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    WT2 = WTH0;
+    update_fcr31();
+}
+FLOAT_OP(cvtw, s)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+FLOAT_OP(cvtw, d)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+
+FLOAT_OP(roundl, d)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    DT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(roundl, s)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    DT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(roundw, d)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    WT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+FLOAT_OP(roundw, s)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+    WT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+
+FLOAT_OP(truncl, d)
+{
+    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(truncl, s)
+{
+    DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(truncw, d)
+{
+    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+FLOAT_OP(truncw, s)
+{
+    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+
+FLOAT_OP(ceill, d)
+{
+    set_float_rounding_mode(float_round_up, &env->fp_status);
+    DT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(ceill, s)
+{
+    set_float_rounding_mode(float_round_up, &env->fp_status);
+    DT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(ceilw, d)
+{
+    set_float_rounding_mode(float_round_up, &env->fp_status);
+    WT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+FLOAT_OP(ceilw, s)
+{
+    set_float_rounding_mode(float_round_up, &env->fp_status);
+    WT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+
+FLOAT_OP(floorl, d)
+{
+    set_float_rounding_mode(float_round_down, &env->fp_status);
+    DT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(floorl, s)
+{
+    set_float_rounding_mode(float_round_down, &env->fp_status);
+    DT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = 0x7fffffffffffffffULL;
+}
+FLOAT_OP(floorw, d)
+{
+    set_float_rounding_mode(float_round_down, &env->fp_status);
+    WT2 = float64_round_to_int(FDT0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+FLOAT_OP(floorw, s)
+{
+    set_float_rounding_mode(float_round_down, &env->fp_status);
+    WT2 = float32_round_to_int(FST0, &env->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = 0x7fffffff;
+}
+
+/* unary operations, MIPS specific, s and d */
+#define FLOAT_UNOP(name)  \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}
+FLOAT_UNOP(rsqrt)
+FLOAT_UNOP(recip)
+#undef FLOAT_UNOP
+
+/* unary operations, MIPS specific, s, d and ps */
+#define FLOAT_UNOP(name)  \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FDT2 = float64_ ## name (FDT0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, &env->fp_status);*/          \
+/*    FSTH2 = float32_ ## name (FSTH0, &env->fp_status);*/        \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}
+FLOAT_UNOP(rsqrt1)
+FLOAT_UNOP(recip1)
+#undef FLOAT_UNOP
+
+/* binary operations */
+#define FLOAT_BINOP(name) \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
+    update_fcr31();                                           \
+    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
+        FDT2 = 0x7ff7ffffffffffffULL;                         \
+    else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
+        if ((env->fcr31 & 0x3) == 0)                          \
+            FDT2 &= 0x8000000000000000ULL;                    \
+    }                     \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
+    update_fcr31();                                           \
+    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID)                \
+        FST2 = 0x7fbfffff;                                    \
+    else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {       \
+        if ((env->fcr31 & 0x3) == 0)                          \
+            FST2 &= 0x80000000ULL;                            \
+    }                     \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
+    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
+    update_fcr31();       \
+    if (GET_FP_CAUSE(env->fcr31) & FP_INVALID) {              \
+        FST2 = 0x7fbfffff;                                    \
+        FSTH2 = 0x7fbfffff;                                   \
+    } else if (GET_FP_CAUSE(env->fcr31) & FP_UNDERFLOW) {     \
+        if ((env->fcr31 & 0x3) == 0) {                        \
+            FST2 &= 0x80000000ULL;                            \
+            FSTH2 &= 0x80000000ULL;                           \
+        }                 \
+    }                     \
+}
+FLOAT_BINOP(add)
+FLOAT_BINOP(sub)
+FLOAT_BINOP(mul)
+FLOAT_BINOP(div)
+#undef FLOAT_BINOP
+
+/* binary operations, MIPS specific */
+#define FLOAT_BINOP(name) \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);*/    \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    set_float_exception_flags(0, &env->fp_status);            \
+/* XXX: not implemented */ \
+/*    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);*/    \
+/*    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status);*/ \
+do_raise_exception(EXCP_RI); \
+    update_fcr31();       \
+}
+FLOAT_BINOP(rsqrt2)
+FLOAT_BINOP(recip2)
+#undef FLOAT_BINOP
+
+FLOAT_OP(addr, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_add (FST0, FSTH0, &env->fp_status);
+    FSTH2 = float32_add (FST1, FSTH1, &env->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(mulr, ps)
+{
+    set_float_exception_flags(0, &env->fp_status);
+    FST2 = float32_mul (FST0, FSTH0, &env->fp_status);
+    FSTH2 = float32_mul (FST1, FSTH1, &env->fp_status);
+    update_fcr31();
+}
+
+#define FOP_COND_D(op, cond)                   \
+void do_cmp_d_ ## op (long cc)                 \
+{                                              \
+    int c = cond;                              \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(cc, env);                  \
+    else                                       \
+        CLEAR_FP_COND(cc, env);                \
+}                                              \
+void do_cmpabs_d_ ## op (long cc)              \
+{                                              \
+    int c;                                     \
+    FDT0 &= ~(1ULL << 63);                     \
+    FDT1 &= ~(1ULL << 63);                     \
+    c = cond;                                  \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(cc, env);                  \
+    else                                       \
+        CLEAR_FP_COND(cc, env);                \
+}
+
+int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
+{
+    if (float64_is_signaling_nan(a) ||
+        float64_is_signaling_nan(b) ||
+        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
+        float_raise(float_flag_invalid, status);
+        return 1;
+    } else if (float64_is_nan(a) || float64_is_nan(b)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_D(f,   (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0))
+FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fp_status))
+FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_D(sf,  (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0))
+FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status))
+FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status)  || float64_le(FDT0, FDT1, &env->fp_status))
+
+#define FOP_COND_S(op, cond)                   \
+void do_cmp_s_ ## op (long cc)                 \
+{                                              \
+    int c = cond;                              \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(cc, env);                  \
+    else                                       \
+        CLEAR_FP_COND(cc, env);                \
+}                                              \
+void do_cmpabs_s_ ## op (long cc)              \
+{                                              \
+    int c;                                     \
+    FST0 &= ~(1 << 31);                        \
+    FST1 &= ~(1 << 31);                        \
+    c = cond;                                  \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(cc, env);                  \
+    else                                       \
+        CLEAR_FP_COND(cc, env);                \
+}
+
+flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
+{
+    extern flag float32_is_nan(float32 a);
+    if (float32_is_signaling_nan(a) ||
+        float32_is_signaling_nan(b) ||
+        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
+        float_raise(float_flag_invalid, status);
+        return 1;
+    } else if (float32_is_nan(a) || float32_is_nan(b)) {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_S(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0))
+FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status))
+FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
+FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_S(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0))
+FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status))
+FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
+FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)  || float32_le(FST0, FST1, &env->fp_status))
+
+#define FOP_COND_PS(op, condl, condh)          \
+void do_cmp_ps_ ## op (long cc)                \
+{                                              \
+    int cl = condl;                            \
+    int ch = condh;                            \
+    update_fcr31();                            \
+    if (cl)                                    \
+        SET_FP_COND(cc, env);                  \
+    else                                       \
+        CLEAR_FP_COND(cc, env);                \
+    if (ch)                                    \
+        SET_FP_COND(cc + 1, env);              \
+    else                                       \
+        CLEAR_FP_COND(cc + 1, env);            \
+}                                              \
+void do_cmpabs_ps_ ## op (long cc)             \
+{                                              \
+    int cl, ch;                                \
+    FST0 &= ~(1 << 31);                        \
+    FSTH0 &= ~(1 << 31);                       \
+    FST1 &= ~(1 << 31);                        \
+    FSTH1 &= ~(1 << 31);                       \
+    cl = condl;                                \
+    ch = condh;                                \
+    update_fcr31();                            \
+    if (cl)                                    \
+        SET_FP_COND(cc, env);                  \
+    else                                       \
+        CLEAR_FP_COND(cc, env);                \
+    if (ch)                                    \
+        SET_FP_COND(cc + 1, env);              \
+    else                                       \
+        CLEAR_FP_COND(cc + 1, env);            \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_PS(f,   (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0),
+                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0))
+FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status))
+FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_PS(sf,  (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0),
+                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0))
+FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status))
+FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_eq(FST0, FST1, &env->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_eq(FST0, FST1, &env->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_lt(FST0, FST1, &env->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_lt(FST0, FST1, &env->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fp_status)   && float32_le(FST0, FST1, &env->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status)    || float32_le(FST0, FST1, &env->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status)  || float32_le(FSTH0, FSTH1, &env->fp_status))

Modified: trunk/src/host/qemu-neo1973/target-mips/op_mem.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_mem.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/op_mem.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -220,35 +220,13 @@
     glue(stq, MEMSUFFIX)(T0, DT0);
     RETURN();
 }
-void glue(op_lwxc1, MEMSUFFIX) (void)
-{
-    WT0 = glue(ldl, MEMSUFFIX)(T0 + T1);
-    RETURN();
-}
-void glue(op_swxc1, MEMSUFFIX) (void)
-{
-    glue(stl, MEMSUFFIX)(T0 + T1, WT0);
-    RETURN();
-}
-void glue(op_ldxc1, MEMSUFFIX) (void)
-{
-    DT0 = glue(ldq, MEMSUFFIX)(T0 + T1);
-    RETURN();
-}
-void glue(op_sdxc1, MEMSUFFIX) (void)
-{
-    glue(stq, MEMSUFFIX)(T0 + T1, DT0);
-    RETURN();
-}
 void glue(op_luxc1, MEMSUFFIX) (void)
 {
-    /* XXX: is defined as unaligned */
-    DT0 = glue(ldq, MEMSUFFIX)(T0 + T1);
+    DT0 = glue(ldq, MEMSUFFIX)(T0 & ~0x7);
     RETURN();
 }
 void glue(op_suxc1, MEMSUFFIX) (void)
 {
-    /* XXX: is defined as unaligned */
-    glue(stq, MEMSUFFIX)(T0 + T1, DT0);
+    glue(stq, MEMSUFFIX)(T0 & ~0x7, DT0);
     RETURN();
 }

Modified: trunk/src/host/qemu-neo1973/target-mips/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/translate.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-mips/translate.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -491,7 +491,7 @@
 FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr);
 
 #define FOP_CONDS(type, fmt)                                            \
-static GenOpFunc1 * cond ## type ## _ ## fmt ## _table[16] = {          \
+static GenOpFunc1 * gen_op_cmp ## type ## _ ## fmt ## _table[16] = {    \
     gen_op_cmp ## type ## _ ## fmt ## _f,                               \
     gen_op_cmp ## type ## _ ## fmt ## _un,                              \
     gen_op_cmp ## type ## _ ## fmt ## _eq,                              \
@@ -511,7 +511,7 @@
 };                                                                      \
 static inline void gen_cmp ## type ## _ ## fmt(int n, long cc)          \
 {                                                                       \
-    cond ## type ## _ ## fmt ## _table[n](cc);                          \
+    gen_op_cmp ## type ## _ ## fmt ## _table[n](cc);                    \
 }
 
 FOP_CONDS(, d)
@@ -525,11 +525,10 @@
     struct TranslationBlock *tb;
     target_ulong pc, saved_pc;
     uint32_t opcode;
-    uint32_t fp_status, saved_fp_status;
+    uint32_t fp_status;
     /* Routine used to access memory */
     int mem_idx;
     uint32_t hflags, saved_hflags;
-    uint32_t CP0_Status;
     int bstate;
     target_ulong btarget;
 } DisasContext;
@@ -628,11 +627,21 @@
     }
 }
 
-static inline void save_fpu_state (DisasContext *ctx)
+static inline void restore_cpu_state (CPUState *env, DisasContext *ctx)
 {
-    if (ctx->fp_status != ctx->saved_fp_status) {
-        gen_op_save_fp_status(ctx->fp_status);
-        ctx->saved_fp_status = ctx->fp_status;
+    ctx->saved_hflags = ctx->hflags;
+    switch (ctx->hflags & MIPS_HFLAG_BMASK) {
+    case MIPS_HFLAG_BR:
+        gen_op_restore_breg_target();
+        break;
+    case MIPS_HFLAG_B:
+        ctx->btarget = env->btarget;
+        break;
+    case MIPS_HFLAG_BC:
+    case MIPS_HFLAG_BL:
+        ctx->btarget = env->btarget;
+        gen_op_restore_bcond();
+        break;
     }
 }
 
@@ -702,10 +711,6 @@
 OP_ST_TABLE(wc1);
 OP_LD_TABLE(dc1);
 OP_ST_TABLE(dc1);
-OP_LD_TABLE(wxc1);
-OP_ST_TABLE(wxc1);
-OP_LD_TABLE(dxc1);
-OP_ST_TABLE(dxc1);
 OP_LD_TABLE(uxc1);
 OP_ST_TABLE(uxc1);
 
@@ -752,6 +757,7 @@
         opn = "scd";
         break;
     case OPC_LDL:
+        GEN_LOAD_REG_TN(T1, rt);
         op_ldst(ldl);
         GEN_STORE_TN_REG(rt, T0);
         opn = "ldl";
@@ -762,6 +768,7 @@
         opn = "sdl";
         break;
     case OPC_LDR:
+        GEN_LOAD_REG_TN(T1, rt);
         op_ldst(ldr);
         GEN_STORE_TN_REG(rt, T0);
         opn = "ldr";
@@ -910,7 +917,7 @@
 static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
                            int rs, int16_t imm)
 {
-    uint32_t uimm;
+    target_ulong uimm;
     const char *opn = "imm arith";
 
     if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
@@ -930,7 +937,7 @@
 #endif
     case OPC_SLTI:
     case OPC_SLTIU:
-        uimm = (int32_t)imm; /* Sign extend to 32 bits */
+        uimm = (target_long)imm; /* Sign extend to 32/64 bits */
         /* Fall through. */
     case OPC_ANDI:
     case OPC_ORI:
@@ -1081,7 +1088,7 @@
         return;
     }
     GEN_STORE_TN_REG(rt, T0);
-    MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
+    MIPS_DEBUG("%s %s, %s, " TARGET_FMT_lx, opn, regnames[rt], regnames[rs], uimm);
 }
 
 /* Arithmetic */
@@ -2028,9 +2035,9 @@
             rn = "SRSCtl";
             break;
         case 3:
-//            gen_op_mfc0_srsmap(); /* shadow registers */
+            gen_op_mfc0_srsmap();
             rn = "SRSMap";
-//            break;
+            break;
         default:
             goto die;
        }
@@ -2113,76 +2120,20 @@
         break;
     case 18:
         switch (sel) {
-        case 0:
-            gen_op_mfc0_watchlo0();
+        case 0 ... 7:
+            gen_op_mfc0_watchlo(sel);
             rn = "WatchLo";
             break;
-        case 1:
-//            gen_op_mfc0_watchlo1();
-            rn = "WatchLo1";
-//            break;
-        case 2:
-//            gen_op_mfc0_watchlo2();
-            rn = "WatchLo2";
-//            break;
-        case 3:
-//            gen_op_mfc0_watchlo3();
-            rn = "WatchLo3";
-//            break;
-        case 4:
-//            gen_op_mfc0_watchlo4();
-            rn = "WatchLo4";
-//            break;
-        case 5:
-//            gen_op_mfc0_watchlo5();
-            rn = "WatchLo5";
-//            break;
-        case 6:
-//            gen_op_mfc0_watchlo6();
-            rn = "WatchLo6";
-//            break;
-        case 7:
-//            gen_op_mfc0_watchlo7();
-            rn = "WatchLo7";
-//            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-            gen_op_mfc0_watchhi0();
+        case 0 ...7:
+            gen_op_mfc0_watchhi(sel);
             rn = "WatchHi";
             break;
-        case 1:
-//            gen_op_mfc0_watchhi1();
-            rn = "WatchHi1";
-//            break;
-        case 2:
-//            gen_op_mfc0_watchhi2();
-            rn = "WatchHi2";
-//            break;
-        case 3:
-//            gen_op_mfc0_watchhi3();
-            rn = "WatchHi3";
-//            break;
-        case 4:
-//            gen_op_mfc0_watchhi4();
-            rn = "WatchHi4";
-//            break;
-        case 5:
-//            gen_op_mfc0_watchhi5();
-            rn = "WatchHi5";
-//            break;
-        case 6:
-//            gen_op_mfc0_watchhi6();
-            rn = "WatchHi6";
-//            break;
-        case 7:
-//            gen_op_mfc0_watchhi7();
-            rn = "WatchHi7";
-//            break;
         default:
             goto die;
         }
@@ -2618,9 +2569,9 @@
             rn = "SRSCtl";
             break;
         case 3:
-//            gen_op_mtc0_srsmap(); /* shadow registers */
+            gen_op_mtc0_srsmap();
             rn = "SRSMap";
-//            break;
+            break;
         default:
             goto die;
         }
@@ -2712,76 +2663,20 @@
         break;
     case 18:
         switch (sel) {
-        case 0:
-            gen_op_mtc0_watchlo0();
+        case 0 ... 7:
+            gen_op_mtc0_watchlo(sel);
             rn = "WatchLo";
             break;
-        case 1:
-//            gen_op_mtc0_watchlo1();
-            rn = "WatchLo1";
-//            break;
-        case 2:
-//            gen_op_mtc0_watchlo2();
-            rn = "WatchLo2";
-//            break;
-        case 3:
-//            gen_op_mtc0_watchlo3();
-            rn = "WatchLo3";
-//            break;
-        case 4:
-//            gen_op_mtc0_watchlo4();
-            rn = "WatchLo4";
-//            break;
-        case 5:
-//            gen_op_mtc0_watchlo5();
-            rn = "WatchLo5";
-//            break;
-        case 6:
-//            gen_op_mtc0_watchlo6();
-            rn = "WatchLo6";
-//            break;
-        case 7:
-//            gen_op_mtc0_watchlo7();
-            rn = "WatchLo7";
-//            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-            gen_op_mtc0_watchhi0();
+        case 0 ... 7:
+            gen_op_mtc0_watchhi(sel);
             rn = "WatchHi";
             break;
-        case 1:
-//            gen_op_mtc0_watchhi1();
-            rn = "WatchHi1";
-//            break;
-        case 2:
-//            gen_op_mtc0_watchhi2();
-            rn = "WatchHi2";
-//            break;
-        case 3:
-//            gen_op_mtc0_watchhi3();
-            rn = "WatchHi3";
-//            break;
-        case 4:
-//            gen_op_mtc0_watchhi4();
-            rn = "WatchHi4";
-//            break;
-        case 5:
-//            gen_op_mtc0_watchhi5();
-            rn = "WatchHi5";
-//            break;
-        case 6:
-//            gen_op_mtc0_watchhi6();
-            rn = "WatchHi6";
-//            break;
-        case 7:
-//            gen_op_mtc0_watchhi7();
-            rn = "WatchHi7";
-//            break;
         default:
             goto die;
         }
@@ -3302,76 +3197,20 @@
         break;
     case 18:
         switch (sel) {
-        case 0:
-            gen_op_dmfc0_watchlo0();
+        case 0 ... 7:
+            gen_op_dmfc0_watchlo(sel);
             rn = "WatchLo";
             break;
-        case 1:
-//            gen_op_dmfc0_watchlo1();
-            rn = "WatchLo1";
-//            break;
-        case 2:
-//            gen_op_dmfc0_watchlo2();
-            rn = "WatchLo2";
-//            break;
-        case 3:
-//            gen_op_dmfc0_watchlo3();
-            rn = "WatchLo3";
-//            break;
-        case 4:
-//            gen_op_dmfc0_watchlo4();
-            rn = "WatchLo4";
-//            break;
-        case 5:
-//            gen_op_dmfc0_watchlo5();
-            rn = "WatchLo5";
-//            break;
-        case 6:
-//            gen_op_dmfc0_watchlo6();
-            rn = "WatchLo6";
-//            break;
-        case 7:
-//            gen_op_dmfc0_watchlo7();
-            rn = "WatchLo7";
-//            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-            gen_op_mfc0_watchhi0();
+        case 0 ... 7:
+            gen_op_mfc0_watchhi(sel);
             rn = "WatchHi";
             break;
-        case 1:
-//            gen_op_mfc0_watchhi1();
-            rn = "WatchHi1";
-//            break;
-        case 2:
-//            gen_op_mfc0_watchhi2();
-            rn = "WatchHi2";
-//            break;
-        case 3:
-//            gen_op_mfc0_watchhi3();
-            rn = "WatchHi3";
-//            break;
-        case 4:
-//            gen_op_mfc0_watchhi4();
-            rn = "WatchHi4";
-//            break;
-        case 5:
-//            gen_op_mfc0_watchhi5();
-            rn = "WatchHi5";
-//            break;
-        case 6:
-//            gen_op_mfc0_watchhi6();
-            rn = "WatchHi6";
-//            break;
-        case 7:
-//            gen_op_mfc0_watchhi7();
-            rn = "WatchHi7";
-//            break;
         default:
             goto die;
         }
@@ -3807,7 +3646,7 @@
             rn = "SRSCtl";
             break;
         case 3:
-            gen_op_mtc0_srsmap(); /* shadow registers */
+            gen_op_mtc0_srsmap();
             rn = "SRSMap";
             break;
         default:
@@ -3892,76 +3731,20 @@
         break;
     case 18:
         switch (sel) {
-        case 0:
-            gen_op_mtc0_watchlo0();
+        case 0 ... 7:
+            gen_op_mtc0_watchlo(sel);
             rn = "WatchLo";
             break;
-        case 1:
-//            gen_op_mtc0_watchlo1();
-            rn = "WatchLo1";
-//            break;
-        case 2:
-//            gen_op_mtc0_watchlo2();
-            rn = "WatchLo2";
-//            break;
-        case 3:
-//            gen_op_mtc0_watchlo3();
-            rn = "WatchLo3";
-//            break;
-        case 4:
-//            gen_op_mtc0_watchlo4();
-            rn = "WatchLo4";
-//            break;
-        case 5:
-//            gen_op_mtc0_watchlo5();
-            rn = "WatchLo5";
-//            break;
-        case 6:
-//            gen_op_mtc0_watchlo6();
-            rn = "WatchLo6";
-//            break;
-        case 7:
-//            gen_op_mtc0_watchlo7();
-            rn = "WatchLo7";
-//            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-            gen_op_mtc0_watchhi0();
+        case 0 ... 7:
+            gen_op_mtc0_watchhi(sel);
             rn = "WatchHi";
             break;
-        case 1:
-//            gen_op_mtc0_watchhi1();
-            rn = "WatchHi1";
-//            break;
-        case 2:
-//            gen_op_mtc0_watchhi2();
-            rn = "WatchHi2";
-//            break;
-        case 3:
-//            gen_op_mtc0_watchhi3();
-            rn = "WatchHi3";
-//            break;
-        case 4:
-//            gen_op_mtc0_watchhi4();
-            rn = "WatchHi4";
-//            break;
-        case 5:
-//            gen_op_mtc0_watchhi5();
-            rn = "WatchHi5";
-//            break;
-        case 6:
-//            gen_op_mtc0_watchhi6();
-            rn = "WatchHi6";
-//            break;
-        case 7:
-//            gen_op_mtc0_watchhi7();
-            rn = "WatchHi7";
-//            break;
         default:
             goto die;
         }
@@ -4229,7 +4012,6 @@
         break;
     case OPC_ERET:
         opn = "eret";
-        save_cpu_state(ctx, 0);
         gen_op_eret();
         ctx->bstate = BS_EXCP;
         break;
@@ -4239,7 +4021,6 @@
             MIPS_INVAL(opn);
             generate_exception(ctx, EXCP_RI);
         } else {
-            save_cpu_state(ctx, 0);
             gen_op_deret();
             ctx->bstate = BS_EXCP;
         }
@@ -4293,20 +4074,20 @@
         gen_op_save_bcond();
         break;
     case OPC_BC1FANY2:
-        gen_op_bc1fany2(cc);
-        opn = "bc1fany2";
+        gen_op_bc1any2f(cc);
+        opn = "bc1any2f";
         goto not_likely;
     case OPC_BC1TANY2:
-        gen_op_bc1tany2(cc);
-        opn = "bc1tany2";
+        gen_op_bc1any2t(cc);
+        opn = "bc1any2t";
         goto not_likely;
     case OPC_BC1FANY4:
-        gen_op_bc1fany4(cc);
-        opn = "bc1fany4";
+        gen_op_bc1any4f(cc);
+        opn = "bc1any4f";
         goto not_likely;
     case OPC_BC1TANY4:
-        gen_op_bc1tany4(cc);
-        opn = "bc1tany4";
+        gen_op_bc1any4t(cc);
+        opn = "bc1any4t";
     not_likely:
         ctx->hflags |= MIPS_HFLAG_BC;
         gen_op_set_bcond();
@@ -4323,27 +4104,6 @@
 
 /* Coprocessor 1 (FPU) */
 
-/* verify if floating point register is valid; an operation is not defined
- * if bit 0 of any register specification is set and the FR bit in the
- * Status register equals zero, since the register numbers specify an
- * even-odd pair of adjacent coprocessor general registers. When the FR bit
- * in the Status register equals one, both even and odd register numbers
- * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers.
- * 
- * Multiple 64 bit wide registers can be checked by calling
- * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
- * 
- * FIXME: This is broken for R2, it needs to be checked at runtime, not
- * at translation time.
- */
-#define CHECK_FR(ctx, freg) do {                                      \
-        if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \
-            MIPS_INVAL("FPU mode");                                   \
-            generate_exception (ctx, EXCP_RI);                        \
-            return;                                                   \
-        }                                                             \
-    } while(0)
-
 #define FOP(func, fmt) (((fmt) << 21) | (func))
 
 static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
@@ -4388,14 +4148,12 @@
         opn = "dmtc1";
         break;
     case OPC_MFHC1:
-        CHECK_FR(ctx, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_mfhc1();
         GEN_STORE_TN_REG(rt, T0);
         opn = "mfhc1";
         break;
     case OPC_MTHC1:
-        CHECK_FR(ctx, fs);
         GEN_LOAD_REG_TN(T0, rt);
         gen_op_mthc1();
         GEN_STORE_FTN_FREG(fs, WTH0);
@@ -4415,9 +4173,9 @@
 
     GEN_LOAD_REG_TN(T0, rd);
     GEN_LOAD_REG_TN(T1, rs);
-    if (cc)
+    if (cc) {
         ccbit = 1 << (24 + cc);
-    else
+    } else
         ccbit = 1 << 23;
     if (!tf)
         gen_op_movf(ccbit);
@@ -4431,9 +4189,9 @@
 {                                                                     \
     uint32_t ccbit;                                                   \
                                                                       \
-    if (cc)                                                           \
+    if (cc) {                                                         \
         ccbit = 1 << (24 + cc);                                       \
-    else                                                              \
+    } else                                                            \
         ccbit = 1 << 23;                                              \
     if (!tf)                                                          \
         glue(gen_op_float_movf_, fmt)(ccbit);                         \
@@ -4546,28 +4304,28 @@
         opn = "neg.s";
         break;
     case FOP(8, 16):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_roundl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "round.l.s";
         break;
     case FOP(9, 16):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_truncl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "trunc.l.s";
         break;
     case FOP(10, 16):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_ceill_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "ceil.l.s";
         break;
     case FOP(11, 16):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_floorl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4621,8 +4379,50 @@
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "movn.s";
         break;
+    case FOP(21, 16):
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_recip_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "recip.s";
+        break;
+    case FOP(22, 16):
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_rsqrt_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt.s";
+        break;
+    case FOP(28, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_op_float_recip2_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "recip2.s";
+        break;
+    case FOP(29, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_recip1_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "recip1.s";
+        break;
+    case FOP(30, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_rsqrt1_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt1.s";
+        break;
+    case FOP(31, 16):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_op_float_rsqrt2_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt2.s";
+        break;
     case FOP(33, 16):
-        CHECK_FR(ctx, fd);
+        gen_op_cp1_registers(fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvtd_s();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4635,14 +4435,14 @@
         opn = "cvt.w.s";
         break;
     case FOP(37, 16):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvtl_s();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "cvt.l.s";
         break;
     case FOP(38, 16):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT1, fs);
         GEN_LOAD_FREG_FTN(WT0, ft);
         gen_op_float_cvtps_s();
@@ -4668,6 +4468,7 @@
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         if (ctx->opcode & (1 << 6)) {
+            gen_op_cp1_64bitmode();
             gen_cmpabs_s(func-48, cc);
             opn = condnames_abs[func-48];
         } else {
@@ -4676,7 +4477,7 @@
         }
         break;
     case FOP(0, 17):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_registers(fs | ft | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         gen_op_float_add_d();
@@ -4685,7 +4486,7 @@
         optype = BINOP;
         break;
     case FOP(1, 17):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_registers(fs | ft | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         gen_op_float_sub_d();
@@ -4694,7 +4495,7 @@
         optype = BINOP;
         break;
     case FOP(2, 17):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_registers(fs | ft | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         gen_op_float_mul_d();
@@ -4703,7 +4504,7 @@
         optype = BINOP;
         break;
     case FOP(3, 17):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_registers(fs | ft | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         gen_op_float_div_d();
@@ -4712,84 +4513,84 @@
         optype = BINOP;
         break;
     case FOP(4, 17):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_registers(fs | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_sqrt_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "sqrt.d";
         break;
     case FOP(5, 17):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_registers(fs | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_abs_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "abs.d";
         break;
     case FOP(6, 17):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_registers(fs | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_mov_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "mov.d";
         break;
     case FOP(7, 17):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_registers(fs | fd);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_chs_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "neg.d";
         break;
     case FOP(8, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_roundl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "round.l.d";
         break;
     case FOP(9, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_truncl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "trunc.l.d";
         break;
     case FOP(10, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_ceill_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "ceil.l.d";
         break;
     case FOP(11, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_floorl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "floor.l.d";
         break;
     case FOP(12, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_roundw_d();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "round.w.d";
         break;
     case FOP(13, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_truncw_d();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "trunc.w.d";
         break;
     case FOP(14, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_ceilw_d();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "ceil.w.d";
         break;
     case FOP(15, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_floorw_d();
         GEN_STORE_FTN_FREG(fd, WT2);
@@ -4819,6 +4620,50 @@
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "movn.d";
         break;
+    case FOP(21, 17):
+        gen_op_cp1_registers(fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_recip_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "recip.d";
+        break;
+    case FOP(22, 17):
+        gen_op_cp1_registers(fs | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_rsqrt_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "rsqrt.d";
+        break;
+    case FOP(28, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, ft);
+        gen_op_float_recip2_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "recip2.d";
+        break;
+    case FOP(29, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_recip1_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "recip1.d";
+        break;
+    case FOP(30, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_rsqrt1_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "rsqrt1.d";
+        break;
+    case FOP(31, 17):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, ft);
+        gen_op_float_rsqrt2_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "rsqrt2.d";
+        break;
     case FOP(48, 17):
     case FOP(49, 17):
     case FOP(50, 17):
@@ -4835,33 +4680,34 @@
     case FOP(61, 17):
     case FOP(62, 17):
     case FOP(63, 17):
-        CHECK_FR(ctx, fs | ft);
         GEN_LOAD_FREG_FTN(DT0, fs);
         GEN_LOAD_FREG_FTN(DT1, ft);
         if (ctx->opcode & (1 << 6)) {
+            gen_op_cp1_64bitmode();
             gen_cmpabs_d(func-48, cc);
             opn = condnames_abs[func-48];
         } else {
+            gen_op_cp1_registers(fs | ft);
             gen_cmp_d(func-48, cc);
             opn = condnames[func-48];
         }
         break;
     case FOP(32, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvts_d();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.d";
         break;
     case FOP(36, 17):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_registers(fs);
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvtw_d();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.w.d";
         break;
     case FOP(37, 17):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvtl_d();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4874,21 +4720,21 @@
         opn = "cvt.s.w";
         break;
     case FOP(33, 20):
-        CHECK_FR(ctx, fd);
+        gen_op_cp1_registers(fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvtd_w();
         GEN_STORE_FTN_FREG(fd, DT2);
         opn = "cvt.d.w";
         break;
     case FOP(32, 21):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvts_l();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.l";
         break;
     case FOP(33, 21):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(DT0, fs);
         gen_op_float_cvtd_l();
         GEN_STORE_FTN_FREG(fd, DT2);
@@ -4896,7 +4742,7 @@
         break;
     case FOP(38, 20):
     case FOP(38, 21):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_cvtps_pw();
@@ -4905,7 +4751,7 @@
         opn = "cvt.ps.pw";
         break;
     case FOP(0, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4916,7 +4762,7 @@
         opn = "add.ps";
         break;
     case FOP(1, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4927,7 +4773,7 @@
         opn = "sub.ps";
         break;
     case FOP(2, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -4938,7 +4784,7 @@
         opn = "mul.ps";
         break;
     case FOP(5, 22):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_abs_ps();
@@ -4947,7 +4793,7 @@
         opn = "abs.ps";
         break;
     case FOP(6, 22):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_mov_ps();
@@ -4956,7 +4802,7 @@
         opn = "mov.ps";
         break;
     case FOP(7, 22):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_chs_ps();
@@ -4965,6 +4811,7 @@
         opn = "neg.ps";
         break;
     case FOP(17, 22):
+        gen_op_cp1_64bitmode();
         GEN_LOAD_REG_TN(T0, ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
@@ -4976,6 +4823,7 @@
         opn = "movcf.ps";
         break;
     case FOP(18, 22):
+        gen_op_cp1_64bitmode();
         GEN_LOAD_REG_TN(T0, ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
@@ -4987,6 +4835,7 @@
         opn = "movz.ps";
         break;
     case FOP(19, 22):
+        gen_op_cp1_64bitmode();
         GEN_LOAD_REG_TN(T0, ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
@@ -4998,25 +4847,76 @@
         opn = "movn.ps";
         break;
     case FOP(24, 22):
-        CHECK_FR(ctx, fs | fd | ft);
-        GEN_LOAD_FREG_FTN(WT0, fs);
-        GEN_LOAD_FREG_FTN(WTH0, fs);
-        GEN_LOAD_FREG_FTN(WT1, ft);
-        GEN_LOAD_FREG_FTN(WTH1, ft);
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, ft);
+        GEN_LOAD_FREG_FTN(WTH0, ft);
+        GEN_LOAD_FREG_FTN(WT1, fs);
+        GEN_LOAD_FREG_FTN(WTH1, fs);
         gen_op_float_addr_ps();
         GEN_STORE_FTN_FREG(fd, WT2);
         GEN_STORE_FTN_FREG(fd, WTH2);
         opn = "addr.ps";
         break;
+    case FOP(26, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, ft);
+        GEN_LOAD_FREG_FTN(WTH0, ft);
+        GEN_LOAD_FREG_FTN(WT1, fs);
+        GEN_LOAD_FREG_FTN(WTH1, fs);
+        gen_op_float_mulr_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "mulr.ps";
+        break;
+    case FOP(28, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        GEN_LOAD_FREG_FTN(WTH2, fd);
+        gen_op_float_recip2_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "recip2.ps";
+        break;
+    case FOP(29, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_recip1_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "recip1.ps";
+        break;
+    case FOP(30, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_rsqrt1_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "rsqrt1.ps";
+        break;
+    case FOP(31, 22):
+        gen_op_cp1_64bitmode();
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        GEN_LOAD_FREG_FTN(WTH2, fd);
+        gen_op_float_rsqrt2_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "rsqrt2.ps";
+        break;
     case FOP(32, 22):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_cvts_pu();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.pu";
         break;
     case FOP(36, 22):
-        CHECK_FR(ctx, fs | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         gen_op_float_cvtpw_ps();
@@ -5025,14 +4925,14 @@
         opn = "cvt.pw.ps";
         break;
     case FOP(40, 22):
-        CHECK_FR(ctx, fs);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvts_pl();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.s.pl";
         break;
     case FOP(44, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_pll_ps();
@@ -5040,7 +4940,7 @@
         opn = "pll.ps";
         break;
     case FOP(45, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH1, ft);
         gen_op_float_plu_ps();
@@ -5048,7 +4948,7 @@
         opn = "plu.ps";
         break;
     case FOP(46, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_pul_ps();
@@ -5056,7 +4956,7 @@
         opn = "pul.ps";
         break;
     case FOP(47, 22):
-        CHECK_FR(ctx, fs | ft | fd);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WTH1, ft);
         gen_op_float_puu_ps();
@@ -5079,7 +4979,7 @@
     case FOP(61, 22):
     case FOP(62, 22):
     case FOP(63, 22):
-        CHECK_FR(ctx, fs | ft);
+        gen_op_cp1_64bitmode();
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WTH0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
@@ -5112,23 +5012,36 @@
 
 /* Coprocessor 3 (FPU) */
 static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd,
-                           int base, int index)
+                           int fs, int base, int index)
 {
     const char *opn = "extended float load/store";
+    int store = 0;
 
-    GEN_LOAD_REG_TN(T0, base);
-    GEN_LOAD_REG_TN(T1, index);
+    /* All of those work only on 64bit FPUs. */
+    gen_op_cp1_64bitmode();
+    if (base == 0) {
+        if (index == 0)
+            gen_op_reset_T0();
+        else
+            GEN_LOAD_REG_TN(T0, index);
+    } else if (index == 0) {
+        GEN_LOAD_REG_TN(T0, base);
+    } else {
+        GEN_LOAD_REG_TN(T0, base);
+        GEN_LOAD_REG_TN(T1, index);
+        gen_op_addr_add();
+    }
     /* Don't do NOP if destination is zero: we must perform the actual
      * memory access
      */
     switch (opc) {
     case OPC_LWXC1:
-        op_ldst(lwxc1);
+        op_ldst(lwc1);
         GEN_STORE_FTN_FREG(fd, WT0);
         opn = "lwxc1";
         break;
     case OPC_LDXC1:
-        op_ldst(ldxc1);
+        op_ldst(ldc1);
         GEN_STORE_FTN_FREG(fd, DT0);
         opn = "ldxc1";
         break;
@@ -5138,26 +5051,30 @@
         opn = "luxc1";
         break;
     case OPC_SWXC1:
-        GEN_LOAD_FREG_FTN(WT0, fd);
-        op_ldst(swxc1);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        op_ldst(swc1);
         opn = "swxc1";
+        store = 1;
         break;
     case OPC_SDXC1:
-        GEN_LOAD_FREG_FTN(DT0, fd);
-        op_ldst(sdxc1);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        op_ldst(sdc1);
         opn = "sdxc1";
+        store = 1;
         break;
     case OPC_SUXC1:
-        GEN_LOAD_FREG_FTN(DT0, fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
         op_ldst(suxc1);
         opn = "suxc1";
+        store = 1;
         break;
     default:
         MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
-    MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[fd],regnames[index], regnames[base]);
+    MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[store ? fs : fd],
+               regnames[index], regnames[base]);
 }
 
 static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd,
@@ -5166,7 +5083,7 @@
     const char *opn = "flt3_arith";
 
     /* All of those work only on 64bit FPUs. */
-    CHECK_FR(ctx, fd | fr | fs | ft);
+    gen_op_cp1_64bitmode();
     switch (opc) {
     case OPC_ALNV_PS:
         GEN_LOAD_REG_TN(T0, fr);
@@ -5383,6 +5300,10 @@
             generate_exception(ctx, EXCP_SYSCALL);
             break;
         case OPC_BREAK:
+            /* XXX: Hack to work around wrong handling of self-modifying code. */
+            ctx->pc += 4;
+            save_cpu_state(ctx, 1);
+            ctx->pc -= 4;
             generate_exception(ctx, EXCP_BREAK);
             break;
         case OPC_SPIM:
@@ -5648,8 +5569,8 @@
          gen_ldst(ctx, op, rt, rs, imm);
          break;
     case OPC_CACHE:
-         /* Treat as a noop */
-         break;
+        /* Treat as a noop */
+        break;
     case OPC_PREF:
         /* Treat as a noop */
         break;
@@ -5732,7 +5653,7 @@
             case OPC_SWXC1:
             case OPC_SDXC1:
             case OPC_SUXC1:
-                gen_flt3_ldst(ctx, op1, sa, rs, rt);
+                gen_flt3_ldst(ctx, op1, sa, rd, rs, rt);
                 break;
             case OPC_PREFX:
                 /* treat as noop */
@@ -5856,26 +5777,12 @@
     ctx.bstate = BS_NONE;
     /* Restore delay slot state from the tb context.  */
     ctx.hflags = tb->flags;
-    ctx.saved_hflags = ctx.hflags;
-    switch (ctx.hflags & MIPS_HFLAG_BMASK) {
-    case MIPS_HFLAG_BR:
-        gen_op_restore_breg_target();
-        break;
-    case MIPS_HFLAG_B:
-        ctx.btarget = env->btarget;
-        break;
-    case MIPS_HFLAG_BC:
-    case MIPS_HFLAG_BL:
-        ctx.btarget = env->btarget;
-        gen_op_restore_bcond();
-        break;
-    }
+    restore_cpu_state(env, &ctx);
 #if defined(CONFIG_USER_ONLY)
     ctx.mem_idx = 0;
 #else
     ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
 #endif
-    ctx.CP0_Status = env->CP0_Status;
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_CPU) {
         fprintf(logfile, "------------------------------------------------\n");
@@ -5932,7 +5839,8 @@
 	switch (ctx.bstate) {
         case BS_STOP:
             gen_op_interrupt_restart();
-            /* Fall through. */
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
         case BS_NONE:
             save_cpu_state(ctxp, 0);
             gen_goto_tb(&ctx, 0, ctx.pc);
@@ -6137,8 +6045,16 @@
     /* vectored interrupts not implemented, timer on int 7,
        no performance counters. */
     env->CP0_IntCtl = 0xe0000000;
-    env->CP0_WatchLo = 0;
-    env->CP0_WatchHi = 0;
+    {
+        int i;
+
+        for (i = 0; i < 7; i++) {
+            env->CP0_WatchLo[i] = 0;
+            env->CP0_WatchHi[i] = 0x80000000;
+        }
+        env->CP0_WatchLo[7] = 0;
+        env->CP0_WatchHi[7] = 0;
+    }
     /* Count register increments in debug mode, EJTAG version 1 */
     env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
 #endif

Modified: trunk/src/host/qemu-neo1973/target-sparc/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/cpu.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-sparc/cpu.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -290,6 +290,8 @@
 
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 void raise_exception(int tt);
+void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
+                          int is_asi);
 
 #include "cpu-all.h"
 

Modified: trunk/src/host/qemu-neo1973/target-sparc/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/helper.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-sparc/helper.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -117,7 +117,7 @@
     }
 
     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
-    *physical = 0xfffff000;
+    *physical = 0xffffffffffff0000ULL;
 
     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
     /* Context base + context number */
@@ -203,7 +203,7 @@
 
     /* Even if large ptes, we map only one 4KB page in the cache to
        avoid filling it too fast */
-    *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
+    *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
     return error_code;
 }
 
@@ -212,7 +212,7 @@
                               int is_user, int is_softmmu)
 {
     target_phys_addr_t paddr;
-    unsigned long vaddr;
+    target_ulong vaddr;
     int error_code = 0, prot, ret = 0, access_index;
 
     error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
@@ -220,7 +220,8 @@
 	vaddr = address & TARGET_PAGE_MASK;
 	paddr &= TARGET_PAGE_MASK;
 #ifdef DEBUG_MMU
-	printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr);
+	printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
+               TARGET_FMT_lx "\n", address, paddr, vaddr);
 #endif
 	ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
 	return ret;
@@ -255,7 +256,8 @@
     uint32_t pde;
 
     /* Context base + context number */
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
+        (env->mmuregs[2] << 2);
     pde = ldl_phys(pde_ptr);
 
     switch (pde & PTE_ENTRYTYPE_MASK) {
@@ -314,30 +316,35 @@
 #ifdef DEBUG_MMU
 void dump_mmu(CPUState *env)
 {
-     target_ulong va, va1, va2;
-     unsigned int n, m, o;
-     target_phys_addr_t pde_ptr, pa;
+    target_ulong va, va1, va2;
+    unsigned int n, m, o;
+    target_phys_addr_t pde_ptr, pa;
     uint32_t pde;
 
     printf("MMU dump:\n");
     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
     pde = ldl_phys(pde_ptr);
-    printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
+    printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
+           (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
-	pde_ptr = mmu_probe(env, va, 2);
-	if (pde_ptr) {
+	pde = mmu_probe(env, va, 2);
+	if (pde) {
 	    pa = cpu_get_phys_page_debug(env, va);
- 	    printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr);
+ 	    printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                   " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
 	    for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
-		pde_ptr = mmu_probe(env, va1, 1);
-		if (pde_ptr) {
+		pde = mmu_probe(env, va1, 1);
+		if (pde) {
 		    pa = cpu_get_phys_page_debug(env, va1);
- 		    printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr);
+ 		    printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
+                           " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
 		    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
-			pde_ptr = mmu_probe(env, va2, 0);
-			if (pde_ptr) {
+			pde = mmu_probe(env, va2, 0);
+			if (pde) {
 			    pa = cpu_get_phys_page_debug(env, va2);
- 			    printf("  VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr);
+ 			    printf("  VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
+                                   va2, pa, pde);
 			}
 		    }
 		}

Modified: trunk/src/host/qemu-neo1973/target-sparc/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/op_helper.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-sparc/op_helper.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -3,6 +3,7 @@
 //#define DEBUG_PCALL
 //#define DEBUG_MMU
 //#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
 
 void raise_exception(int tt)
 {
@@ -151,6 +152,8 @@
     uint32_t ret = 0;
 
     switch (asi) {
+    case 2: /* SuperSparc MXCC registers */
+        break;
     case 3: /* MMU probe */
 	{
 	    int mmulev;
@@ -179,9 +182,32 @@
 #endif
 	}
 	break;
-    case 0x20 ... 0x2f: /* MMU passthrough */
+    case 9: /* Supervisor code access */
         switch(size) {
         case 1:
+            ret = ldub_code(T0);
+            break;
+        case 2:
+            ret = lduw_code(T0 & ~1);
+            break;
+        default:
+        case 4:
+            ret = ldl_code(T0 & ~3);
+            break;
+        case 8:
+            ret = ldl_code(T0 & ~3);
+            T0 = ldl_code((T0 + 4) & ~3);
+            break;
+        }
+        break;
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+        break;
+    case 0x20: /* MMU passthrough */
+        switch(size) {
+        case 1:
             ret = ldub_phys(T0);
             break;
         case 2:
@@ -197,7 +223,33 @@
 	    break;
         }
 	break;
+    case 0x2e: /* MMU passthrough, 0xexxxxxxxx */
+    case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */
+        switch(size) {
+        case 1:
+            ret = ldub_phys((target_phys_addr_t)T0
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 2:
+            ret = lduw_phys((target_phys_addr_t)(T0 & ~1)
+                            | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        default:
+        case 4:
+            ret = ldl_phys((target_phys_addr_t)(T0 & ~3)
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            break;
+        case 8:
+            ret = ldl_phys((target_phys_addr_t)(T0 & ~3)
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+            T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3)
+                           | ((target_phys_addr_t)(asi & 0xf) << 32));
+	    break;
+        }
+	break;
+    case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
     default:
+        do_unassigned_access(T0, 0, 0, 1);
 	ret = 0;
 	break;
     }
@@ -207,6 +259,8 @@
 void helper_st_asi(int asi, int size, int sign)
 {
     switch(asi) {
+    case 2: /* SuperSparc MXCC registers */
+        break;
     case 3: /* MMU flush */
 	{
 	    int mmulev;
@@ -271,18 +325,28 @@
 #endif
 	    return;
 	}
+    case 0xc: /* I-cache tag */
+    case 0xd: /* I-cache data */
+    case 0xe: /* D-cache tag */
+    case 0xf: /* D-cache data */
+    case 0x10: /* I/D-cache flush page */
+    case 0x11: /* I/D-cache flush segment */
+    case 0x12: /* I/D-cache flush region */
+    case 0x13: /* I/D-cache flush context */
+    case 0x14: /* I/D-cache flush user */
+        break;
     case 0x17: /* Block copy, sta access */
 	{
 	    // value (T1) = src
 	    // address (T0) = dst
 	    // copy 32 bytes
-	    uint32_t src = T1, dst = T0;
-	    uint8_t temp[32];
+            unsigned int i;
+            uint32_t src = T1 & ~3, dst = T0 & ~3, temp;
 	    
-	    tswap32s(&src);
-
-	    cpu_physical_memory_read(src, (void *) &temp, 32);
-	    cpu_physical_memory_write(dst, (void *) &temp, 32);
+            for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+                temp = ldl_kernel(src);
+                stl_kernel(dst, temp);
+            }
 	}
 	return;
     case 0x1f: /* Block fill, stda access */
@@ -290,19 +354,17 @@
 	    // value (T1, T2)
 	    // address (T0) = dst
 	    // fill 32 bytes
-	    int i;
-	    uint32_t dst = T0;
-	    uint64_t val;
-	    
-	    val = (((uint64_t)T1) << 32) | T2;
-	    tswap64s(&val);
+            unsigned int i;
+            uint32_t dst = T0 & 7;
+            uint64_t val;
 
-	    for (i = 0; i < 32; i += 8, dst += 8) {
-		cpu_physical_memory_write(dst, (void *) &val, 8);
-	    }
+            val = (((uint64_t)T1) << 32) | T2;
+
+            for (i = 0; i < 32; i += 8, dst += 8)
+                stq_kernel(dst, val);
 	}
 	return;
-    case 0x20 ... 0x2f: /* MMU passthrough */
+    case 0x20: /* MMU passthrough */
 	{
             switch(size) {
             case 1:
@@ -322,7 +384,40 @@
             }
 	}
 	return;
+    case 0x2e: /* MMU passthrough, 0xexxxxxxxx */
+    case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */
+	{
+            switch(size) {
+            case 1:
+                stb_phys((target_phys_addr_t)T0
+                         | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
+                break;
+            case 2:
+                stw_phys((target_phys_addr_t)(T0 & ~1)
+                            | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
+                break;
+            case 4:
+            default:
+                stl_phys((target_phys_addr_t)(T0 & ~3)
+                           | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
+                break;
+            case 8:
+                stl_phys((target_phys_addr_t)(T0 & ~3)
+                           | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
+                stl_phys((target_phys_addr_t)((T0 + 4) & ~3)
+                           | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
+                break;
+            }
+	}
+	return;
+    case 0x31: /* Ross RT620 I-cache flush */
+    case 0x36: /* I-cache flash clear */
+    case 0x37: /* D-cache flash clear */
+        break;
+    case 9: /* Supervisor code access, XXX */
+    case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
     default:
+        do_unassigned_access(T0, 1, 0, 1);
 	return;
     }
 }
@@ -441,6 +536,7 @@
     case 0x5f: // D-MMU demap, WO
     case 0x77: // Interrupt vector, WO
     default:
+        do_unassigned_access(T0, 0, 0, 1);
 	ret = 0;
 	break;
     }
@@ -656,6 +752,7 @@
     case 0x8a: // Primary no-fault LE, RO
     case 0x8b: // Secondary no-fault LE, RO
     default:
+        do_unassigned_access(T0, 1, 0, 1);
 	return;
     }
 }
@@ -986,3 +1083,53 @@
 }
 
 #endif
+
+#ifndef TARGET_SPARC64
+void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
+                          int is_asi)
+{
+    CPUState *saved_env;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    if (env->mmuregs[3]) /* Fault status register */
+	env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+    if (is_asi)
+        env->mmuregs[3] |= 1 << 16;
+    if (env->psrs)
+        env->mmuregs[3] |= 1 << 5;
+    if (is_exec)
+        env->mmuregs[3] |= 1 << 6;
+    if (is_write)
+        env->mmuregs[3] |= 1 << 7;
+    env->mmuregs[3] |= (5 << 2) | 2;
+    env->mmuregs[4] = addr; /* Fault address register */
+    if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+#ifdef DEBUG_UNASSIGNED
+        printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
+               "\n", addr, env->pc);
+#endif
+        raise_exception(TT_DATA_ACCESS);
+    }
+    env = saved_env;
+}
+#else
+void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
+                          int is_asi)
+{
+#ifdef DEBUG_UNASSIGNED
+    CPUState *saved_env;
+
+    /* XXX: hack to restore env in all cases, even if not called from
+       generated code */
+    saved_env = env;
+    env = cpu_single_env;
+    printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n",
+           addr, env->pc);
+    env = saved_env;
+#endif
+    raise_exception(TT_DATA_ACCESS);
+}
+#endif

Modified: trunk/src/host/qemu-neo1973/target-sparc/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/translate.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/target-sparc/translate.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -3494,6 +3494,8 @@
     if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0)
         if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0)
             return -1;
+    if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
+        return -1;
     return phys_addr;
 }
 #endif

Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/vl.c	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1361,14 +1361,13 @@
                 for (i = 0; i < MAX_DISKS; i++) {
                     if (bs_table[i])
                         bdrv_commit(bs_table[i]);
-                    if (mtd_bdrv)
-                        bdrv_commit(mtd_bdrv);
                 }
+                if (mtd_bdrv)
+                    bdrv_commit(mtd_bdrv);
             }
             break;
         case 'b':
-            if (chr->chr_event)
-                chr->chr_event(chr->opaque, CHR_EVENT_BREAK);
+            qemu_chr_event(chr, CHR_EVENT_BREAK);
             break;
         case 'c':
             /* Switch to the next registered device */
@@ -6661,7 +6660,6 @@
     }
 #endif
     qemu_aio_poll();
-    qemu_bh_poll();
 
     if (vm_running) {
         qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], 
@@ -6669,10 +6667,15 @@
         /* run dma transfers, if any */
         DMA_run();
     }
-    
+
     /* real time timers */
     qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], 
                     qemu_get_clock(rt_clock));
+
+    /* Check bottom-halves last in case any of the earlier events triggered
+       them.  */
+    qemu_bh_poll();
+    
 }
 
 static CPUState *cur_cpu;
@@ -7172,6 +7175,8 @@
     qemu_register_machine(&shix_machine);
 #elif defined(TARGET_ALPHA)
     /* XXX: TODO */
+#elif defined(TARGET_M68K)
+    qemu_register_machine(&an5206_machine);
 #else
 #error unsupported CPU
 #endif

Modified: trunk/src/host/qemu-neo1973/vl.h
===================================================================
--- trunk/src/host/qemu-neo1973/vl.h	2007-05-24 18:45:22 UTC (rev 2079)
+++ trunk/src/host/qemu-neo1973/vl.h	2007-05-24 19:28:30 UTC (rev 2080)
@@ -1026,7 +1026,7 @@
 typedef struct fdctrl_t fdctrl_t;
 
 fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped, 
-                       uint32_t io_base,
+                       target_phys_addr_t io_base,
                        BlockDriverState **fds);
 int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
 
@@ -1049,7 +1049,8 @@
 
 void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn);
 void pcnet_h_reset(void *opaque);
-void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq);
+void *lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
+                 qemu_irq irq);
 
 /* vmmouse.c */
 void *vmmouse_init(void *m);
@@ -1212,7 +1213,7 @@
 extern QEMUMachine ss5_machine, ss10_machine;
 
 /* iommu.c */
-void *iommu_init(uint32_t addr);
+void *iommu_init(target_phys_addr_t addr);
 void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr,
                                  uint8_t *buf, int len, int is_write);
 static inline void sparc_iommu_memory_read(void *opaque,
@@ -1230,13 +1231,13 @@
 }
 
 /* tcx.c */
-void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
-	      unsigned long vram_offset, int vram_size, int width, int height,
+void tcx_init(DisplayState *ds, target_phys_addr_t addr, uint8_t *vram_base,
+              unsigned long vram_offset, int vram_size, int width, int height,
               int depth);
 
 /* slavio_intctl.c */
 void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu);
-void *slavio_intctl_init(uint32_t addr, uint32_t addrg,
+void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
                          const uint32_t *intbit_to_level,
                          qemu_irq **irq);
 void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env);
@@ -1252,26 +1253,28 @@
 int load_uboot(const char *filename, target_ulong *ep, int *is_linux);
 
 /* slavio_timer.c */
-void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu,
-                       void *intctl);
+void slavio_timer_init(target_phys_addr_t addr, int irq, int mode,
+                       unsigned int cpu, void *intctl);
 
 /* slavio_serial.c */
-SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1,
-                                CharDriverState *chr2);
-void slavio_serial_ms_kbd_init(int base, qemu_irq);
+SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,
+                                CharDriverState *chr1, CharDriverState *chr2);
+void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq);
 
 /* slavio_misc.c */
-void *slavio_misc_init(uint32_t base, qemu_irq irq);
+void *slavio_misc_init(target_phys_addr_t base, target_phys_addr_t power_base,
+                       qemu_irq irq);
 void slavio_set_power_fail(void *opaque, int power_failing);
 
 /* esp.c */
 void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id);
-void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque);
+void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
+               void *dma_opaque);
 void esp_reset(void *opaque);
 
 /* sparc32_dma.c */
-void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq,
-                       void *iommu);
+void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq espirq,
+                       qemu_irq leirq, void *iommu);
 void ledma_set_irq(void *opaque, int isr);
 void ledma_memory_read(void *opaque, target_phys_addr_t addr, 
                        uint8_t *buf, int len, int do_bswap);
@@ -1596,11 +1599,30 @@
 /* dscm1xxxx.c */
 struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv);
 
+/* ptimer.c */
+typedef struct ptimer_state ptimer_state;
+typedef void (*ptimer_cb)(void *opaque);
+
+ptimer_state *ptimer_init(QEMUBH *bh);
+void ptimer_set_period(ptimer_state *s, int64_t period);
+void ptimer_set_freq(ptimer_state *s, uint32_t freq);
+void ptimer_set_limit(ptimer_state *s, uint32_t limit, int reload);
+uint32_t ptimer_get_count(ptimer_state *s);
+void ptimer_set_count(ptimer_state *s, uint32_t count);
+void ptimer_run(ptimer_state *s, int oneshot);
+void ptimer_stop(ptimer_state *s);
+
 #define unlikely(cond)	__builtin_expect(!!(cond), 0)
 
 #include "hw/pxa.h"
 #include "hw/s3c.h"
 
+/* mcf5206.c */
+qemu_irq *mcf5206_init(uint32_t base, CPUState *env);
+
+/* an5206.c */
+extern QEMUMachine an5206_machine;
+
 #include "gdbstub.h"
 
 #endif /* defined(QEMU_TOOL) */





More information about the commitlog mailing list